Browse Source

Only delete the conversations from the user who gets deleted

Peter Justin 7 years ago
parent
commit
a55e6f71b2

+ 6 - 4
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)

+ 7 - 2
flaskbb/templates/layout.html

@@ -97,13 +97,18 @@
                                     <li>
                                         <a href="{{ url_for('message.view_conversation', conversation_id=message.id) }}">
                                             <div>
-                                                <span class="author-name">{{ message.from_user.username }}</span> <span class="pull-right text-muted">{{ message.last_message.date_created|time_since }}</span>
+                                                {% if message.from_user %}
+                                                    <span class="author-name">{{ message.from_user.username }}</span>
+                                                {% else %}
+                                                    {% trans %}Deleted User{% endtrans %}
+                                                {% endif %}
+                                                <span class="pull-right text-muted">{{ message.last_message.date_created|time_since }}</span>
                                                 <div class="message-subject">{{ message.subject }}</div>
                                             </div>
                                         </a>
                                     </li>
                                     {% else %}
-                                    <li><a href="#">No unread messages.</a></li>
+                                    <li><a href="#">{% trans %}No unread messages.{% endtrans %}</a></li>
                                     {% endfor %}
                                     <li class="divider"></li>
                                     <li><a href="{{ url_for('message.inbox') }}"><span class="fa fa-envelope fa-fw"></span> {% trans %}Inbox{% endtrans %}</a></li>

+ 2 - 2
flaskbb/templates/message/conversation.html

@@ -98,7 +98,7 @@
                         {% endif %}
 
                         {% else %}
-                        <div class="author-name"><h4>{% trans %}Deleted{% endtrans %}</h4></div>
+                        <div class="author-name"><h4>{% trans %}Deleted User{% endtrans %}</h4></div>
                         <div class="author-title"><h5>{% trans %}Guest{% endtrans %}</h5></div>
                         {% endif %}
                     </div>
@@ -110,7 +110,7 @@
     </div>
 </div>
 
-{% 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 class="form" action="#" method="post">
     {{ form.hidden_tag() }}

+ 15 - 4
flaskbb/templates/message/conversation_list.html

@@ -18,7 +18,7 @@
         <div class="row conversation-row hover {% if conversation.unread %}unread{% endif %}">
             <!-- avatar -->
             <div class="col-md-1 col-sm-2 col-xs-2 conversation-avatar">
-                {% if conversation.from_user.avatar %}
+                {% if conversation.from_user and conversation.from_user.avatar %}
                 <img src="{{ conversation.from_user.avatar }}" class="img-circle" alt="avatar" width="65px" height="65px" />
                 {% else %}
                 <img src="{{ url_for('static', filename='img/avatar80x80.png') }}" class="img-circle" alt="avatar" width="65px" height="65px" />
@@ -41,9 +41,20 @@
                 </div>
                 <!-- meta info (date, user) -->
                 <div class="conversation-meta">
-                    From <a href="{{ conversation.from_user.url }}">{{ conversation.from_user.username }}</a>
-                    to <a href="{{ conversation.to_user.url }}">{{ conversation.to_user.username }}</a>
-                    on {{ conversation.last_message.date_created|format_date("%d %B %Y - %H:%M") }}
+                    {% trans %}From{% endtrans %}
+                    {% if conversation.from_user %}
+                        <a href="{{ conversation.from_user.url }}">{{ conversation.from_user.username }}</a>
+                    {% else %}
+                        {% trans %}Deleted User{% endtrans %}
+                    {% endif %}
+
+                    {% trans %}to{% endtrans %}
+                    {% if conversation.to_user %}
+                        <a href="{{ conversation.to_user.url }}">{{ conversation.to_user.username }}</a>
+                    {% else %}
+                        {% trans %}Deleted User{% endtrans %}
+                    {% endif %}
+                    {% trans %}on{% endtrans %} {{ conversation.last_message.date_created|format_date("%d %B %Y - %H:%M") }}
                 </div>
                 <!-- actual content -->
                 <div class="conversation-content">

+ 47 - 32
flaskbb/user/models.py

@@ -18,8 +18,7 @@ from flaskbb.exceptions import AuthenticationError
 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 @@ class User(db.Model, UserMixin, CRUDMixin):
 
     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()
 

+ 16 - 1
migrations/201802021027_af3f5579c84d_add_cascades.py

@@ -10,6 +10,8 @@ import logging
 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'])