Browse Source

Move conversations related things into a plugin

Peter Justin 7 years ago
parent
commit
aac93661f3

+ 1 - 0
.gitignore

@@ -139,3 +139,4 @@ whoosh_index
 .sass-cache
 .sass-cache
 bower_components
 bower_components
 node_modules
 node_modules
+.DS_Store

+ 2 - 0
docs/hooks.rst

@@ -65,6 +65,8 @@ Template Hooks
 
 
 .. autofunction:: flaskbb_tpl_before_navigation
 .. autofunction:: flaskbb_tpl_before_navigation
 .. autofunction:: flaskbb_tpl_after_navigation
 .. autofunction:: flaskbb_tpl_after_navigation
+.. autofunction:: flaskbb_tpl_before_user_nav_loggedin
+.. autofunction:: flaskbb_tpl_after_user_nav_loggedin
 .. autofunction:: flaskbb_tpl_before_registration_form
 .. autofunction:: flaskbb_tpl_before_registration_form
 .. autofunction:: flaskbb_tpl_after_registration_form
 .. autofunction:: flaskbb_tpl_after_registration_form
 .. autofunction:: flaskbb_tpl_before_user_details_form
 .. autofunction:: flaskbb_tpl_before_user_details_form

+ 0 - 3
flaskbb/message/__init__.py

@@ -1,3 +0,0 @@
-import logging
-
-logger = logging.getLogger(__name__)

+ 0 - 79
flaskbb/message/forms.py

@@ -1,79 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.message.forms
-    ~~~~~~~~~~~~~~~~~~~~~
-
-    It provides the forms that are needed for the message views.
-
-    :copyright: (c) 2014 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-import logging
-from flask_login import current_user
-from flask_wtf import FlaskForm
-from wtforms import StringField, TextAreaField, ValidationError, SubmitField
-from wtforms.validators import DataRequired
-from flask_babelplus import lazy_gettext as _
-
-from flaskbb.user.models import User
-from flaskbb.message.models import Conversation, Message
-
-
-logger = logging.getLogger(__name__)
-
-
-class ConversationForm(FlaskForm):
-    to_user = StringField(_("Recipient"), validators=[
-        DataRequired(message=_("A valid username is required."))])
-
-    subject = StringField(_("Subject"), validators=[
-        DataRequired(message=_("A Subject is required."))])
-
-    message = TextAreaField(_("Message"), validators=[
-        DataRequired(message=_("A message is required."))])
-
-    send_message = SubmitField(_("Start Conversation"))
-    save_message = SubmitField(_("Save Conversation"))
-
-    def validate_to_user(self, field):
-        user = User.query.filter_by(username=field.data).first()
-        if not user:
-            raise ValidationError(_("The username you entered does not "
-                                    "exist."))
-        if user.id == current_user.id:
-            raise ValidationError(_("You cannot send a PM to yourself."))
-
-    def save(self, from_user, to_user, user_id, unread, as_draft=False,
-             shared_id=None):
-
-        conversation = Conversation(
-            subject=self.subject.data,
-            draft=as_draft,
-            shared_id=shared_id,
-            from_user_id=from_user,
-            to_user_id=to_user,
-            user_id=user_id,
-            unread=unread
-        )
-        message = Message(message=self.message.data, user_id=from_user)
-        return conversation.save(message=message)
-
-
-class MessageForm(FlaskForm):
-    message = TextAreaField(_("Message"), validators=[
-        DataRequired(message=_("A message is required."))])
-    submit = SubmitField(_("Send Message"))
-
-    def save(self, conversation, user_id, unread=False):
-        """Saves the form data to the model.
-        :param conversation: The Conversation object.
-        :param user_id: The id from the user who sent the message.
-        :param reciever: If the message should also be stored in the recievers
-                         inbox.
-        """
-        message = Message(message=self.message.data, user_id=user_id)
-
-        if unread:
-            conversation.unread = True
-            conversation.save()
-        return message.save(conversation)

+ 0 - 123
flaskbb/message/models.py

@@ -1,123 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.message.models
-    ~~~~~~~~~~~~~~~~~~~~~~
-
-    The models for the conversations and messages are located here.
-
-    :copyright: (c) 2014 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-import logging
-from sqlalchemy_utils import UUIDType
-
-from flaskbb.extensions import db
-from flaskbb.utils.helpers import time_utcnow
-from flaskbb.utils.database import CRUDMixin, UTCDateTime
-
-
-logger = logging.getLogger(__name__)
-
-
-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", ondelete="CASCADE"),
-                        nullable=False)
-    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",
-                                                     ondelete="SET NULL"),
-                           nullable=True)
-    shared_id = db.Column(UUIDType, nullable=False)
-    subject = db.Column(db.String(255), nullable=True)
-    date_created = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
-                             nullable=False)
-    date_modified = db.Column(UTCDateTime(timezone=True), default=time_utcnow,
-                              nullable=False)
-    trash = db.Column(db.Boolean, default=False, nullable=False)
-    draft = db.Column(db.Boolean, default=False, nullable=False)
-    unread = db.Column(db.Boolean, default=False, nullable=False)
-
-    messages = db.relationship(
-        "Message", lazy="joined", backref="conversation",
-        primaryjoin="Message.conversation_id == Conversation.id",
-        order_by="asc(Message.id)", cascade="all, delete-orphan"
-    )
-
-    # this is actually the users message box
-    user = db.relationship("User", lazy="joined", foreign_keys=[user_id])
-    # the user to whom the conversation is addressed
-    to_user = db.relationship("User", lazy="joined", foreign_keys=[to_user_id])
-    # the user who sent the message
-    from_user = db.relationship("User", lazy="joined",
-                                foreign_keys=[from_user_id])
-
-    @property
-    def first_message(self):
-        """Returns the first message object."""
-        return self.messages[0]
-
-    @property
-    def last_message(self):
-        """Returns the last message object."""
-        return self.messages[-1]
-
-    def save(self, message=None):
-        """Saves a conversation and returns the saved conversation object.
-
-        :param message: If given, it will also save the message for the
-                        conversation. It expects a Message object.
-        """
-        if message is not None:
-            # create the conversation
-            self.date_created = time_utcnow()
-            db.session.add(self)
-            db.session.commit()
-
-            # create the actual message for the conversation
-            message.save(self)
-            return self
-
-        self.date_modified = time_utcnow()
-        db.session.add(self)
-        db.session.commit()
-        return self
-
-
-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",
-                                              ondelete="CASCADE"),
-                                nullable=False)
-
-    # the user who wrote the message
-    user_id = db.Column(db.Integer,
-                        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)
-
-    user = db.relationship("User", lazy="joined")
-
-    def save(self, conversation=None):
-        """Saves a private message.
-
-        :param conversation: The  conversation to which the message
-                             belongs to.
-        """
-        if conversation is not None:
-            self.conversation = conversation
-            conversation.date_modified = time_utcnow()
-            self.date_created = time_utcnow()
-
-        db.session.add(self)
-        db.session.commit()
-        return self

+ 0 - 428
flaskbb/message/views.py

@@ -1,428 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.message.views
-    ~~~~~~~~~~~~~~~~~~~~~
-
-    The views for the conversations and messages are located in this module.
-
-    :copyright: (c) 2014 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-import logging
-import uuid
-from functools import wraps
-
-from flask import Blueprint, abort, flash, redirect, request, url_for
-from flask.views import MethodView
-from flask_babelplus import gettext as _
-from flask_login import current_user, login_required
-
-from flaskbb.extensions import db
-from flaskbb.message.forms import ConversationForm, MessageForm
-from flaskbb.message.models import Conversation, Message
-from flaskbb.user.models import User
-from flaskbb.utils.helpers import (format_quote, real, register_view,
-                                   render_template, time_utcnow)
-from flaskbb.utils.settings import flaskbb_config
-
-logger = logging.getLogger(__name__)
-
-message = Blueprint("message", __name__)
-
-
-def check_message_box_space(redirect_to=None):
-    """Checks the message quota has been exceeded. If thats the case
-    it flashes a message and redirects back to some endpoint.
-
-    :param redirect_to: The endpoint to redirect to. If set to ``None`` it
-                        will redirect to the ``message.inbox`` endpoint.
-    """
-    if current_user.message_count >= flaskbb_config["MESSAGE_QUOTA"]:
-        flash(
-            _(
-                "You cannot send any messages anymore because you have "
-                "reached your message limit."
-            ), "danger"
-        )
-        return redirect(redirect_to or url_for("message.inbox"))
-
-
-def require_message_box_space(f):
-    """Decorator for :func:`check_message_box_space`."""
-    # not sure how this can be done without explicitly providing a decorator
-    # for this
-    @wraps(f)
-    def wrapper(*a, **k):
-        return check_message_box_space() or f(*a, **k)
-
-    return wrapper
-
-
-class Inbox(MethodView):
-    decorators = [login_required]
-
-    def get(self):
-        page = request.args.get('page', 1, type=int)
-        # the inbox will display both, the recieved and the sent messages
-        conversations = Conversation.query.filter(
-            Conversation.user_id == current_user.id,
-            Conversation.draft == False,
-            Conversation.trash == False,
-        ).order_by(Conversation.date_modified.desc()).paginate(
-            page, flaskbb_config['TOPICS_PER_PAGE'], False
-        )
-
-        return render_template("message/inbox.html",
-                               conversations=conversations)
-
-
-class ViewConversation(MethodView):
-    decorators = [login_required]
-    form = MessageForm
-
-    def get(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        if conversation.unread:
-            conversation.unread = False
-            current_user.invalidate_cache(permissions=False)
-            conversation.save()
-
-        form = self.form()
-        return render_template("message/conversation.html",
-                               conversation=conversation, form=form)
-
-    @require_message_box_space
-    def post(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        form = self.form()
-        if form.validate_on_submit():
-            to_user_id = None
-            # If the current_user is the user who recieved the message
-            # then we have to change the id's a bit.
-            if current_user.id == conversation.to_user_id:
-                to_user_id = conversation.from_user_id
-                to_user = conversation.from_user
-            else:
-                to_user_id = conversation.to_user_id
-                to_user = conversation.to_user
-
-            form.save(conversation=conversation, user_id=current_user.id)
-
-            # save the message in the recievers conversation
-            old_conv = conversation
-            conversation = Conversation.query.filter(
-                Conversation.user_id == to_user_id,
-                Conversation.shared_id == conversation.shared_id
-            ).first()
-
-            # user deleted the conversation, start a new conversation with just
-            # the recieving message
-            if conversation is None:
-                conversation = Conversation(
-                    subject=old_conv.subject,
-                    from_user=real(current_user),
-                    to_user=to_user,
-                    user_id=to_user_id,
-                    shared_id=old_conv.shared_id
-                )
-                conversation.save()
-
-            form.save(conversation=conversation, user_id=current_user.id, unread=True)
-            conversation.to_user.invalidate_cache(permissions=False)
-
-            return redirect(url_for("message.view_conversation", conversation_id=old_conv.id))
-
-        return render_template("message/conversation.html", conversation=conversation, form=form)
-
-
-class NewConversation(MethodView):
-    decorators = [login_required]
-    form = ConversationForm
-
-    def get(self):
-        form = self.form()
-        form.to_user.data = request.args.get("to_user")
-        return render_template("message/message_form.html", form=form, title=_("Compose Message"))
-
-    def post(self):
-        form = self.form()
-        if "save_message" in request.form and form.validate():
-            to_user = User.query.filter_by(username=form.to_user.data).first()
-
-            shared_id = uuid.uuid4()
-
-            form.save(
-                from_user=current_user.id,
-                to_user=to_user.id,
-                user_id=current_user.id,
-                unread=False,
-                as_draft=True,
-                shared_id=shared_id
-            )
-
-            flash(_("Message saved."), "success")
-            return redirect(url_for("message.drafts"))
-
-        if "send_message" in request.form and form.validate():
-            check_message_box_space()
-
-            to_user = User.query.filter_by(username=form.to_user.data).first()
-
-            # this is the shared id between conversations because the messages
-            # are saved on both ends
-            shared_id = uuid.uuid4()
-
-            # Save the message in the current users inbox
-            form.save(
-                from_user=current_user.id,
-                to_user=to_user.id,
-                user_id=current_user.id,
-                unread=False,
-                shared_id=shared_id
-            )
-
-            # Save the message in the recievers inbox
-            form.save(
-                from_user=current_user.id,
-                to_user=to_user.id,
-                user_id=to_user.id,
-                unread=True,
-                shared_id=shared_id
-            )
-            to_user.invalidate_cache(permissions=False)
-
-            flash(_("Message sent."), "success")
-            return redirect(url_for("message.sent"))
-
-        return render_template("message/message_form.html", form=form, title=_("Compose Message"))
-
-
-class EditConversation(MethodView):
-    decorators = [login_required]
-    form = ConversationForm
-
-    def get(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        if not conversation.draft:
-            flash(_("You cannot edit a sent message."), "danger")
-            return redirect(url_for("message.inbox"))
-
-        form = self.form()
-        form.to_user.data = conversation.to_user.username
-        form.subject.data = conversation.subject
-        form.message.data = conversation.first_message.message
-
-        return render_template("message/message_form.html", form=form, title=_("Edit Message"))
-
-    def post(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        if not conversation.draft:
-            flash(_("You cannot edit a sent message."), "danger")
-            return redirect(url_for("message.inbox"))
-
-        form = self.form()
-
-        if request.method == "POST":
-            if "save_message" in request.form:
-                to_user = User.query.filter_by(username=form.to_user.data).first()
-
-                conversation.draft = True
-                conversation.to_user_id = to_user.id
-                conversation.first_message.message = form.message.data
-                conversation.save()
-
-                flash(_("Message saved."), "success")
-                return redirect(url_for("message.drafts"))
-
-            if "send_message" in request.form and form.validate():
-                check_message_box_space()
-
-                to_user = User.query.filter_by(username=form.to_user.data).first()
-                # Save the message in the recievers inbox
-                form.save(
-                    from_user=current_user.id,
-                    to_user=to_user.id,
-                    user_id=to_user.id,
-                    unread=True,
-                    shared_id=conversation.shared_id
-                )
-
-                # Move the message from ``Drafts`` to ``Sent``.
-                conversation.draft = False
-                conversation.to_user = to_user
-                conversation.date_created = time_utcnow()
-                conversation.save()
-
-                flash(_("Message sent."), "success")
-                return redirect(url_for("message.sent"))
-        else:
-            form.to_user.data = conversation.to_user.username
-            form.subject.data = conversation.subject
-            form.message.data = conversation.first_message.message
-
-        return render_template("message/message_form.html", form=form, title=_("Edit Message"))
-
-
-class RawMessage(MethodView):
-    decorators = [login_required]
-
-    def get(self, message_id):
-
-        message = Message.query.filter_by(id=message_id).first_or_404()
-
-        # abort if the message was not the current_user's one or the one of the
-        # recieved ones
-        if not (message.conversation.from_user_id == current_user.id
-                or message.conversation.to_user_id == current_user.id):
-            abort(404)
-
-        return format_quote(username=message.user.username, content=message.message)
-
-
-class MoveConversation(MethodView):
-    decorators = [login_required]
-
-    def post(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        conversation.trash = True
-        conversation.save()
-
-        return redirect(url_for("message.inbox"))
-
-
-class RestoreConversation(MethodView):
-    decorators = [login_required]
-
-    def post(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        conversation.trash = False
-        conversation.save()
-        return redirect(url_for("message.trash"))
-
-
-class DeleteConversation(MethodView):
-    decorators = [login_required]
-
-    def post(self, conversation_id):
-        conversation = Conversation.query.filter_by(
-            id=conversation_id, user_id=current_user.id
-        ).first_or_404()
-
-        conversation.delete()
-        return redirect(url_for("message.trash"))
-
-
-class SentMessages(MethodView):
-    decorators = [login_required]
-
-    def get(self):
-
-        page = request.args.get('page', 1, type=int)
-
-        conversations = Conversation.query. \
-            filter(
-                Conversation.user_id == current_user.id,
-                Conversation.draft == False,
-                Conversation.trash == False,
-                db.not_(Conversation.to_user_id == current_user.id)
-            ).\
-            order_by(Conversation.date_modified.desc()). \
-            paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
-
-        return render_template(
-            "message/sent.html", conversations=conversations
-        )
-
-
-class DraftMessages(MethodView):
-    decorators = [login_required]
-
-    def get(self):
-
-        page = request.args.get('page', 1, type=int)
-
-        conversations = Conversation.query. \
-            filter(
-                Conversation.user_id == current_user.id,
-                Conversation.draft == True,
-                Conversation.trash == False
-            ).\
-            order_by(Conversation.date_modified.desc()). \
-            paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
-
-        return render_template(
-            "message/drafts.html", conversations=conversations
-        )
-
-
-class TrashedMessages(MethodView):
-    decorators = [login_required]
-
-    def get(self):
-
-        page = request.args.get('page', 1, type=int)
-
-        conversations = Conversation.query. \
-            filter(
-                Conversation.user_id == current_user.id,
-                Conversation.trash == True,
-            ).\
-            order_by(Conversation.date_modified.desc()). \
-            paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
-
-        return render_template(
-            "message/trash.html", conversations=conversations
-        )
-
-
-register_view(message, routes=['/drafts'], view_func=DraftMessages.as_view('drafts'))
-register_view(message, routes=['/', '/inbox'], view_func=Inbox.as_view('inbox'))
-register_view(
-    message,
-    routes=['/<int:conversation_id>/delete'],
-    view_func=DeleteConversation.as_view('delete_conversation')
-)
-register_view(
-    message,
-    routes=["/<int:conversation_id>/edit"],
-    view_func=EditConversation.as_view('edit_conversation')
-)
-register_view(
-    message,
-    routes=['/<int:conversation_id>/move'],
-    view_func=MoveConversation.as_view('move_conversation')
-)
-register_view(
-    message,
-    routes=['/<int:conversation_id>/restore'],
-    view_func=RestoreConversation.as_view('restore_conversation')
-)
-register_view(
-    message,
-    routes=["/<int:conversation_id>/view"],
-    view_func=ViewConversation.as_view('view_conversation')
-)
-register_view(
-    message, routes=['/message/<int:message_id>/raw'], view_func=RawMessage.as_view('raw_message')
-)
-register_view(message, routes=["/new"], view_func=NewConversation.as_view('new_conversation'))
-register_view(message, routes=['/sent'], view_func=SentMessages.as_view('sent'))
-register_view(message, routes=['/trash'], view_func=TrashedMessages.as_view('trash'))

+ 18 - 0
flaskbb/plugins/spec.py

@@ -82,6 +82,24 @@ def flaskbb_tpl_after_navigation():
 
 
 
 
 @spec
 @spec
+def flaskbb_tpl_before_user_nav_loggedin():
+    """Hook for registering additional user navigational items
+    which are only shown when a user is logged in.
+
+    in :file:`templates/layout.html`.
+    """
+
+
+@spec
+def flaskbb_tpl_after_user_nav_loggedin():
+    """Hook for registering additional user navigational items
+    which are only shown when a user is logged in.
+
+    in :file:`templates/layout.html`.
+    """
+
+
+@spec
 def flaskbb_tpl_before_registration_form():
 def flaskbb_tpl_before_registration_form():
     """This hook is emitted in the Registration form **before** the first
     """This hook is emitted in the Registration form **before** the first
     input field but after the hidden CSRF token field.
     input field but after the hidden CSRF token field.

+ 5 - 34
flaskbb/templates/layout.html

@@ -80,41 +80,9 @@
 
 
                         <!-- navbar right -->
                         <!-- navbar right -->
                         <ul class="nav navbar-nav navbar-right">
                         <ul class="nav navbar-nav navbar-right">
-
                             {% if current_user and current_user.is_authenticated %}
                             {% if current_user and current_user.is_authenticated %}
-                            <!-- Inbox -->
-                            <li class="dropdown {{ is_active('message.inbox') }}">
-                                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
-                                    <span class="fa fa-envelope fa-fw"></span> {% trans %}Inbox{% endtrans %}
-                                    {% if current_user.unread_count > 0 %}
-                                    <span class="label label-danger">{{ current_user.unread_count }}</span>
-                                    {% else %}
-                                    <span class="label label-info">{{ current_user.unread_count }}</span>
-                                    {% endif %}
-                                </a>
-                                <ul class="dropdown-menu dropdown-messages">
-                                    {% for message in current_user.unread_messages %}
-                                    <li>
-                                        <a href="{{ url_for('message.view_conversation', conversation_id=message.id) }}">
-                                            <div>
-                                                {% 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="#">{% 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>
-                                    <li><a href="{{ url_for('message.new_conversation') }}"><span class="fa fa-pencil fa-fw"></span> {% trans %}New Message{% endtrans %}</a></li>
-                                </ul>
-                            </li>
+
+                            {{ run_hook("flaskbb_tpl_before_user_nav_loggedin") }}
 
 
                             <!-- User Menu -->
                             <!-- User Menu -->
                             <li>
                             <li>
@@ -137,6 +105,9 @@
                                     </ul>
                                     </ul>
                                 </div>
                                 </div>
                             </li>
                             </li>
+
+                            {{ run_hook("flaskbb_tpl_after_user_nav_loggedin") }}
+
                             {% else %}
                             {% else %}
                             <!-- Not logged in - Login/Register -->
                             <!-- Not logged in - Login/Register -->
                             <li>
                             <li>

+ 0 - 133
flaskbb/templates/message/conversation.html

@@ -1,133 +0,0 @@
-{% extends theme("message/message_layout.html") %}
-
-{% block message_content %}
-{# quick check if the conversation is a draft #}
-{% if conversation.draft %}
-    {% set messages = [conversation.first_message] %}
-{% else %}
-    {% set messages = conversation.messages %}
-{% endif %}
-
-<div class="panel conversation-panel">
-    <div class="panel-heading conversation-head">
-        Subject: <strong>{{ conversation.subject }}</strong>
-    </div>
-
-    <div class="panel-body conversation-body">
-        <div class="conversation-box">
-            {% for message in messages %}
-            <!-- First Comment -->
-            <div class="row conversation-row" id="mid{{message.id}}">
-                {% if current_user.id == message.user_id %}
-                <div class="col-md-2 col-sm-3 col-xs-12">
-                    <div class="conversation-author author">
-                        <!-- Registered User -->
-                        <div class="author-name"><h4><a href="{{ message.user.url }}">{{ message.user.username }}</a></h4></div>
-
-                        <!-- check if user is online or not -->
-                        {% if message.user|is_online %}
-                        <div class="author-online" data-toggle="tooltip" data-placement="top" title="online"></div>
-                        {% else %}
-                        <div class="author-offline" data-toggle="tooltip" data-placement="top" title="offline"></div>
-                        {% endif %}
-                        <div class="author-title"><h5>{{ message.user.primary_group.name }}</h5></div>
-
-                        {% if message.user.avatar %}
-                            <div class="author-avatar"><img src="{{ message.user.avatar }}" alt="avatar"></div>
-                        {% endif %}
-
-                        <div class="author-registered">{% trans %}Joined{% endtrans %}: {{ message.user.date_joined|format_date('%b %d %Y') }}</div>
-                        <div class="author-posts">{% trans %}Posts{% endtrans %}: {{ message.user.post_count }}</div>
-
-                        {% if message.user.website %}
-                        <div class="author-website"><a href="{{ message.user.website }}" rel="nofollow">{% trans %}Website{% endtrans %}</a></div>
-                        {% endif %}
-                    </div>
-                </div>
-                {% endif %}
-                <div class="col-md-10 col-sm-9 col-xs-12">
-                    <div class="conversation-message arrow {% if current_user.id == message.user_id %}left{% else %}right{% endif %}">
-                        <div class="message-box">
-
-                            <div class="text-left message-header">
-                                <time class="conversation-date" datetime="{{ message.date_created }}"><i class="fa fa-clock-o"></i> {{ message.date_created|format_date("%d %B %Y - %H:%M") }}</time>
-                            </div>
-
-                            <div class="message-content">
-                                {{ message.message|markup }}
-                            </div>
-
-                            <div class="message-footer">
-                            {% if conversation.draft %}
-                                <p class="text-right"><a href="{{ url_for('message.edit_conversation', conversation_id=conversation.id) }}" class="btn btn-default btn-sm"><i class="fa fa-pencil"></i> edit</a></p>
-                            {% else %}
-                                <p class="{% if current_user.id == message.user_id %}left{% else %}right{% endif %}"><a href="#" class="btn btn-default btn-sm reply-btn" data-message-id="{{ message.id }}"><i class="fa fa-reply"></i> reply</a></p>
-                            {% endif %}
-                            </div>
-
-                        </div>
-                    </div>
-                </div>
-                {% if current_user.id != message.user_id %}
-                <div class="col-md-2 col-sm-3 col-xs-12">
-                    <div class="conversation-author author">
-                        {% if message.user_id and message.user %}
-                        <!-- Registered User -->
-                        <div class="author-name"><h4><a href="{{ message.user.url }}">{{ message.user.username }}</a></h4></div>
-
-                        <!-- check if user is online or not -->
-                        {% if message.user|is_online %}
-                        <div class="author-online" data-toggle="tooltip" data-placement="top" title="online"></div>
-                        {% else %}
-                        <div class="author-offline" data-toggle="tooltip" data-placement="top" title="offline"></div>
-                        {% endif %}
-                        <div class="author-title"><h5>{{ message.user.primary_group.name }}</h5></div>
-
-                        {% if message.user.avatar %}
-                            <div class="author-avatar"><img src="{{ message.user.avatar }}" alt="avatar"></div>
-                        {% endif %}
-
-                        <div class="author-registered">{% trans %}Joined{% endtrans %}: {{ message.user.date_joined|format_date('%b %d %Y') }}</div>
-                        <div class="author-posts">{% trans %}Posts{% endtrans %}: {{ message.user.post_count }}</div>
-                        <div class="author-pm">
-                        <a href="{{ url_for('message.new_conversation') }}?to_user={{ message.user.username }}">{% trans %}Message{% endtrans %}</a>
-                        </div>
-
-                        {% if message.user.website %}
-                        <div class="author-website"><a href="{{ message.user.website }}" rel="nofollow">{% trans %}Website{% endtrans %}</a></div>
-                        {% endif %}
-
-                        {% else %}
-                        <div class="author-name"><h4>{% trans %}Deleted User{% endtrans %}</h4></div>
-                        <div class="author-title"><h5>{% trans %}Guest{% endtrans %}</h5></div>
-                        {% endif %}
-                    </div>
-                </div>
-                {% endif %}
-            </div>
-        {% endfor %}
-        </div>
-    </div>
-</div>
-
-{% 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() }}
-    <div class="row conversation-reply">
-        <div class="col-md-12 col-sm-12 col-xs-12">
-            <div class="editor-box">
-                <div class="editor">
-                    {{ render_quickreply(form.message, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
-                </div>
-                <div class="editor-submit">
-                    {{ render_submit_field(form.submit, input_class="btn btn-success pull-right") }}
-                </div>
-            </div>
-        </div>
-    </div>
-    {% include theme('editor_help.html') %}
-</form>
-{% endif %}
-
-{% endblock %}

+ 0 - 108
flaskbb/templates/message/conversation_list.html

@@ -1,108 +0,0 @@
-{% from "macros.html" import generate_obj_id %}
-<div class="panel conversation-panel">
-    <div class="panel-heading conversation-head">
-        <div class="row">
-            <div class="col-md-12 col-sm-12 col-xs-12">
-                <div class="pull-left">
-                    <span class="fa fa-comment"></span> {% trans %}Conversations{% endtrans %}
-                </div>
-
-                <div class="pull-right">
-                    <span class="label label-info" title="The amount of all conversations" data-toggle="tooltip" data-placement="top">{{ current_user.message_count }}/{{ flaskbb_config["MESSAGE_QUOTA"] }}</span>
-                </div>
-            </div>
-        </div>
-    </div>
-    <div class="panel-body conversation-body">
-        {% for conversation in conversations.items %}
-        <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 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" />
-                {% endif %}
-            </div>
-            <!-- other stuff -->
-            <div class="col-md-11 col-sm-10 col-xs-10 conversation-info">
-                <!-- subject -->
-                <div class="conversation-subject">
-                    <a href="{{ url_for('message.view_conversation', conversation_id=conversation.id) }}">
-                        {% if conversation.unread %}
-                            <strong>{{ conversation.subject }}</strong>
-                        {% else %}
-                            {{ conversation.subject }}
-                        {% endif %}
-                    </a>
-                    <div class="pull-right">
-                        <strong><small>#{{ generate_obj_id(conversations, loop.index, flaskbb_config["TOPICS_PER_PAGE"]) }}</small></strong>
-                    </div>
-                </div>
-                <!-- meta info (date, user) -->
-                <div class="conversation-meta">
-                    {% 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">
-                    {{ conversation.last_message.message|crop_title(150)|markup }}
-                </div>
-                <!-- actions -->
-                <div class="conversation-actions">
-                    {% if include_move %}
-                    <form class="inline-form" method="POST" action="{{ url_for('message.move_conversation', conversation_id=conversation.id) }}">
-                        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
-                        <button type="submit" class="btn btn-info btn-xs" title="Move to Trash" data-toggle="tooltip" data-placement="top">
-                            <span class="fa fa-archive"></span>
-                        </button>
-                    </form>
-                    {% endif %}
-
-                    {% if include_delete %}
-                    <form class="inline-form" method="POST" action="{{ url_for('message.delete_conversation', conversation_id=conversation.id) }}">
-                        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
-                        <button type="submit" class="btn btn-danger btn-xs" title="Delete this conversation" data-toggle="tooltip" data-placement="top">
-                            <span class="fa fa-trash"></span>
-                        </button>
-                    </form>
-                    {% endif %}
-
-                    {% if include_restore %}
-                    <form class="inline-form" method="POST" action="{{ url_for('message.restore_conversation', conversation_id=conversation.id) }}">
-                        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
-                        <button type="submit" class="btn btn-success btn-xs" title="Restore this conversation" data-toggle="tooltip" data-placement="top">
-                            <span class="fa fa-undo"></span>
-                        </button>
-                    </form>
-                    {% endif %}
-
-                    {% if include_edit %}
-                    <a class="btn btn-success btn-xs" alt="Edit" title="Edit this conversation" href="{{ url_for('message.edit_conversation', conversation_id = conversation.id) }}" data-toggle="tooltip" data-placement="top">
-                        <span class="fa fa-pencil"></span>
-                    </a>
-                    {% endif %}
-                </div>
-            </div>
-        </div>
-        {% else %}
-        <div class="row conversation-row">
-            <div class="col-md-12 col-sm-12 col-xs-12">
-                {% trans %}No conversations found.{% endtrans %}
-            </div>
-        </div>
-        {% endfor %}
-    </div>
-</div>

+ 0 - 13
flaskbb/templates/message/drafts.html

@@ -1,13 +0,0 @@
-{% set page_title = _("Drafts") %}
-
-{% from theme('macros.html') import render_pagination %}
-{% extends theme("message/message_layout.html") %}
-{% block message_content %}
-
-{% set include_move = True %}
-{% set include_edit = True %}
-{% include theme("message/conversation_list.html") %}
-
-{{ render_pagination(conversations, url_for("message.drafts")) }}
-
-{% endblock %}

+ 0 - 12
flaskbb/templates/message/inbox.html

@@ -1,12 +0,0 @@
-{% set page_title = _("Inbox") %}
-
-{% from theme('macros.html') import render_pagination %}
-{% extends theme("message/message_layout.html") %}
-{% block message_content %}
-
-{% set include_move = True %}
-{% include theme("message/conversation_list.html") %}
-
-{{ render_pagination(conversations, url_for("message.inbox")) }}
-
-{% endblock %}

+ 0 - 41
flaskbb/templates/message/message_form.html

@@ -1,41 +0,0 @@
-{% set page_title = title %}
-
-{% extends theme("message/message_layout.html") %}
-
-{% block message_content %}
-{% from theme("macros.html") import render_submit_field, render_quickreply, render_field %}
-<form class="form-horizontal" role="form" method="post">
-    {{ form.hidden_tag() }}
-    <div class="panel page-panel">
-        <div class="panel-heading page-head">
-            {{ title }}
-        </div>
-
-        <div class="panel-body page-body">
-            {{ form.hidden_tag() }}
-            <div class="col-md-12 col-sm-12 col-xs-12">
-
-                {{ render_field(form.to_user, div_class="col-md-6 col-sm-6 col-xs-6") }}
-                {{ render_field(form.subject, div_class="col-md-6 col-sm-6 col-xs-6") }}
-
-                <div class="form-group">
-                    <div class="col-md-12 col-sm-12 col-xs-12">
-                        <div class="editor-box">
-                            <div class="editor">
-                                {{ render_quickreply(form.message, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
-                            </div>
-                            <div class="editor-submit">
-                                <div class="pull-right">
-                                    {{ render_submit_field(form.send_message, input_class="btn btn-success") }}
-                                    {{ render_submit_field(form.save_message, input_class="btn btn-info") }}
-                                </div>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    {% include theme('editor_help.html') %}
-</form>
-{% endblock %}

+ 0 - 29
flaskbb/templates/message/message_layout.html

@@ -1,29 +0,0 @@
-{% extends theme("layout.html") %}
-{% block content %}
-{%- from theme('macros.html') import navlink with context -%}
-
-<ol class="breadcrumb flaskbb-breadcrumb">
-    <li><a href="{{ url_for('forum.index') }}">{% trans %}Forum{% endtrans %}</a></li>
-    <li><a href="{{ url_for('user.profile', username=current_user.username) }}">{{ current_user.username }}</a></li>
-    <li class="active">{% trans %}Private Message{% endtrans %}</li>
-</ol>
-
-<div class="row">
-    <div class="col-sm-3 col-md-2">
-        <div class="sidebar">
-            <ul class="nav sidenav">
-                <div class="sidenav-btn">
-                    <a href="{{ url_for('message.new_conversation') }}" class="btn btn-success">{% trans %}New Message{% endtrans %}</a>
-                </div>
-                {{ navlink('message.inbox', _('Inbox')) }}
-                {{ navlink('message.sent', _('Sent')) }}
-                {{ navlink('message.drafts', _('Drafts')) }}
-                {{ navlink('message.trash', _('Trash')) }}
-            </ul>
-        </div><!--/.sidebar -->
-    </div><!--/.col-sm-3 -->
-    <div class="col-sm-9 col-md-10">
-        {% block message_content %}{% endblock %}
-    </div><!--/.col-sm-9 -->
-</div><!--/.row -->
-{% endblock %}

+ 0 - 12
flaskbb/templates/message/sent.html

@@ -1,12 +0,0 @@
-{% set page_title = _("Sent Messages") %}
-
-{% from theme('macros.html') import render_pagination %}
-{% extends theme("message/message_layout.html") %}
-{% block message_content %}
-
-{% set include_move = True %}
-{% include theme("message/conversation_list.html") %}
-
-{{ render_pagination(conversations, url_for("message.sent")) }}
-
-{% endblock %}

+ 0 - 13
flaskbb/templates/message/trash.html

@@ -1,13 +0,0 @@
-{% set page_title = _("Trash") %}
-
-{% from theme('macros.html') import render_pagination %}
-{% extends theme("message/message_layout.html") %}
-{% block message_content %}
-
-{% set include_restore = True %}
-{% set include_delete = True %}
-{% include theme("message/conversation_list.html") %}
-
-{{ render_pagination(conversations, url_for("message.trash")) }}
-
-{% endblock %}

+ 4 - 40
flaskbb/user/models.py

@@ -19,7 +19,6 @@ from flaskbb.utils.helpers import time_utcnow
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.database import CRUDMixin, UTCDateTime, make_comparable
 from flaskbb.utils.database import CRUDMixin, UTCDateTime, make_comparable
 from flaskbb.forum.models import Post, Topic, Forum, topictracker
 from flaskbb.forum.models import Post, Topic, Forum, topictracker
-from flaskbb.message.models import Conversation, Message
 
 
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
@@ -205,24 +204,6 @@ class User(db.Model, UserMixin, CRUDMixin):
         return self.get_groups()
         return self.get_groups()
 
 
     @property
     @property
-    def unread_messages(self):
-        """Returns the unread messages for the user."""
-        return self.get_unread_messages()
-
-    @property
-    def unread_count(self):
-        """Returns the unread message count for the user."""
-        return len(self.unread_messages)
-
-    @property
-    def message_count(self):
-        """Returns the number of private messages of this user."""
-        return Conversation.query.filter(
-            Conversation.user_id == self.id,
-            Conversation.id == Message.conversation_id
-        ).count()
-
-    @property
     def days_registered(self):
     def days_registered(self):
         """Returns the amount of days the user is registered."""
         """Returns the amount of days the user is registered."""
         days_registered = (time_utcnow() - self.date_joined).days
         days_registered = (time_utcnow() - self.date_joined).days
@@ -427,27 +408,10 @@ class User(db.Model, UserMixin, CRUDMixin):
                 perms[c] = getattr(group, c) or perms.get(c, False)
                 perms[c] = getattr(group, c) or perms.get(c, False)
         return perms
         return perms
 
 
-    @cache.memoize()
-    def get_unread_messages(self):
-        """Returns all unread messages for the user."""
-        unread_messages = Conversation.query.\
-            filter(Conversation.unread, Conversation.user_id == self.id).all()
-        return unread_messages
-
-    def invalidate_cache(self, permissions=True, messages=True):
-        """Invalidates this objects cached metadata.
-
-        :param permissions_only: If set to ``True`` it will only invalidate
-                                 the permissions cache. Otherwise it will
-                                 also invalidate the user's unread message
-                                 cache.
-        """
-        if messages:
-            cache.delete_memoized(self.get_unread_messages, self)
-
-        if permissions:
-            cache.delete_memoized(self.get_permissions, self)
-            cache.delete_memoized(self.get_groups, self)
+    def invalidate_cache(self):
+        """Invalidates this objects cached metadata."""
+        cache.delete_memoized(self.get_permissions, self)
+        cache.delete_memoized(self.get_groups, self)
 
 
     def ban(self):
     def ban(self):
         """Bans the user. Returns True upon success."""
         """Bans the user. Returns True upon success."""

+ 0 - 29
tests/unit/test_message_models.py

@@ -1,29 +0,0 @@
-from flaskbb.message.models import Message, Conversation
-
-
-def test_conversation_save(conversation):
-    """ also tests message.save() since we must create a message to save """
-    message = Message(
-        user_id=conversation.user_id,
-        conversation_id=conversation.id,
-        message="Hello World"
-    )
-    conversation.save(message=message)
-    assert conversation.shared_id is not None
-
-
-def test_first_message(conversation_msgs, user):
-    conversation = conversation_msgs
-    assert conversation.first_message.message == "First message"
-
-
-def test_last_message(conversation_msgs, user):
-    conversation = conversation_msgs
-    assert conversation.last_message.message == "Second message"
-
-    message = Message(
-        user_id=user.id,
-        message="Third message"
-    )
-    conversation.save(message=message)
-    assert conversation.last_message.message != "Second message"