Repository: fossasia/open-event-server

Issue:
Migration error while setting database fields as NOT NULL
The following migration error occurs. 

```
column "licence" contains null values
 [SQL: 'ALTER TABLE event_copyrights ALTER COLUMN licence SET NOT NULL']
```

Please delete the records that have null value. Also check other migration files after this, to ensure all migrations do proper checks and clean up existing data. 

---

**Full log for reference:**
```
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade 63deafdfebd6 -> 740b89e12cbb, empty message
Traceback (most recent call last):
  File "manage.py", line 109, in <module>
    manager.run()
  File "/usr/local/lib/python2.7/site-packages/flask_script/__init__.py", line 412, in run
    result = self.handle(sys.argv[0], sys.argv[1:])
  File "/usr/local/lib/python2.7/site-packages/flask_script/__init__.py", line 383, in handle
    res = handle(*args, **config)
  File "/usr/local/lib/python2.7/site-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/flask_migrate/__init__.py", line 247, in upgrade
    command.upgrade(config, revision, sql=sql, tag=tag)
  File "/usr/local/lib/python2.7/site-packages/alembic/command.py", line 254, in upgrade
    script.run_env()
  File "/usr/local/lib/python2.7/site-packages/alembic/script/base.py", line 425, in run_env
    util.load_python_file(self.dir, 'env.py')
  File "/usr/local/lib/python2.7/site-packages/alembic/util/pyfiles.py", line 93, in load_python_file
    module = load_module_py(module_id, path)
  File "/usr/local/lib/python2.7/site-packages/alembic/util/compat.py", line 75, in load_module_py
    mod = imp.load_source(module_id, path, fp)
  File "migrations/env.py", line 158, in <module>
    run_migrations_online()
  File "migrations/env.py", line 151, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/usr/local/lib/python2.7/site-packages/alembic/runtime/environment.py", line 836, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/usr/local/lib/python2.7/site-packages/alembic/runtime/migration.py", line 330, in run_migrations
    step.migration_fn(**kw)
  File "/opev/open_event/migrations/versions/740b89e12cbb_.py", line 23, in upgrade
    nullable=False)
  File "<string>", line 8, in alter_column
  File "<string>", line 3, in alter_column
  File "/usr/local/lib/python2.7/site-packages/alembic/operations/ops.py", line 1430, in alter_column
    return operations.invoke(alt)
  File "/usr/local/lib/python2.7/site-packages/alembic/operations/base.py", line 318, in invoke
    return fn(self, operation)
  File "/usr/local/lib/python2.7/site-packages/alembic/operations/toimpl.py", line 53, in alter_column
    **operation.kw
  File "/usr/local/lib/python2.7/site-packages/alembic/ddl/postgresql.py", line 118, in alter_column
    **kw)
  File "/usr/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 145, in alter_column
    existing_nullable=existing_nullable,
  File "/usr/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 118, in _exec
    return conn.execute(construct, *multiparams, **params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 945, in execute
    return meth(self, multiparams, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection
    return connection._execute_ddl(self, multiparams, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1002, in _execute_ddl
    compiled
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1189, in _execute_context
    context)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1402, in _handle_dbapi_exception
    exc_info
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
    context)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 470, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) column "licence" contains null values
 [SQL: 'ALTER TABLE event_copyrights ALTER COLUMN licence SET NOT NULL']
```


Discussion:

Resolving patch:
diff --git a/app/models/role_invite.py b/app/models/role_invite.py
--- a/app/models/role_invite.py
+++ b/app/models/role_invite.py
@@ -13,7 +13,7 @@ class RoleInvite(db.Model):
 
     id = db.Column(db.Integer, primary_key=True)
 
-    email = db.Column(db.String)
+    email = db.Column(db.String, nullable=False)
 
     event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
     event = db.relationship('Event', back_populates='role_invites')
diff --git a/migrations/versions/740b89e12cbb_.py b/migrations/versions/740b89e12cbb_.py
--- a/migrations/versions/740b89e12cbb_.py
+++ b/migrations/versions/740b89e12cbb_.py
@@ -17,7 +17,29 @@
 
 
 def upgrade():
-    # ### commands auto generated by Alembic - please adjust! ###
+    # commands auto generated by Alembic - please adjust! #
+    op.execute("DELETE FROM event_copyrights WHERE licence='' ",
+               execution_options=None)
+    op.execute("DELETE FROM sessions WHERE title='' ",
+               execution_options=None)
+    op.execute("DELETE FROM social_links WHERE link='' ",
+               execution_options=None)
+    op.execute("DELETE FROM speakers_calls WHERE announcement='' ",
+               execution_options=None)
+    op.execute("DELETE FROM ticket_holders WHERE firstname='' ",
+               execution_options=None)
+    op.execute("DELETE FROM tickets WHERE name='' ",
+               execution_options=None)
+    op.execute("DELETE FROM tickets WHERE sales_ends_at IS NULL",
+               execution_options=None)
+    op.execute("DELETE FROM tickets WHERE sales_starts_at IS NULL",
+               execution_options=None)
+    op.execute("DELETE FROM tickets WHERE type='' ",
+               execution_options=None)
+    op.execute("DELETE FROM users WHERE _email='' ",
+               execution_options=None)
+    op.execute("DELETE FROM users WHERE _password='' ",
+               execution_options=None)
     op.alter_column('event_copyrights', 'licence',
                     existing_type=sa.VARCHAR(),
                     nullable=False)
@@ -51,11 +73,11 @@ def upgrade():
     op.alter_column('users', '_password',
                     existing_type=sa.VARCHAR(length=128),
                     nullable=False)
-    # ### end Alembic commands ###
+    # end Alembic commands #
 
 
 def downgrade():
-    # ### commands auto generated by Alembic - please adjust! ###
+    # commands auto generated by Alembic - please adjust! #
     op.alter_column('users', '_password',
                     existing_type=sa.VARCHAR(length=128),
                     nullable=True)
@@ -89,4 +111,4 @@ def downgrade():
     op.alter_column('event_copyrights', 'licence',
                     existing_type=sa.VARCHAR(),
                     nullable=True)
-    # ### end Alembic commands ###
+    # end Alembic commands #
diff --git a/migrations/versions/1adc6271d9fc_.py b/migrations/versions/9e1204b2e096_.py
similarity index 71%
rename from migrations/versions/1adc6271d9fc_.py
rename to migrations/versions/9e1204b2e096_.py
--- a/migrations/versions/1adc6271d9fc_.py
+++ b/migrations/versions/9e1204b2e096_.py
@@ -7,6 +7,7 @@
 """
 
 from alembic import op
+import sqlalchemy as sa
 
 
 # revision identifiers, used by Alembic.
@@ -16,6 +17,11 @@
 
 def upgrade():
     # commands auto generated by Alembic - please adjust! #
+    op.execute("DELETE FROM role_invites WHERE email='' ",
+               execution_options=None)
+    op.alter_column('role_invites', 'email',
+                    existing_type=sa.VARCHAR(),
+                    nullable=False)
     op.alter_column('role_invites', 'is_declined', new_column_name='status')
     op.execute("ALTER TABLE role_invites ALTER status TYPE varchar USING CASE status WHEN TRUE THEN 'declined'\
                 ELSE 'pending' END", execution_options=None)
@@ -24,6 +30,9 @@ def upgrade():
 
 def downgrade():
     # commands auto generated by Alembic - please adjust! #
+    op.alter_column('role_invites', 'email',
+                    existing_type=sa.VARCHAR(),
+                    nullable=True)
     op.execute("ALTER TABLE role_invites ALTER status TYPE boolean USING CASE status WHEN 'declined' THEN TRUE\
                 ELSE FALSE END", execution_options=None)
     op.alter_column('role_invites', 'status', new_column_name='is_declined')


Test patch: