From 0600d1ea1dccd8c4878d90754e808a0855ae98e7 Mon Sep 17 00:00:00 2001
From: Ben Adida <ben@adida.net>
Date: Sat, 21 Aug 2010 22:56:46 -0700
Subject: [PATCH] added south for database migrations

---
 README.txt                        |  14 ++
 auth/jsonfield.py                 |   7 +
 auth/migrations/0001_initial.py   |  49 ++++++
 auth/migrations/__init__.py       |   0
 helios/migrations/0001_initial.py | 259 ++++++++++++++++++++++++++++++
 helios/migrations/__init__.py     |   0
 settings.py.sample                |   2 +
 7 files changed, 331 insertions(+)
 create mode 100644 auth/migrations/0001_initial.py
 create mode 100644 auth/migrations/__init__.py
 create mode 100644 helios/migrations/0001_initial.py
 create mode 100644 helios/migrations/__init__.py

diff --git a/README.txt b/README.txt
index 7729347..7551db6 100644
--- a/README.txt
+++ b/README.txt
@@ -16,3 +16,17 @@ NEEDS:
 -- easy_install celery
 -- easy_install django-celery
 
+- South for schema migration
+-- easy_install South
+
+
+GETTING SOUTH WORKING ON EXISTING INSTALL
+- as of Helios v3.0.4, we're using South to migrate data models
+- if you've already loaded the data model beforehand, you need to tell South that you've migrated appropriately
+- so, if your data model is up to date with the code, do
+
+python manage.py migrate --list
+
+- if there are some unchecked migrations, and you are SURE that your database is up to date with the models (which should be the case if you're between v3.0.0 and v3.0.4 inclusive), then do
+
+python manage.py migrate --fake
diff --git a/auth/jsonfield.py b/auth/jsonfield.py
index 54311ac..f731630 100644
--- a/auth/jsonfield.py
+++ b/auth/jsonfield.py
@@ -53,3 +53,10 @@ class JSONField(models.TextField):
         value = json.dumps(value, cls=DjangoJSONEncoder)
 
         return super(JSONField, self).get_db_prep_save(value)
+
+##
+## for schema migration, we have to tell South about JSONField
+## basically that it's the same as its parent class
+##
+from south.modelsinspector import add_introspection_rules
+add_introspection_rules([], ["^auth\.jsonfield\.JSONField"])
diff --git a/auth/migrations/0001_initial.py b/auth/migrations/0001_initial.py
new file mode 100644
index 0000000..35ba118
--- /dev/null
+++ b/auth/migrations/0001_initial.py
@@ -0,0 +1,49 @@
+# 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 'User'
+        db.create_table('auth_user', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('user_type', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('user_id', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)),
+            ('info', self.gf('auth.jsonfield.JSONField')()),
+            ('token', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('admin_p', self.gf('django.db.models.fields.BooleanField')(default=False)),
+        ))
+        db.send_create_signal('auth', ['User'])
+
+        # Adding unique constraint on 'User', fields ['user_type', 'user_id']
+        db.create_unique('auth_user', ['user_type', 'user_id'])
+
+
+    def backwards(self, orm):
+        
+        # Removing unique constraint on 'User', fields ['user_type', 'user_id']
+        db.delete_unique('auth_user', ['user_type', 'user_id'])
+
+        # Deleting model 'User'
+        db.delete_table('auth_user')
+
+
+    models = {
+        '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': ('auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('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 = ['auth']
diff --git a/auth/migrations/__init__.py b/auth/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/helios/migrations/0001_initial.py b/helios/migrations/0001_initial.py
new file mode 100644
index 0000000..5d3b723
--- /dev/null
+++ b/helios/migrations/0001_initial.py
@@ -0,0 +1,259 @@
+# 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 'Election'
+        db.create_table('helios_election', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('admin', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('short_name', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=250)),
+            ('description', self.gf('django.db.models.fields.TextField')()),
+            ('public_key', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('private_key', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('questions', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('eligibility', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('openreg', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('featured_p', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('use_voter_aliases', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('cast_url', self.gf('django.db.models.fields.CharField')(max_length=500)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('modified_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('frozen_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('archived_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('registration_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_ends_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_started_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_extended_until', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_ended_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_started_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_finished_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallies_combined_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voters_hash', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('encrypted_tally', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('result', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('result_proof', self.gf('auth.jsonfield.JSONField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Election'])
+
+        # Adding model 'ElectionLog'
+        db.create_table('helios_electionlog', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('log', self.gf('django.db.models.fields.CharField')(max_length=500)),
+            ('at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+        ))
+        db.send_create_signal('helios', ['ElectionLog'])
+
+        # Adding model 'VoterFile'
+        db.create_table('helios_voterfile', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('voter_file', self.gf('django.db.models.fields.files.FileField')(max_length=250)),
+            ('uploaded_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('processing_started_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('processing_finished_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('num_voters', self.gf('django.db.models.fields.IntegerField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['VoterFile'])
+
+        # Adding model 'Voter'
+        db.create_table('helios_voter', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)),
+            ('voter_type', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('voter_id', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('alias', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('vote', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('cast_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Voter'])
+
+        # Adding model 'CastVote'
+        db.create_table('helios_castvote', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('voter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Voter'])),
+            ('vote', self.gf('auth.jsonfield.JSONField')()),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('cast_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('verified_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('invalidated_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['CastVote'])
+
+        # Adding model 'AuditedBallot'
+        db.create_table('helios_auditedballot', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('raw_vote', self.gf('django.db.models.fields.TextField')()),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('added_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+        ))
+        db.send_create_signal('helios', ['AuditedBallot'])
+
+        # Adding model 'Trustee'
+        db.create_table('helios_trustee', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+            ('email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
+            ('secret', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('public_key', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('public_key_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('secret_key', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('pok', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('decryption_factors', self.gf('auth.jsonfield.JSONField')(null=True)),
+            ('decryption_proofs', self.gf('auth.jsonfield.JSONField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Trustee'])
+
+
+    def backwards(self, orm):
+        
+        # Deleting model 'Election'
+        db.delete_table('helios_election')
+
+        # Deleting model 'ElectionLog'
+        db.delete_table('helios_electionlog')
+
+        # Deleting model 'VoterFile'
+        db.delete_table('helios_voterfile')
+
+        # Deleting model 'Voter'
+        db.delete_table('helios_voter')
+
+        # Deleting model 'CastVote'
+        db.delete_table('helios_castvote')
+
+        # Deleting model 'AuditedBallot'
+        db.delete_table('helios_auditedballot')
+
+        # Deleting model 'Trustee'
+        db.delete_table('helios_trustee')
+
+
+    models = {
+        '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': ('auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('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'})
+        },
+        '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'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            '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['auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'eligibility': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', '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': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('auth.jsonfield.JSONField', [], {'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_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': {'object_name': 'Trustee'},
+            'decryption_factors': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('auth.jsonfield.JSONField', [], {'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': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'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'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'voter_type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        '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'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/migrations/__init__.py b/helios/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/settings.py.sample b/settings.py.sample
index 936054a..0728901 100644
--- a/settings.py.sample
+++ b/settings.py.sample
@@ -79,6 +79,8 @@ INSTALLED_APPS = (
     'django.contrib.sites',
     ## needed for queues
     'djcelery',
+    ## needed for schema migration
+    'south',
     ## HELIOS stuff
     'auth',
     'helios',
-- 
GitLab