From 3282d60d17f0ce8d6c3cebdfa786e8caca0d89a6 Mon Sep 17 00:00:00 2001
From: Megan Henning <meganhenning@flywheel.io>
Date: Wed, 10 May 2017 18:27:34 -0500
Subject: [PATCH] Ensure subject age is int

---
 bin/database.py                               | 20 ++++++++++++-
 raml/schemas/definitions/subject.json         |  2 +-
 .../python/test_containers.py                 | 29 +++++++++++++++++++
 3 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/bin/database.py b/bin/database.py
index 55126e04..497c20c1 100755
--- a/bin/database.py
+++ b/bin/database.py
@@ -19,7 +19,7 @@ from api.jobs.jobs import Job
 from api.jobs import gears
 from api.types import Origin
 
-CURRENT_DATABASE_VERSION = 27 # An int that is bumped when a new schema change is made
+CURRENT_DATABASE_VERSION = 28 # An int that is bumped when a new schema change is made
 
 def get_db_version():
 
@@ -93,6 +93,7 @@ def process_cursor(cursor, closure):
     # pool.close()
     # pool.join()
 
+    logging.info('Proccessing {} items in cursor ...'.format(cursor.count()))
 
     failed = False
     for document in cursor:
@@ -990,6 +991,21 @@ def upgrade_to_27():
         config.db.projects.update_one({'_id': p['_id']}, {'$set': {'template': template}})
         storage.recalc_sessions_compliance(project_id=str(p['_id']))
 
+def upgrade_to_28():
+    """
+    Fixes session.subject.age sometimes being a floating-point rather than integer.
+    """
+
+    sessions = config.db.sessions.find({'subject.age': {'$type': 'double'}})
+    logging.info('Fixing {} subjects with age stored as double ...'.format(sessions.count()))
+    for x in sessions:
+        try:
+            int_age = int(x['subject']['age'])
+        except:
+            int_age = None
+
+        config.db.sessions.update({'_id': x['_id']}, {'$set': {'subject.age': int_age}})
+
 
 def upgrade_schema():
     """
@@ -1003,7 +1019,9 @@ def upgrade_schema():
         while db_version < CURRENT_DATABASE_VERSION:
             db_version += 1
             upgrade_script = 'upgrade_to_'+str(db_version)
+            logging.info('Upgrading to version {} ...'.format(db_version))
             globals()[upgrade_script]()
+            logging.info('Upgrade to version {} complete.'.format(db_version))
     except KeyError as e:
         logging.exception('Attempted to upgrade using script that does not exist: {}'.format(e))
         sys.exit(1)
diff --git a/raml/schemas/definitions/subject.json b/raml/schemas/definitions/subject.json
index a71d3aaa..7218d203 100644
--- a/raml/schemas/definitions/subject.json
+++ b/raml/schemas/definitions/subject.json
@@ -7,7 +7,7 @@
         "firstname_hash":   { "type": ["string", "null"] },
         "lastname_hash":    { "type": ["string", "null"] },
 
-        "age":              { "type": ["number", "null"] },
+        "age":              { "type": ["integer", "null"] },
         "sex":              { "enum": ["male", "female", "other", "unknown", null] },
         "race":             { "enum": ["American Indian or Alaska Native", "Asian", "Native Hawaiian or Other Pacific Islander", "Black or African American", "White", "More Than One Race", "Unknown or Not Reported", null] },
         "ethnicity":        { "enum": ["Not Hispanic or Latino", "Hispanic or Latino", "Unknown or Not Reported", null] },
diff --git a/test/integration_tests/python/test_containers.py b/test/integration_tests/python/test_containers.py
index 9e61f029..05fb1f94 100644
--- a/test/integration_tests/python/test_containers.py
+++ b/test/integration_tests/python/test_containers.py
@@ -285,3 +285,32 @@ def test_put_container(data_builder, as_admin):
         'subject': {'_id': '000000000000000000000000'}
     })
     assert r.ok
+
+def test_subject_age_must_be_int(data_builder, as_admin):
+    # Ensure subject age can only be set as int (and None)
+    # Found old data that had subject age stored as float
+
+    session = data_builder.create_session()
+
+    subject_age = 123.2
+
+    # Attempt to send age as float
+    r = as_admin.put('/sessions/' + session, json={
+        'subject': {
+            'age': subject_age
+        }
+    })
+    assert r.status_code == 400
+
+    subject_age = 123
+
+    # Ensure subject age set as int works correctly
+    r = as_admin.put('/sessions/' + session, json={
+        'subject': {
+            'age': subject_age
+        }
+    })
+    assert r.ok
+
+    r = as_admin.get('/sessions/' + session)
+    assert subject_age == r.json['subject']['age']
-- 
GitLab