From 6cfc1830d1d39812b661fe61a4e91346174ef91f Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 07:26:05 +0100 Subject: [PATCH 1/9] Add cascades --- flaskbb/forum/models.py | 66 ++++--- flaskbb/management/models.py | 10 +- flaskbb/message/models.py | 15 +- flaskbb/plugins/models.py | 5 +- flaskbb/user/models.py | 32 ++-- ...2053_ec39ababe957_add_ondelete_cascades.py | 174 ++++++++++++++++++ 6 files changed, 242 insertions(+), 60 deletions(-) create mode 100644 migrations/201802012053_ec39ababe957_add_ondelete_cascades.py diff --git a/flaskbb/forum/models.py b/flaskbb/forum/models.py index 4931dd088..1e3182185 100644 --- a/flaskbb/forum/models.py +++ b/flaskbb/forum/models.py @@ -27,30 +27,33 @@ moderators = db.Table( 'moderators', - db.Column('user_id', db.Integer(), db.ForeignKey('users.id'), + db.Column('user_id', db.Integer(), + db.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), db.Column('forum_id', db.Integer(), - db.ForeignKey('forums.id', use_alter=True, + db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE", name="fk_mods_forum_id"), nullable=False)) topictracker = db.Table( 'topictracker', - db.Column('user_id', db.Integer(), db.ForeignKey('users.id'), + db.Column('user_id', db.Integer(), + db.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), db.Column('topic_id', db.Integer(), - db.ForeignKey('topics.id', use_alter=True, + db.ForeignKey('topics.id', use_alter=True, ondelete="CASCADE", name="fk_tracker_topic_id"), nullable=False)) forumgroups = db.Table( 'forumgroups', - db.Column('group_id', db.Integer(), db.ForeignKey('groups.id'), + db.Column('group_id', db.Integer(), + db.ForeignKey('groups.id', ondelete="CASCADE"), nullable=False), db.Column('forum_id', db.Integer(), - db.ForeignKey('forums.id', use_alter=True, + db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE", name="fk_fg_forum_id"), nullable=False)) @@ -58,17 +61,20 @@ class TopicsRead(db.Model, CRUDMixin): __tablename__ = "topicsread" - user_id = db.Column(db.Integer, db.ForeignKey("users.id"), + user_id = db.Column(db.Integer, + db.ForeignKey("users.id", ondelete="CASCADE"), primary_key=True) user = db.relationship('User', uselist=False, foreign_keys=[user_id]) topic_id = db.Column(db.Integer, db.ForeignKey("topics.id", use_alter=True, - name="fk_tr_topic_id"), + name="fk_tr_topic_id", + ondelete="CASCADE"), primary_key=True) topic = db.relationship('Topic', uselist=False, foreign_keys=[topic_id]) forum_id = db.Column(db.Integer, db.ForeignKey("forums.id", use_alter=True, - name="fk_tr_forum_id"), + name="fk_tr_forum_id", + ondelete="CASCADE"), primary_key=True) forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id]) last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow, @@ -78,12 +84,14 @@ class TopicsRead(db.Model, CRUDMixin): class ForumsRead(db.Model, CRUDMixin): __tablename__ = "forumsread" - user_id = db.Column(db.Integer, db.ForeignKey("users.id"), + user_id = db.Column(db.Integer, + db.ForeignKey("users.id", ondelete="CASCADE"), primary_key=True) user = db.relationship('User', uselist=False, foreign_keys=[user_id]) forum_id = db.Column(db.Integer, db.ForeignKey("forums.id", use_alter=True, - name="fk_fr_forum_id"), + name="fk_fr_forum_id", + ondelete="CASCADE"), primary_key=True) forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id]) last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow, @@ -390,7 +398,7 @@ class Topic(HideableCRUDMixin, db.Model): id = db.Column(db.Integer, primary_key=True) forum_id = db.Column(db.Integer, db.ForeignKey("forums.id", - use_alter=True, + use_alter=True, ondelete="CASCADE", name="fk_topic_forum_id"), nullable=False) title = db.Column(db.String(255), nullable=False) @@ -667,6 +675,12 @@ def delete(self, users=None): db.session.delete(self) self._fix_user_post_counts(users or self.involved_users().all()) self._fix_post_counts(forum) + + # forum.last_post_id shouldn't usually be none + if forum.last_post_id is None or \ + self.last_post_id == forum.last_post_id: + forum.update_last_post(commit=False) + db.session.commit() return self @@ -723,8 +737,6 @@ def _remove_topic_from_forum(self): self.forum.last_post_username = None self.forum.last_post_created = None - TopicsRead.query.filter_by(topic_id=self.id).delete() - def _fix_user_post_counts(self, users=None): # Update the post counts if users: @@ -789,7 +801,8 @@ class Forum(db.Model, CRUDMixin): __tablename__ = "forums" id = db.Column(db.Integer, primary_key=True) - category_id = db.Column(db.Integer, db.ForeignKey("categories.id"), + category_id = db.Column(db.Integer, + db.ForeignKey("categories.id", ondelete="CASCADE"), nullable=False) title = db.Column(db.String(255), nullable=False) description = db.Column(db.Text, nullable=True) @@ -803,11 +816,14 @@ class Forum(db.Model, CRUDMixin): # One-to-one last_post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), - nullable=True) + nullable=True) # we handle this case ourselfs last_post = db.relationship("Post", backref="last_post_forum", uselist=False, foreign_keys=[last_post_id]) - last_post_user_id = db.Column(db.Integer, db.ForeignKey("users.id"), + # set to null if the user got deleted + last_post_user_id = db.Column(db.Integer, + db.ForeignKey("users.id", + ondelete="SET NULL"), nullable=True) last_post_user = db.relationship( @@ -827,8 +843,7 @@ class Forum(db.Model, CRUDMixin): topics = db.relationship( "Topic", backref="forum", - lazy="dynamic", - cascade="all, delete-orphan" + lazy="dynamic" ) # Many-to-many @@ -872,7 +887,7 @@ def __repr__(self): """ return "<{} {}>".format(self.__class__.__name__, self.id) - def update_last_post(self): + def update_last_post(self, commit=True): """Updates the last post in the forum.""" last_post = Post.query.\ filter(Post.topic_id == Topic.id, @@ -900,7 +915,8 @@ def update_last_post(self): self.last_post_username = None self.last_post_created = None - db.session.commit() + if commit: + db.session.commit() def update_read(self, user, forumsread, topicsread): """Updates the ForumsRead status for the user. In order to work @@ -1021,11 +1037,6 @@ def delete(self, users=None): db.session.delete(self) db.session.commit() - # Delete the entries for the forum in the ForumsRead and TopicsRead - # relation - ForumsRead.query.filter_by(forum_id=self.id).delete() - TopicsRead.query.filter_by(forum_id=self.id).delete() - # Update the users post count if users: users_list = [] @@ -1113,8 +1124,7 @@ class Category(db.Model, CRUDMixin): # One-to-many forums = db.relationship("Forum", backref="category", lazy="dynamic", primaryjoin='Forum.category_id == Category.id', - order_by='asc(Forum.position)', - cascade="all, delete-orphan") + order_by='asc(Forum.position)') # Properties @property diff --git a/flaskbb/management/models.py b/flaskbb/management/models.py index f39d10db7..900038778 100644 --- a/flaskbb/management/models.py +++ b/flaskbb/management/models.py @@ -10,13 +10,10 @@ """ import logging -from flask_wtf import FlaskForm -from flaskbb._compat import iteritems, text_type +from flaskbb._compat import iteritems from flaskbb.extensions import cache, db from flaskbb.utils.database import CRUDMixin from flaskbb.utils.forms import SettingValueType, generate_settings_form -from wtforms import (BooleanField, FloatField, IntegerField, SelectField, - SelectMultipleField, TextField, validators) logger = logging.getLogger(__name__) @@ -27,8 +24,7 @@ class SettingsGroup(db.Model, CRUDMixin): key = db.Column(db.String(255), primary_key=True) name = db.Column(db.String(255), nullable=False) description = db.Column(db.Text, nullable=False) - settings = db.relationship("Setting", lazy="dynamic", backref="group", - cascade="all, delete-orphan") + settings = db.relationship("Setting", lazy="dynamic", backref="group") def __repr__(self): return "<{} {}>".format(self.__class__.__name__, self.key) @@ -41,7 +37,7 @@ class Setting(db.Model, CRUDMixin): value = db.Column(db.PickleType, nullable=False) settingsgroup = db.Column(db.String(255), db.ForeignKey('settingsgroup.key', - use_alter=True, + use_alter=True, ondelete="CASCADE", name="fk_settingsgroup"), nullable=False) diff --git a/flaskbb/message/models.py b/flaskbb/message/models.py index d2e07dcad..2263c16a6 100644 --- a/flaskbb/message/models.py +++ b/flaskbb/message/models.py @@ -23,7 +23,9 @@ class Conversation(db.Model, CRUDMixin): __tablename__ = "conversations" id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False) + user_id = db.Column(db.Integer, + db.ForeignKey("users.id", ondelete="CASCADE"), + nullable=False) from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True) to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"), @@ -41,8 +43,7 @@ class Conversation(db.Model, CRUDMixin): messages = db.relationship( "Message", lazy="joined", backref="conversation", primaryjoin="Message.conversation_id == Conversation.id", - order_by="asc(Message.id)", - cascade="all, delete-orphan" + order_by="asc(Message.id)" ) # this is actually the users message box @@ -89,11 +90,15 @@ class Message(db.Model, CRUDMixin): __tablename__ = "messages" id = db.Column(db.Integer, primary_key=True) - conversation_id = db.Column(db.Integer, db.ForeignKey("conversations.id"), + conversation_id = db.Column(db.Integer, + db.ForeignKey("conversations.id", + ondelete="CASCADE"), nullable=False) # the user who wrote the message - user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False) + user_id = db.Column(db.Integer, + db.ForeignKey("users.id", ondelete="CASCADE"), + nullable=False) message = db.Column(db.Text, nullable=False) date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow, nullable=False) diff --git a/flaskbb/plugins/models.py b/flaskbb/plugins/models.py index 4de831950..e398fb4bb 100644 --- a/flaskbb/plugins/models.py +++ b/flaskbb/plugins/models.py @@ -28,7 +28,9 @@ class PluginStore(CRUDMixin, db.Model): # Extra attributes like, validation things (min, max length...) # For Select*Fields required: choices extra = db.Column(db.PickleType, nullable=True) - plugin_id = db.Column(db.Integer, db.ForeignKey('plugin_registry.id')) + plugin_id = db.Column(db.Integer, + db.ForeignKey("plugin_registry.id", + ondelete="CASCADE")) # Display stuff name = db.Column(db.Unicode(255), nullable=False) @@ -62,7 +64,6 @@ class PluginRegistry(CRUDMixin, db.Model): values = db.relationship( 'PluginStore', collection_class=attribute_mapped_collection('key'), - cascade='all, delete-orphan', backref='plugin' ) diff --git a/flaskbb/user/models.py b/flaskbb/user/models.py index 5e42ed7b4..02ccc41ca 100644 --- a/flaskbb/user/models.py +++ b/flaskbb/user/models.py @@ -28,9 +28,11 @@ groups_users = db.Table( 'groups_users', - db.Column('user_id', db.Integer, db.ForeignKey('users.id'), + db.Column('user_id', db.Integer, + db.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), - db.Column('group_id', db.Integer, db.ForeignKey('groups.id'), + db.Column('group_id', db.Integer, + db.ForeignKey('groups.id', ondelete="CASCADE"), nullable=False) ) @@ -115,8 +117,10 @@ class User(db.Model, UserMixin, CRUDMixin): theme = db.Column(db.String(15), nullable=True) language = db.Column(db.String(15), default="en", nullable=True) - posts = db.relationship("Post", backref="user", lazy="dynamic", primaryjoin="User.id == Post.user_id") - topics = db.relationship("Topic", backref="user", lazy="dynamic", primaryjoin="User.id == Topic.user_id") + posts = db.relationship("Post", backref="user", lazy="dynamic", + primaryjoin="User.id == Post.user_id") + topics = db.relationship("Topic", backref="user", lazy="dynamic", + primaryjoin="User.id == Topic.user_id") post_count = db.Column(db.Integer, default=0) @@ -194,7 +198,6 @@ def message_count(self): Conversation.id == Message.conversation_id ).count() - @property def days_registered(self): """Returns the amount of days the user is registered.""" @@ -480,22 +483,15 @@ def save(self, groups=None): def delete(self): """Deletes the User.""" - # This isn't done automatically... - Conversation.query.filter_by(user_id=self.id).delete() - ForumsRead.query.filter_by(user_id=self.id).delete() - TopicsRead.query.filter_by(user_id=self.id).delete() # This should actually be handeld by the dbms.. but dunno why it doesnt # work here - from flaskbb.forum.models import Forum - - last_post_forums = Forum.query.\ - filter_by(last_post_user_id=self.id).all() - - for forum in last_post_forums: - forum.last_post_user_id = None - forum.save() - + #from flaskbb.forum.models import Forum + #last_post_forums = Forum.query.\ + # filter_by(last_post_user_id=self.id).all() + #for forum in last_post_forums: + # forum.last_post_user_id = None + # forum.save() db.session.delete(self) db.session.commit() diff --git a/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py b/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py new file mode 100644 index 000000000..928c08611 --- /dev/null +++ b/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py @@ -0,0 +1,174 @@ +"""Add ondelete cascades + +Revision ID: ec39ababe957 +Revises: 7c3fcf8a3335 +Create Date: 2018-02-01 20:53:08.146277 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ec39ababe957' +down_revision = '7c3fcf8a3335' +branch_labels = () +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('conversations', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key("fk_conversations_user_id", 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('forumgroups', schema=None) as batch_op: + batch_op.drop_constraint('fk_forum_id', type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key('fk_fg_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) + + with op.batch_alter_table('forums', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id'], ondelete='SET NULL') + + with op.batch_alter_table('forumsread', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('groups_users', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('messages', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('moderators', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_mods_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('plugin_store', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('posts', schema=None) as batch_op: + batch_op.alter_column('hidden', + existing_type=sa.BOOLEAN(), + nullable=True) + + with op.batch_alter_table('settings', schema=None) as batch_op: + batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey') + batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key'], ondelete='CASCADE', use_alter=True) + + with op.batch_alter_table('topics', schema=None) as batch_op: + batch_op.alter_column('hidden', + existing_type=sa.BOOLEAN(), + nullable=True) + batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) + + with op.batch_alter_table('topicsread', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey') + batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey') + batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True) + batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('topictracker', schema=None) as batch_op: + batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('topictracker', schema=None) as batch_op: + batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id']) + + with op.batch_alter_table('topicsread', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey') + batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey') + batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id']) + batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id']) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + + with op.batch_alter_table('topics', schema=None) as batch_op: + batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id']) + batch_op.alter_column('hidden', + existing_type=sa.BOOLEAN(), + nullable=False) + + with op.batch_alter_table('settings', schema=None) as batch_op: + batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey') + batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key']) + + with op.batch_alter_table('posts', schema=None) as batch_op: + batch_op.alter_column('hidden', + existing_type=sa.BOOLEAN(), + nullable=False) + + with op.batch_alter_table('plugin_store', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id']) + + with op.batch_alter_table('moderators', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_mods_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id']) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + + with op.batch_alter_table('messages', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id']) + + with op.batch_alter_table('groups_users', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id']) + + with op.batch_alter_table('forumsread', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey') + batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id']) + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + + with op.batch_alter_table('forums', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id']) + batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id']) + + with op.batch_alter_table('forumgroups', schema=None) as batch_op: + batch_op.drop_constraint('fk_fg_forum_id', type_='foreignkey') + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id']) + batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id']) + + with op.batch_alter_table('conversations', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + + # ### end Alembic commands ### From 5289219f4ad5f5886c0804f0f64537184b31794b Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 11:00:59 +0100 Subject: [PATCH 2/9] Remove use_alter and self-defined fk names This is not needed anymore as of SQLAlchemy>=1.0 See: http://docs.sqlalchemy.org/en/latest/core/constraints.html#sqlalchemy.schema.ForeignKeyConstraint.params.use_alter --- flaskbb/forum/models.py | 30 ++++++++---------------------- flaskbb/management/models.py | 3 +-- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/flaskbb/forum/models.py b/flaskbb/forum/models.py index 1e3182185..ce199f689 100644 --- a/flaskbb/forum/models.py +++ b/flaskbb/forum/models.py @@ -31,8 +31,7 @@ db.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), db.Column('forum_id', db.Integer(), - db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE", - name="fk_mods_forum_id"), + db.ForeignKey('forums.id', ondelete="CASCADE"), nullable=False)) @@ -42,8 +41,7 @@ db.ForeignKey('users.id', ondelete="CASCADE"), nullable=False), db.Column('topic_id', db.Integer(), - db.ForeignKey('topics.id', use_alter=True, ondelete="CASCADE", - name="fk_tracker_topic_id"), + db.ForeignKey('topics.id', ondelete="CASCADE"), nullable=False)) @@ -53,8 +51,7 @@ db.ForeignKey('groups.id', ondelete="CASCADE"), nullable=False), db.Column('forum_id', db.Integer(), - db.ForeignKey('forums.id', use_alter=True, ondelete="CASCADE", - name="fk_fg_forum_id"), + db.ForeignKey('forums.id', ondelete="CASCADE"), nullable=False)) @@ -66,15 +63,11 @@ class TopicsRead(db.Model, CRUDMixin): primary_key=True) user = db.relationship('User', uselist=False, foreign_keys=[user_id]) topic_id = db.Column(db.Integer, - db.ForeignKey("topics.id", use_alter=True, - name="fk_tr_topic_id", - ondelete="CASCADE"), + db.ForeignKey("topics.id", ondelete="CASCADE"), primary_key=True) topic = db.relationship('Topic', uselist=False, foreign_keys=[topic_id]) forum_id = db.Column(db.Integer, - db.ForeignKey("forums.id", use_alter=True, - name="fk_tr_forum_id", - ondelete="CASCADE"), + db.ForeignKey("forums.id", ondelete="CASCADE"), primary_key=True) forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id]) last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow, @@ -89,9 +82,7 @@ class ForumsRead(db.Model, CRUDMixin): primary_key=True) user = db.relationship('User', uselist=False, foreign_keys=[user_id]) forum_id = db.Column(db.Integer, - db.ForeignKey("forums.id", use_alter=True, - name="fk_fr_forum_id", - ondelete="CASCADE"), + db.ForeignKey("forums.id", ondelete="CASCADE"), primary_key=True) forum = db.relationship('Forum', uselist=False, foreign_keys=[forum_id]) last_read = db.Column(UTCDateTime(timezone=True), default=time_utcnow, @@ -157,10 +148,7 @@ class Post(HideableCRUDMixin, db.Model): id = db.Column(db.Integer, primary_key=True) topic_id = db.Column(db.Integer, - db.ForeignKey("topics.id", - use_alter=True, - name="fk_post_topic_id", - ondelete="CASCADE"), + db.ForeignKey("topics.id", ondelete="CASCADE"), nullable=True) user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True) username = db.Column(db.String(200), nullable=False) @@ -397,9 +385,7 @@ class Topic(HideableCRUDMixin, db.Model): id = db.Column(db.Integer, primary_key=True) forum_id = db.Column(db.Integer, - db.ForeignKey("forums.id", - use_alter=True, ondelete="CASCADE", - name="fk_topic_forum_id"), + db.ForeignKey("forums.id", ondelete="CASCADE"), nullable=False) title = db.Column(db.String(255), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True) diff --git a/flaskbb/management/models.py b/flaskbb/management/models.py index 900038778..ca6d6e7e0 100644 --- a/flaskbb/management/models.py +++ b/flaskbb/management/models.py @@ -37,8 +37,7 @@ class Setting(db.Model, CRUDMixin): value = db.Column(db.PickleType, nullable=False) settingsgroup = db.Column(db.String(255), db.ForeignKey('settingsgroup.key', - use_alter=True, ondelete="CASCADE", - name="fk_settingsgroup"), + ondelete="CASCADE"), nullable=False) # The name (displayed in the form) From ee3441dc8bbe4a4a0771d870c3a9b59a1b4a08f9 Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 11:01:28 +0100 Subject: [PATCH 3/9] Use global naming convetion for all constraints --- flaskbb/extensions.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/flaskbb/extensions.py b/flaskbb/extensions.py index 954c07c52..7d81e5bb4 100644 --- a/flaskbb/extensions.py +++ b/flaskbb/extensions.py @@ -27,7 +27,7 @@ WhoosheeQuery) from flask_wtf.csrf import CSRFProtect from flaskbb.exceptions import AuthorizationRequired -from sqlalchemy import event +from sqlalchemy import MetaData, event from sqlalchemy.orm import Query as SQLAQuery @@ -73,7 +73,15 @@ def register_whoosheer(self, wh): allows = Allows(throws=AuthorizationRequired) # Database -db = SQLAlchemy() +metadata = MetaData( + naming_convention={ + "ix": 'ix_%(column_0_label)s', + "uq": "uq_%(table_name)s_%(column_0_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s" + } +) +db = SQLAlchemy(metadata=metadata) # Whooshee (Full Text Search) whooshee = FlaskBBWhooshee() From 23b9d745bddfff2843ea78610ec372b665925d60 Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 11:01:47 +0100 Subject: [PATCH 4/9] Add migrations --- ...2053_ec39ababe957_add_ondelete_cascades.py | 174 ------------- .../201802021027_af3f5579c84d_add_cascades.py | 234 ++++++++++++++++++ 2 files changed, 234 insertions(+), 174 deletions(-) delete mode 100644 migrations/201802012053_ec39ababe957_add_ondelete_cascades.py create mode 100644 migrations/201802021027_af3f5579c84d_add_cascades.py diff --git a/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py b/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py deleted file mode 100644 index 928c08611..000000000 --- a/migrations/201802012053_ec39ababe957_add_ondelete_cascades.py +++ /dev/null @@ -1,174 +0,0 @@ -"""Add ondelete cascades - -Revision ID: ec39ababe957 -Revises: 7c3fcf8a3335 -Create Date: 2018-02-01 20:53:08.146277 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'ec39ababe957' -down_revision = '7c3fcf8a3335' -branch_labels = () -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('conversations', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key("fk_conversations_user_id", 'users', ['user_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('forumgroups', schema=None) as batch_op: - batch_op.drop_constraint('fk_forum_id', type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key('fk_fg_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) - - with op.batch_alter_table('forums', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id'], ondelete='SET NULL') - - with op.batch_alter_table('forumsread', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('groups_users', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('messages', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('moderators', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_mods_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('plugin_store', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('posts', schema=None) as batch_op: - batch_op.alter_column('hidden', - existing_type=sa.BOOLEAN(), - nullable=True) - - with op.batch_alter_table('settings', schema=None) as batch_op: - batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey') - batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key'], ondelete='CASCADE', use_alter=True) - - with op.batch_alter_table('topics', schema=None) as batch_op: - batch_op.alter_column('hidden', - existing_type=sa.BOOLEAN(), - nullable=True) - batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) - - with op.batch_alter_table('topicsread', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey') - batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey') - batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True) - batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id'], ondelete='CASCADE', use_alter=True) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - - with op.batch_alter_table('topictracker', schema=None) as batch_op: - batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id'], ondelete='CASCADE', use_alter=True) - - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('topictracker', schema=None) as batch_op: - batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - batch_op.create_foreign_key('fk_tracker_topic_id', 'topics', ['topic_id'], ['id']) - - with op.batch_alter_table('topicsread', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey') - batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey') - batch_op.create_foreign_key('fk_tr_topic_id', 'topics', ['topic_id'], ['id']) - batch_op.create_foreign_key('fk_tr_forum_id', 'forums', ['forum_id'], ['id']) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - - with op.batch_alter_table('topics', schema=None) as batch_op: - batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_topic_forum_id', 'forums', ['forum_id'], ['id']) - batch_op.alter_column('hidden', - existing_type=sa.BOOLEAN(), - nullable=False) - - with op.batch_alter_table('settings', schema=None) as batch_op: - batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey') - batch_op.create_foreign_key('fk_settingsgroup', 'settingsgroup', ['settingsgroup'], ['key']) - - with op.batch_alter_table('posts', schema=None) as batch_op: - batch_op.alter_column('hidden', - existing_type=sa.BOOLEAN(), - nullable=False) - - with op.batch_alter_table('plugin_store', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'plugin_registry', ['plugin_id'], ['id']) - - with op.batch_alter_table('moderators', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_mods_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id']) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - - with op.batch_alter_table('messages', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - batch_op.create_foreign_key(None, 'conversations', ['conversation_id'], ['id']) - - with op.batch_alter_table('groups_users', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id']) - - with op.batch_alter_table('forumsread', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey') - batch_op.create_foreign_key('fk_fr_forum_id', 'forums', ['forum_id'], ['id']) - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - - with op.batch_alter_table('forums', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'categories', ['category_id'], ['id']) - batch_op.create_foreign_key(None, 'users', ['last_post_user_id'], ['id']) - - with op.batch_alter_table('forumgroups', schema=None) as batch_op: - batch_op.drop_constraint('fk_fg_forum_id', type_='foreignkey') - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'groups', ['group_id'], ['id']) - batch_op.create_foreign_key('fk_forum_id', 'forums', ['forum_id'], ['id']) - - with op.batch_alter_table('conversations', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='foreignkey') - batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) - - # ### end Alembic commands ### diff --git a/migrations/201802021027_af3f5579c84d_add_cascades.py b/migrations/201802021027_af3f5579c84d_add_cascades.py new file mode 100644 index 000000000..b8dfb1da5 --- /dev/null +++ b/migrations/201802021027_af3f5579c84d_add_cascades.py @@ -0,0 +1,234 @@ +"""Add cascades + +Revision ID: af3f5579c84d +Revises: 7c3fcf8a3335 +Create Date: 2018-02-02 10:27:50.290095 + +""" +import logging + +from alembic import op +import sqlalchemy as sa + +logger = logging.getLogger("alembic.runtime.migration") + +# revision identifiers, used by Alembic. +revision = 'af3f5579c84d' +down_revision = '7c3fcf8a3335' +branch_labels = () +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + con = op.get_bind() + + if con.engine.dialect.name == "sqlite": + # its not possible to remove unnamed constraints... + logger.warning("SQLite is only partially supported for revision {}." + .format(revision)) + + with op.batch_alter_table('conversations', schema=None) as batch_op: + if con.engine.dialect.name == "mysql": + # user_id + batch_op.drop_constraint("conversations_ibfk_3", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('conversations_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_conversations_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('forumgroups', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_forum_id', type_='foreignkey') + elif con.engine.dialect.name == "mysql": + # group_id + batch_op.drop_constraint("forumgroups_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('forumgroups_group_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_forumgroups_group_id_groups'), 'groups', ['group_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_forumgroups_forum_id_forums'), 'forums', ['forum_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('forums', schema=None) as batch_op: + if con.engine.dialect.name == "mysql": + # category_id + batch_op.drop_constraint("forums_ibfk_1", type_='foreignkey') + # last_post_user_id + batch_op.drop_constraint("forums_ibfk_3", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('forums_category_id_fkey', type_='foreignkey') + batch_op.drop_constraint('forums_last_post_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_forums_category_id_categories'), 'categories', ['category_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_forums_last_post_user_id_users'), 'users', ['last_post_user_id'], ['id'], ondelete='SET NULL') + + with op.batch_alter_table('forumsread', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_fr_forum_id', type_='foreignkey') + elif con.engine.dialect.name == "mysql": + # user_id + batch_op.drop_constraint("forumsread_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('forumsread_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_forumsread_forum_id_forums'), 'forums', ['forum_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_forumsread_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('groups_users', schema=None) as batch_op: + if con.engine.dialect.name == "mysql": + # group_id + batch_op.drop_constraint("groups_users_ibfk_1", type_='foreignkey') + # user_id + batch_op.drop_constraint("groups_users_ibfk_2", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('groups_users_group_id_fkey', type_='foreignkey') + batch_op.drop_constraint('groups_users_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_groups_users_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_groups_users_group_id_groups'), 'groups', ['group_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('messages', schema=None) as batch_op: + if con.engine.dialect.name == "mysql": + # conversation_id + batch_op.drop_constraint("messages_ibfk_1", type_='foreignkey') + # user_id + batch_op.drop_constraint("messages_ibfk_2", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('messages_conversation_id_fkey', type_='foreignkey') + batch_op.drop_constraint('messages_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_messages_conversation_id_conversations'), 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_messages_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('moderators', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_forum_id', type_='foreignkey') + elif con.engine.dialect.name == "mysql": + # user_id + batch_op.drop_constraint("moderators_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('moderators_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_moderators_forum_id_forums'), 'forums', ['forum_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_moderators_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('plugin_store', schema=None) as batch_op: + if con.engine.dialect.name == "mysql": + # plugin_id + batch_op.drop_constraint("plugin_store_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('plugin_store_plugin_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_plugin_store_plugin_id_plugin_registry'), 'plugin_registry', ['plugin_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('posts', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_post_topic_id', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_posts_topic_id_topics'), 'topics', ['topic_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('settings', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_settingsgroup', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_settings_settingsgroup_settingsgroup'), 'settingsgroup', ['settingsgroup'], ['key'], ondelete='CASCADE') + + with op.batch_alter_table('topics', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_topic_forum_id', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_topics_forum_id_forums'), 'forums', ['forum_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('topicsread', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_tr_forum_id', type_='foreignkey') + batch_op.drop_constraint('fk_tr_topic_id', type_='foreignkey') + elif con.engine.dialect.name == "mysql": + # user_id + batch_op.drop_constraint("topicsread_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('topicsread_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_topicsread_topic_id_topics'), 'topics', ['topic_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_topicsread_forum_id_forums'), 'forums', ['forum_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_topicsread_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('topictracker', schema=None) as batch_op: + if con.engine.dialect.name == "sqlite": + batch_op.drop_constraint('fk_tracker_topic_id', type_='foreignkey') + elif con.engine.dialect.name == "mysql": + # user_id + batch_op.drop_constraint("topictracker_ibfk_1", type_='foreignkey') + elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('topictracker_user_id_fkey', type_='foreignkey') + + batch_op.create_foreign_key(batch_op.f('fk_topictracker_topic_id_topics'), 'topics', ['topic_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_topictracker_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('topictracker', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_topictracker_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_topictracker_topic_id_topics'), type_='foreignkey') + batch_op.create_foreign_key('fk_topictracker_user_id_users', 'users', ['user_id'], ['id']) + + with op.batch_alter_table('topicsread', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_topicsread_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_topicsread_forum_id_forums'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_topicsread_topic_id_topics'), type_='foreignkey') + batch_op.create_foreign_key('fk_topicsread_user_id_users', 'users', ['user_id'], ['id']) + + with op.batch_alter_table('topics', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_topics_forum_id_forums'), type_='foreignkey') + + with op.batch_alter_table('settings', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_settings_settingsgroup_settingsgroup'), type_='foreignkey') + + with op.batch_alter_table('posts', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_posts_topic_id_topics'), type_='foreignkey') + + with op.batch_alter_table('plugin_store', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_plugin_store_plugin_id_plugin_registry'), type_='foreignkey') + batch_op.create_foreign_key('fk_plugin_store_plugin_id_plugin_registry', 'plugin_registry', ['plugin_id'], ['id']) + + with op.batch_alter_table('moderators', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_moderators_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_moderators_forum_id_forums'), type_='foreignkey') + batch_op.create_foreign_key('fk_moderators_user_id_users', 'users', ['user_id'], ['id']) + + with op.batch_alter_table('messages', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_messages_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_messages_conversation_id_conversations'), type_='foreignkey') + batch_op.create_foreign_key('fk_messages_user_id_users', 'users', ['user_id'], ['id']) + batch_op.create_foreign_key('fk_messages_conversation_id_conversations', 'conversations', ['conversation_id'], ['id']) + + with op.batch_alter_table('groups_users', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_groups_users_group_id_groups'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_groups_users_user_id_users'), type_='foreignkey') + batch_op.create_foreign_key('fk_groups_users_user_id_users', 'users', ['user_id'], ['id']) + batch_op.create_foreign_key('fk_groups_users_group_id_groups', 'groups', ['group_id'], ['id']) + + with op.batch_alter_table('forumsread', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_forumsread_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_forumsread_forum_id_forums'), type_='foreignkey') + batch_op.create_foreign_key('fk_forumsread_user_id_users', 'users', ['user_id'], ['id']) + + with op.batch_alter_table('forums', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_forums_last_post_user_id_users'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_forums_category_id_categories'), type_='foreignkey') + batch_op.create_foreign_key('fk_forums_last_post_user_id_users', 'users', ['last_post_user_id'], ['id']) + batch_op.create_foreign_key('fk_forums_category_id_categories', 'categories', ['category_id'], ['id']) + + with op.batch_alter_table('forumgroups', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_forumgroups_forum_id_forums'), type_='foreignkey') + batch_op.drop_constraint(batch_op.f('fk_forumgroups_group_id_groups'), type_='foreignkey') + batch_op.create_foreign_key('fk_forumgroups_group_id_groups', 'groups', ['group_id'], ['id']) + + with op.batch_alter_table('conversations', schema=None) as batch_op: + batch_op.drop_constraint(batch_op.f('fk_conversations_user_id_users'), type_='foreignkey') + batch_op.create_foreign_key('fk_conversations_user_id_users', 'users', ['user_id'], ['id']) + + # ### end Alembic commands ### From a456e57a6161cb72cc7840b2b0dc1c3f4a35fba8 Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 12:26:40 +0100 Subject: [PATCH 5/9] Add note about mysql database charset --- docs/installation.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 9636c8371..ab8653032 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -243,7 +243,13 @@ Both methods are included in the example configs. Installation ------------ -**Sqlite users:** create a DB file in your project source. +**MySQL users:** Make sure that you create the database using the +``utf8mb4`` charset:: + + CREATE DATABASE flaskbb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +See `this `_ SO answer for more +information. For a guided install, run:: From 7394e255eac20edaac5dc5977d0c23f9ee554c17 Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 2 Feb 2018 15:49:37 +0100 Subject: [PATCH 6/9] Make sure that childrens are getting removed when the parent got removed --- flaskbb/forum/models.py | 23 ++++++++++------------- flaskbb/management/models.py | 3 ++- flaskbb/message/models.py | 2 +- flaskbb/plugins/models.py | 3 ++- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/flaskbb/forum/models.py b/flaskbb/forum/models.py index ce199f689..04c32120d 100644 --- a/flaskbb/forum/models.py +++ b/flaskbb/forum/models.py @@ -148,7 +148,8 @@ class Post(HideableCRUDMixin, db.Model): id = db.Column(db.Integer, primary_key=True) topic_id = db.Column(db.Integer, - db.ForeignKey("topics.id", ondelete="CASCADE"), + db.ForeignKey("topics.id", ondelete="CASCADE", + use_alter=True), nullable=True) user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True) username = db.Column(db.String(200), nullable=False) @@ -416,7 +417,8 @@ class Topic(HideableCRUDMixin, db.Model): # One-to-many posts = db.relationship("Post", backref="topic", lazy="dynamic", primaryjoin="Post.topic_id == Topic.id", - cascade="all, delete-orphan", post_update=True) + cascade="all, delete-orphan", + post_update=True) # Properties @property @@ -812,11 +814,8 @@ class Forum(db.Model, CRUDMixin): ondelete="SET NULL"), nullable=True) - last_post_user = db.relationship( - "User", - uselist=False, - foreign_keys=[last_post_user_id] - ) + last_post_user = db.relationship("User", uselist=False, + foreign_keys=[last_post_user_id]) # Not nice, but needed to improve the performance; can be set to NULL # if the forum has no posts @@ -826,11 +825,8 @@ class Forum(db.Model, CRUDMixin): default=time_utcnow, nullable=True) # One-to-many - topics = db.relationship( - "Topic", - backref="forum", - lazy="dynamic" - ) + topics = db.relationship("Topic", backref="forum", lazy="dynamic", + cascade="all, delete-orphan") # Many-to-many moderators = db.relationship( @@ -1110,7 +1106,8 @@ class Category(db.Model, CRUDMixin): # One-to-many forums = db.relationship("Forum", backref="category", lazy="dynamic", primaryjoin='Forum.category_id == Category.id', - order_by='asc(Forum.position)') + order_by='asc(Forum.position)', + cascade="all, delete-orphan") # Properties @property diff --git a/flaskbb/management/models.py b/flaskbb/management/models.py index ca6d6e7e0..d738e8600 100644 --- a/flaskbb/management/models.py +++ b/flaskbb/management/models.py @@ -24,7 +24,8 @@ class SettingsGroup(db.Model, CRUDMixin): key = db.Column(db.String(255), primary_key=True) name = db.Column(db.String(255), nullable=False) description = db.Column(db.Text, nullable=False) - settings = db.relationship("Setting", lazy="dynamic", backref="group") + settings = db.relationship("Setting", lazy="dynamic", backref="group", + cascade="all, delete-orphan") def __repr__(self): return "<{} {}>".format(self.__class__.__name__, self.key) diff --git a/flaskbb/message/models.py b/flaskbb/message/models.py index 2263c16a6..a4601cffd 100644 --- a/flaskbb/message/models.py +++ b/flaskbb/message/models.py @@ -43,7 +43,7 @@ class Conversation(db.Model, CRUDMixin): messages = db.relationship( "Message", lazy="joined", backref="conversation", primaryjoin="Message.conversation_id == Conversation.id", - order_by="asc(Message.id)" + order_by="asc(Message.id)", cascade="all, delete-orphan" ) # this is actually the users message box diff --git a/flaskbb/plugins/models.py b/flaskbb/plugins/models.py index e398fb4bb..16641a22d 100644 --- a/flaskbb/plugins/models.py +++ b/flaskbb/plugins/models.py @@ -64,7 +64,8 @@ class PluginRegistry(CRUDMixin, db.Model): values = db.relationship( 'PluginStore', collection_class=attribute_mapped_collection('key'), - backref='plugin' + backref='plugin', + cascade="all, delete-orphan", ) @property From a55e6f71b270167960a0c2fd0cded30f78414e01 Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Mon, 5 Feb 2018 23:03:12 +0100 Subject: [PATCH 7/9] Only delete the conversations from the user who gets deleted --- flaskbb/message/models.py | 10 ++- flaskbb/templates/layout.html | 9 ++- flaskbb/templates/message/conversation.html | 4 +- .../templates/message/conversation_list.html | 19 ++++- flaskbb/user/models.py | 79 +++++++++++-------- .../201802021027_af3f5579c84d_add_cascades.py | 17 +++- 6 files changed, 93 insertions(+), 45 deletions(-) diff --git a/flaskbb/message/models.py b/flaskbb/message/models.py index a4601cffd..127780583 100644 --- a/flaskbb/message/models.py +++ b/flaskbb/message/models.py @@ -26,9 +26,11 @@ class Conversation(db.Model, CRUDMixin): user_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="CASCADE"), nullable=False) - from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"), + from_user_id = db.Column(db.Integer, db.ForeignKey("users.id", + ondelete="SET NULL"), nullable=True) - to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"), + to_user_id = db.Column(db.Integer, db.ForeignKey("users.id", + ondelete="SET NULL"), nullable=True) shared_id = db.Column(UUIDType, nullable=False) subject = db.Column(db.String(255), nullable=True) @@ -97,8 +99,8 @@ class Message(db.Model, CRUDMixin): # the user who wrote the message user_id = db.Column(db.Integer, - db.ForeignKey("users.id", ondelete="CASCADE"), - nullable=False) + db.ForeignKey("users.id", ondelete="SET NULL"), + nullable=True) message = db.Column(db.Text, nullable=False) date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow, nullable=False) diff --git a/flaskbb/templates/layout.html b/flaskbb/templates/layout.html index 4c4628760..42f5c7b43 100644 --- a/flaskbb/templates/layout.html +++ b/flaskbb/templates/layout.html @@ -97,13 +97,18 @@
  • - {{ message.from_user.username }} {{ message.last_message.date_created|time_since }} + {% if message.from_user %} + {{ message.from_user.username }} + {% else %} + {% trans %}Deleted User{% endtrans %} + {% endif %} + {{ message.last_message.date_created|time_since }}
    {{ message.subject }}
  • {% else %} -
  • No unread messages.
  • +
  • {% trans %}No unread messages.{% endtrans %}
  • {% endfor %}
  • {% trans %}Inbox{% endtrans %}
  • diff --git a/flaskbb/templates/message/conversation.html b/flaskbb/templates/message/conversation.html index 8296c1f88..de4c5a563 100644 --- a/flaskbb/templates/message/conversation.html +++ b/flaskbb/templates/message/conversation.html @@ -98,7 +98,7 @@ {% endif %} {% else %} -

    {% trans %}Deleted{% endtrans %}

    +

    {% trans %}Deleted User{% endtrans %}

    {% trans %}Guest{% endtrans %}
    {% endif %} @@ -110,7 +110,7 @@ -{% if not conversation.draft %} +{% if not conversation.draft and conversation.from_user != None and conversation.to_user != None %} {% from "macros.html" import render_quickreply, render_submit_field %}
    {{ form.hidden_tag() }} diff --git a/flaskbb/templates/message/conversation_list.html b/flaskbb/templates/message/conversation_list.html index 12ebbe3da..02b2bbede 100644 --- a/flaskbb/templates/message/conversation_list.html +++ b/flaskbb/templates/message/conversation_list.html @@ -18,7 +18,7 @@
    - {% if conversation.from_user.avatar %} + {% if conversation.from_user and conversation.from_user.avatar %} avatar {% else %} avatar @@ -41,9 +41,20 @@
    - From {{ conversation.from_user.username }} - to {{ conversation.to_user.username }} - on {{ conversation.last_message.date_created|format_date("%d %B %Y - %H:%M") }} + {% trans %}From{% endtrans %} + {% if conversation.from_user %} + {{ conversation.from_user.username }} + {% else %} + {% trans %}Deleted User{% endtrans %} + {% endif %} + + {% trans %}to{% endtrans %} + {% if conversation.to_user %} + {{ conversation.to_user.username }} + {% else %} + {% trans %}Deleted User{% endtrans %} + {% endif %} + {% trans %}on{% endtrans %} {{ conversation.last_message.date_created|format_date("%d %B %Y - %H:%M") }}
    diff --git a/flaskbb/user/models.py b/flaskbb/user/models.py index 02ccc41ca..36bdbb4b9 100644 --- a/flaskbb/user/models.py +++ b/flaskbb/user/models.py @@ -18,8 +18,7 @@ from flaskbb.utils.helpers import time_utcnow from flaskbb.utils.settings import flaskbb_config from flaskbb.utils.database import CRUDMixin, UTCDateTime, make_comparable -from flaskbb.forum.models import (Post, Topic, Forum, topictracker, TopicsRead, - ForumsRead) +from flaskbb.forum.models import Post, Topic, Forum, topictracker from flaskbb.message.models import Conversation, Message @@ -117,32 +116,57 @@ class User(db.Model, UserMixin, CRUDMixin): theme = db.Column(db.String(15), nullable=True) language = db.Column(db.String(15), default="en", nullable=True) - posts = db.relationship("Post", backref="user", lazy="dynamic", - primaryjoin="User.id == Post.user_id") - topics = db.relationship("Topic", backref="user", lazy="dynamic", - primaryjoin="User.id == Topic.user_id") - post_count = db.Column(db.Integer, default=0) primary_group_id = db.Column(db.Integer, db.ForeignKey('groups.id'), nullable=False) - primary_group = db.relationship('Group', lazy="joined", - backref="user_group", uselist=False, - foreign_keys=[primary_group_id]) - - secondary_groups = \ - db.relationship('Group', - secondary=groups_users, - primaryjoin=(groups_users.c.user_id == id), - backref=db.backref('users', lazy='dynamic'), - lazy='dynamic') - - tracked_topics = \ - db.relationship("Topic", secondary=topictracker, - primaryjoin=(topictracker.c.user_id == id), - backref=db.backref("topicstracked", lazy="dynamic"), - lazy="dynamic") + posts = db.relationship( + "Post", + backref="user", + primaryjoin="User.id == Post.user_id", + lazy="dynamic" + ) + + topics = db.relationship( + "Topic", + backref="user", + primaryjoin="User.id == Topic.user_id", + lazy="dynamic" + ) + + primary_group = db.relationship( + "Group", + backref="user_group", + uselist=False, + lazy="joined", + foreign_keys=[primary_group_id] + ) + + secondary_groups = db.relationship( + "Group", + secondary=groups_users, + primaryjoin=(groups_users.c.user_id == id), + backref=db.backref("users", lazy="dynamic"), + lazy="dynamic" + ) + + tracked_topics = db.relationship( + "Topic", + secondary=topictracker, + primaryjoin=(topictracker.c.user_id == id), + backref=db.backref("topicstracked", lazy="dynamic"), + lazy="dynamic", + cascade="all, delete-orphan", + single_parent=True + ) + + conversations = db.relationship( + "Conversation", + primaryjoin="Conversation.user_id == User.id", + lazy="dynamic", + passive_deletes="all" # let the dbms handle the foreignkeys + ) # Properties @property @@ -483,15 +507,6 @@ def save(self, groups=None): def delete(self): """Deletes the User.""" - - # This should actually be handeld by the dbms.. but dunno why it doesnt - # work here - #from flaskbb.forum.models import Forum - #last_post_forums = Forum.query.\ - # filter_by(last_post_user_id=self.id).all() - #for forum in last_post_forums: - # forum.last_post_user_id = None - # forum.save() db.session.delete(self) db.session.commit() diff --git a/migrations/201802021027_af3f5579c84d_add_cascades.py b/migrations/201802021027_af3f5579c84d_add_cascades.py index b8dfb1da5..d276ced71 100644 --- a/migrations/201802021027_af3f5579c84d_add_cascades.py +++ b/migrations/201802021027_af3f5579c84d_add_cascades.py @@ -10,6 +10,8 @@ from alembic import op import sqlalchemy as sa +import flaskbb + logger = logging.getLogger("alembic.runtime.migration") # revision identifiers, used by Alembic. @@ -32,10 +34,18 @@ def upgrade(): if con.engine.dialect.name == "mysql": # user_id batch_op.drop_constraint("conversations_ibfk_3", type_='foreignkey') + # TODO: setup mysqldb and check + batch_op.drop_constraint("conversations_ibfk_2", type_='foreignkey') + batch_op.drop_constraint("conversations_ibfk_1", type_='foreignkey') elif con.engine.dialect.name == "postgresql": + batch_op.drop_constraint('conversations_to_user_id_fkey', type_='foreignkey') + batch_op.drop_constraint('conversations_from_user_id_fkey', type_='foreignkey') batch_op.drop_constraint('conversations_user_id_fkey', type_='foreignkey') batch_op.create_foreign_key(batch_op.f('fk_conversations_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_conversations_from_user_id_users'), 'users', ['from_user_id'], ['id'], ondelete='SET NULL') + batch_op.create_foreign_key(batch_op.f('fk_conversations_to_user_id_users'), 'users', ['to_user_id'], ['id'], ondelete='SET NULL') + with op.batch_alter_table('forumgroups', schema=None) as batch_op: if con.engine.dialect.name == "sqlite": @@ -97,8 +107,10 @@ def upgrade(): batch_op.drop_constraint('messages_conversation_id_fkey', type_='foreignkey') batch_op.drop_constraint('messages_user_id_fkey', type_='foreignkey') + batch_op.alter_column('user_id', existing_type=flaskbb.utils.database.UTCDateTime(timezone=True), nullable=True) + batch_op.create_foreign_key(batch_op.f('fk_messages_conversation_id_conversations'), 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE') - batch_op.create_foreign_key(batch_op.f('fk_messages_user_id_users'), 'users', ['user_id'], ['id'], ondelete='CASCADE') + batch_op.create_foreign_key(batch_op.f('fk_messages_user_id_users'), 'users', ['user_id'], ['id'], ondelete='SET NULL') with op.batch_alter_table('moderators', schema=None) as batch_op: if con.engine.dialect.name == "sqlite": @@ -202,6 +214,9 @@ def downgrade(): with op.batch_alter_table('messages', schema=None) as batch_op: batch_op.drop_constraint(batch_op.f('fk_messages_user_id_users'), type_='foreignkey') batch_op.drop_constraint(batch_op.f('fk_messages_conversation_id_conversations'), type_='foreignkey') + + batch_op.alter_column('user_id', existing_type=flaskbb.utils.database.UTCDateTime(timezone=True), nullable=False) + batch_op.create_foreign_key('fk_messages_user_id_users', 'users', ['user_id'], ['id']) batch_op.create_foreign_key('fk_messages_conversation_id_conversations', 'conversations', ['conversation_id'], ['id']) From 44ea4c7eb15fadc2764ae535f83b69edbd205feb Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 9 Feb 2018 21:53:26 +0100 Subject: [PATCH 8/9] Fix mysql migration --- docs/installation.rst | 10 ++++++---- migrations/201802021027_af3f5579c84d_add_cascades.py | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index ab8653032..e64ebf83c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -244,12 +244,14 @@ Installation ------------ **MySQL users:** Make sure that you create the database using the -``utf8mb4`` charset:: +``utf8`` charset:: - CREATE DATABASE flaskbb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + CREATE DATABASE flaskbb CHARACTER SET utf8; -See `this `_ SO answer for more -information. +Even though the ``utf8mb4`` charset is prefered today +(see `this `_ SO answer), we have to +create our database using the ``utf8`` charset. A good explanation about this +issue can be found `here `_. For a guided install, run:: diff --git a/migrations/201802021027_af3f5579c84d_add_cascades.py b/migrations/201802021027_af3f5579c84d_add_cascades.py index d276ced71..a85d7bec7 100644 --- a/migrations/201802021027_af3f5579c84d_add_cascades.py +++ b/migrations/201802021027_af3f5579c84d_add_cascades.py @@ -34,8 +34,9 @@ def upgrade(): if con.engine.dialect.name == "mysql": # user_id batch_op.drop_constraint("conversations_ibfk_3", type_='foreignkey') - # TODO: setup mysqldb and check + # to_user_id batch_op.drop_constraint("conversations_ibfk_2", type_='foreignkey') + # from_user_id batch_op.drop_constraint("conversations_ibfk_1", type_='foreignkey') elif con.engine.dialect.name == "postgresql": batch_op.drop_constraint('conversations_to_user_id_fkey', type_='foreignkey') @@ -98,6 +99,10 @@ def upgrade(): batch_op.create_foreign_key(batch_op.f('fk_groups_users_group_id_groups'), 'groups', ['group_id'], ['id'], ondelete='CASCADE') with op.batch_alter_table('messages', schema=None) as batch_op: + batch_op.alter_column('user_id', + existing_type=sa.INTEGER(), + nullable=True) + if con.engine.dialect.name == "mysql": # conversation_id batch_op.drop_constraint("messages_ibfk_1", type_='foreignkey') @@ -107,8 +112,6 @@ def upgrade(): batch_op.drop_constraint('messages_conversation_id_fkey', type_='foreignkey') batch_op.drop_constraint('messages_user_id_fkey', type_='foreignkey') - batch_op.alter_column('user_id', existing_type=flaskbb.utils.database.UTCDateTime(timezone=True), nullable=True) - batch_op.create_foreign_key(batch_op.f('fk_messages_conversation_id_conversations'), 'conversations', ['conversation_id'], ['id'], ondelete='CASCADE') batch_op.create_foreign_key(batch_op.f('fk_messages_user_id_users'), 'users', ['user_id'], ['id'], ondelete='SET NULL') From f9cddcbf98202c6bd5fe10686d0741eadfb1da7e Mon Sep 17 00:00:00 2001 From: Peter Justin Date: Fri, 9 Feb 2018 22:36:51 +0100 Subject: [PATCH 9/9] Fix tests --- tests/endtoend/test_message_views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/endtoend/test_message_views.py b/tests/endtoend/test_message_views.py index 686d5da2b..82b95e939 100644 --- a/tests/endtoend/test_message_views.py +++ b/tests/endtoend/test_message_views.py @@ -2,7 +2,7 @@ from werkzeug import exceptions from flask_login import login_user -from flaskbb.message import views +from flaskbb.message import views, models def test_message_not_logged_in(application): @@ -18,7 +18,8 @@ def test_message_inbox(application, default_settings, conversation_msgs, user): with application.test_request_context(): login_user(user) resp = view.get() - assert 'From test_normal' in resp + assert '' in resp + assert 'test_normal' in resp def test_message_view_conversation(