Browse Source

Merged the "pms" module with the user module and named it "messages"

sh4nks 11 years ago
parent
commit
7603e1cca3

+ 3 - 0
.gitignore

@@ -36,5 +36,8 @@ __pycache__
 *.pyc
 *.db
 .venv
+*.sublime-workspace
+*.sublime-project
+*.egg-info
 flaskbb/configs/production.py
 flaskbb/configs/development.py

+ 0 - 0
flaskbb/pms/__init__.py


+ 0 - 44
flaskbb/pms/forms.py

@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.pms.forms
-    ~~~~~~~~~~~~~~~~~~~~
-
-    It provides the forms that are needed for the pm views.
-
-    :copyright: (c) 2013 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-from flask.ext.wtf import Form
-from wtforms import TextField, TextAreaField, ValidationError
-from wtforms.validators import Required
-
-from flask.ext.login import current_user
-
-from flaskbb.user.models import User
-from flaskbb.pms.models import PrivateMessage
-
-
-class NewMessage(Form):
-    to_user = TextField("To User", validators=[
-        Required(message="A username is required.")])
-    subject = TextField("Subject", validators=[
-        Required(message="A subject is required.")])
-    message = TextAreaField("Message", validators=[
-        Required(message="A message is required.")])
-
-    def validate_to_user(self, field):
-        user = User.query.filter_by(username=field.data).first()
-        if not user:
-            raise ValidationError("The username you have entered doesn't 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):
-        message = PrivateMessage(
-            subject=self.subject.data,
-            message=self.message.data,
-            unread=unread)
-
-        if as_draft:
-            return message.save(from_user, to_user, user_id, draft=True)
-        return message.save(from_user, to_user, user_id)

+ 0 - 57
flaskbb/pms/models.py

@@ -1,57 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.pms.models
-    ~~~~~~~~~~~~~~~~~~~~
-
-    This module provides the appropriate models for the pm views.
-
-    :copyright: (c) 2013 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-from datetime import datetime
-
-from flaskbb.extensions import db
-
-
-class PrivateMessage(db.Model):
-    __tablename__ = "privatemessages"
-
-    id = db.Column(db.Integer, primary_key=True)
-    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
-    from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
-    to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
-    subject = db.Column(db.String)
-    message = db.Column(db.Text)
-    date_created = db.Column(db.DateTime, default=datetime.utcnow())
-    trash = db.Column(db.Boolean, nullable=False, default=False)
-    draft = db.Column(db.Boolean, nullable=False, default=False)
-    unread = db.Column(db.Boolean, nullable=False, default=True)
-
-    user = db.relationship("User", backref="pms", lazy="joined",
-                           foreign_keys=[user_id])
-    from_user = db.relationship("User", lazy="joined",
-                                foreign_keys=[from_user_id])
-    to_user = db.relationship("User", lazy="joined", foreign_keys=[to_user_id])
-
-    def save(self, from_user=None, to_user=None, user_id=None, draft=False):
-        if self.id:
-            db.session.add(self)
-            db.session.commit()
-            return self
-
-        if draft:
-            self.draft = True
-
-        # Add the message to the user's pm box
-        self.user_id = user_id
-        self.from_user_id = from_user
-        self.to_user_id = to_user
-
-        db.session.add(self)
-        db.session.commit()
-        return self
-
-    def delete(self):
-        db.session.delete(self)
-        db.session.commit()
-        return self

+ 0 - 133
flaskbb/pms/views.py

@@ -1,133 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    flaskbb.pms.views
-    ~~~~~~~~~~~~~~~~~~~~
-
-    This module contains the views that provides the functionality
-    for creating and viewing private messages.
-
-    :copyright: (c) 2013 by the FlaskBB Team.
-    :license: BSD, see LICENSE for more details.
-"""
-from flask import Blueprint, render_template, flash, redirect, url_for, request
-from flask.ext.login import login_required, current_user
-
-from flaskbb.extensions import db
-from flaskbb.user.models import User
-from flaskbb.pms.forms import NewMessage
-from flaskbb.pms.models import PrivateMessage
-
-pms = Blueprint("pms", __name__)
-
-
-@pms.route("/")
-@pms.route("/inbox")
-@login_required
-def inbox():
-    messages = PrivateMessage.query.filter(
-        PrivateMessage.user_id == current_user.id,
-        PrivateMessage.draft == False,
-        PrivateMessage.trash == False,
-        db.not_(PrivateMessage.from_user_id == current_user.id)).all()
-    return render_template("pms/inbox.html", messages=messages)
-
-
-@pms.route("/message/<int:id>")
-@login_required
-def view_message(id):
-    message = PrivateMessage.query.filter_by(id=id).first()
-    if message.unread:
-        message.unread=False
-        db.session.commit()
-    return render_template("pms/view_message.html", message=message)
-
-
-@pms.route("/sent")
-@login_required
-def sent():
-    messages = PrivateMessage.query.filter(
-        PrivateMessage.user_id == current_user.id,
-        PrivateMessage.draft == False,
-        PrivateMessage.trash == False,
-        db.not_(PrivateMessage.to_user_id == current_user.id)).all()
-    return render_template("pms/sent.html", messages=messages)
-
-
-@pms.route("/trash")
-@login_required
-def trash():
-    messages = PrivateMessage.query.filter(
-        PrivateMessage.user_id == current_user.id,
-        PrivateMessage.trash == True).all()
-    return render_template("pms/trash.html", messages=messages)
-
-
-@pms.route("/draft")
-@login_required
-def drafts():
-    messages = PrivateMessage.query.filter(
-        PrivateMessage.user_id == current_user.id,
-        PrivateMessage.draft == True,
-        PrivateMessage.trash == False).all()
-    return render_template("pms/drafts.html", messages=messages)
-
-
-@pms.route("/new", methods=["POST", "GET"])
-@login_required
-def new_message():
-    form = NewMessage()
-    to_user = request.args.get("to_user")
-
-    if request.method == "POST":
-        if "save_message" in request.form:
-            to_user = User.query.filter_by(username=form.to_user.data).first()
-
-            form.save(from_user=current_user.id,
-                      to_user=to_user.id,
-                      user_id=current_user.id,
-                      unread=False,
-                      as_draft=True)
-
-            flash("Message saved!", "success")
-            return redirect(url_for("pms.drafts"))
-
-        if "send_message" in request.form and form.validate():
-            to_user = User.query.filter_by(username=form.to_user.data).first()
-
-            # 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)
-
-            # 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)
-
-            flash("Message sent!", "success")
-            return redirect(url_for("pms.sent"))
-    else:
-        form.to_user.data = to_user
-
-    return render_template("pms/new_message.html", form=form)
-
-
-@pms.route("/<int:id>/move")
-@login_required
-def move_message(id):
-    message = PrivateMessage.query.filter_by(id=id).first()
-    message.trash = True
-    message.save()
-    flash("Message moved to Trash!", "success")
-    return redirect(url_for("pms.inbox"))
-
-
-@pms.route("/<int:id>/delete")
-@login_required
-def delete_message(id):
-    message = PrivateMessage.query.filter_by(id=id).first()
-    message.delete()
-    flash("Message deleted!", "success")
-    return redirect(url_for("pms.inbox"))

+ 2 - 2
flaskbb/templates/layout.html

@@ -66,8 +66,8 @@
                                 <span class="glyphicon glyphicon-envelope"></span> <span class="badge">{{ current_user.pm_unread }}</span>
                             </button>
                             <ul class="dropdown-menu" role="menu">
-                                <li><a href="{{ url_for('pms.inbox') }}"><span class="glyphicon glyphicon-envelope"></span> Inbox</a></li>
-                                <li><a href="{{ url_for('pms.new_message') }}"><span class="glyphicon glyphicon-pencil"></span> New Message</a></li>
+                                <li><a href="{{ url_for('user.inbox') }}"><span class="glyphicon glyphicon-envelope"></span> Inbox</a></li>
+                                <li><a href="{{ url_for('user.new_message') }}"><span class="glyphicon glyphicon-pencil"></span> New Message</a></li>
                             </ul>
                         </div>
                     {% else %}

+ 5 - 5
flaskbb/templates/pms/drafts.html → flaskbb/templates/message/drafts.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 <table class="table table-bordered">
     <thead>
         <tr>
@@ -13,10 +13,10 @@
         {% for message in messages %}
         <tr>
             <td><a href="{{ url_for('user.profile', username=message.to_user.username) }}">{{ message.to_user.username }}</a></td>
-            <td><a href="{{ url_for('pms.view_message', id=message.id) }}">{% if message.subject %}{{ message.subject }}{% else %}(No Subject){% endif %}</a></td>
+            <td><a href="{{ url_for('user.view_message', id=message.id) }}">{% if message.subject %}{{ message.subject }}{% else %}(No Subject){% endif %}</a></td>
             <td>{{ message.date_created|format_date('%d %B %Y') }}</td>
-            <td><a href="{{ url_for('pms.delete_message', id=message.id) }}">Delete</a> |
-                <a href="{{ url_for('pms.move_message', id=message.id) }}">Move</a></td>
+            <td><a href="{{ url_for('user.delete_message', id=message.id) }}">Delete</a> |
+                <a href="{{ url_for('user.move_message', id=message.id) }}">Move</a></td>
         </tr>
         {% endfor %}
     </tbody>

+ 5 - 5
flaskbb/templates/pms/inbox.html → flaskbb/templates/message/inbox.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 <table class="table table-bordered">
     <thead>
         <tr>
@@ -13,10 +13,10 @@
         {% for message in messages %}
         <tr>
             <td><a href="{{ url_for('user.profile', username=message.from_user.username) }}">{{ message.from_user.username }}</a></td>
-            <td><a href="{{ url_for('pms.view_message', id=message.id) }}">{{ message.subject }}</a></td>
+            <td><a href="{{ url_for('user.view_message', id=message.id) }}">{{ message.subject }}</a></td>
             <td>{{ message.date_created|time_since }}</td>
-            <td><a href="{{ url_for('pms.delete_message', id=message.id) }}">Delete</a> |
-                <a href="{{ url_for('pms.move_message', id=message.id) }}">Move</a></td>
+            <td><a href="{{ url_for('user.delete_message', id=message.id) }}">Delete</a> |
+                <a href="{{ url_for('user.move_message', id=message.id) }}">Move</a></td>
         </tr>
         {% endfor %}
     </tbody>

+ 6 - 6
flaskbb/templates/pms/pm_layout.html → flaskbb/templates/message/message_layout.html

@@ -12,16 +12,16 @@
     <div class="col-sm-3">
         <div class="sidebar">
             <ul class="nav sidenav">
-                <li class="nav-header">Options | <small><a href="{{ url_for('pms.new_message') }}">New PM</a></small></li>
-                {{ navlink('pms.inbox', 'Inbox') }}
-                {{ navlink('pms.sent', 'Sent') }}
-                {{ navlink('pms.drafts', 'Drafts') }}
-                {{ navlink('pms.trash', 'Trash') }}
+                <li class="nav-header">Options | <small><a href="{{ url_for('user.new_message') }}">New PM</a></small></li>
+                {{ navlink('user.inbox', 'Inbox') }}
+                {{ navlink('user.sent', 'Sent') }}
+                {{ navlink('user.drafts', 'Drafts') }}
+                {{ navlink('user.trash', 'Trash') }}
             </ul>
         </div><!--/.sidebar -->
     </div><!--/.col-sm-3 -->
     <div class="col-sm-9">
-        {% block pm_content %}{% endblock %}
+        {% block message_content %}{% endblock %}
     </div><!--/.col-sm-9 -->
 </div><!--/.row -->
 {% endblock %}

+ 2 - 2
flaskbb/templates/pms/new_message.html → flaskbb/templates/message/new_message.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 {% import "macros.html" as wtf %}
 <form class="form-horizontal" role="form" method="post" name="new">
     <legend>Compose Message</legend>

+ 5 - 5
flaskbb/templates/pms/sent.html → flaskbb/templates/message/sent.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 <table class="table table-bordered">
     <thead>
         <tr>
@@ -13,10 +13,10 @@
         {% for message in messages %}
         <tr>
             <td><a href="{{ url_for('user.profile', username=message.to_user.username) }}">{{ message.to_user.username }}</a></td>
-            <td><a href="{{ url_for('pms.view_message', id=message.id) }}">{{ message.subject }}</a></td>
+            <td><a href="{{ url_for('user.view_message', id=message.id) }}">{{ message.subject }}</a></td>
             <td>{{ message.date_created|time_since }}</td>
-            <td><a href="{{ url_for('pms.delete_message', id=message.id) }}">Delete</a> |
-                <a href="{{ url_for('pms.move_message', id=message.id) }}">Move</a></td>
+            <td><a href="{{ url_for('user.delete_message', id=message.id) }}">Delete</a> |
+                <a href="{{ url_for('user.move_message', id=message.id) }}">Move</a></td>
         </tr>
         {% endfor %}
     </tbody>

+ 4 - 4
flaskbb/templates/pms/trash.html → flaskbb/templates/message/trash.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 <table class="table table-bordered">
     <thead>
         <tr>
@@ -13,9 +13,9 @@
         {% for message in messages %}
         <tr>
             <td>{% if message.to_user %}<a href="{{ url_for('user.profile', username=message.to_user.username) }}">{{ message.to_user.username }}</a>{% else %} (No User) {% endif %}</td>
-            <td><a href="{{ url_for('pms.view_message', id=message.id) }}">{% if message.subject %}{{ message.subject }}{% else %}(No Subject){% endif %}</a></td>
+            <td><a href="{{ url_for('user.view_message', id=message.id) }}">{% if message.subject %}{{ message.subject }}{% else %}(No Subject){% endif %}</a></td>
             <td>{{ message.date_created|format_date }}</td>
-            <td><a href="{{ url_for('pms.delete_message', id=message.id) }}">Delete</a></td>
+            <td><a href="{{ url_for('user.delete_message', id=message.id) }}">Delete</a></td>
         </tr>
         {% endfor %}
     </tbody>

+ 2 - 2
flaskbb/templates/pms/view_message.html → flaskbb/templates/message/view_message.html

@@ -1,5 +1,5 @@
-{% extends "pms/pm_layout.html" %}
-{% block pm_content %}
+{% extends "message/message_layout.html" %}
+{% block message_content %}
 <table class="table table-bordered">
     <tbody>
         <tr>

+ 29 - 1
flaskbb/user/forms.py

@@ -8,16 +8,18 @@
     :copyright: (c) 2013 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
 """
+from flask.ext.login import current_user
 from flask.ext.wtf import Form
 from wtforms import (TextField, PasswordField, DateField, TextAreaField,
                      SelectField, ValidationError)
 from wtforms.validators import (Length, Required, Email, EqualTo, regexp,
                                 Optional, URL)
 
-from flaskbb.user.models import User
+from flaskbb.user.models import User, PrivateMessage
 from flaskbb.extensions import db
 from flaskbb.helpers import SelectDateWidget
 
+
 IMG_RE = r'^[^/\\]\.(?:jpg|gif|png)'
 
 is_image = regexp(IMG_RE,
@@ -86,3 +88,29 @@ class ChangeUserDetailsForm(Form):
 
     notes = TextAreaField("Notes", validators=[
         Optional(), Length(min=0, max=5000)])
+
+
+class NewMessage(Form):
+    to_user = TextField("To User", validators=[
+        Required(message="A username is required.")])
+    subject = TextField("Subject", validators=[
+        Required(message="A subject is required.")])
+    message = TextAreaField("Message", validators=[
+        Required(message="A message is required.")])
+
+    def validate_to_user(self, field):
+        user = User.query.filter_by(username=field.data).first()
+        if not user:
+            raise ValidationError("The username you have entered doesn't 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):
+        message = PrivateMessage(
+            subject=self.subject.data,
+            message=self.message.data,
+            unread=unread)
+
+        if as_draft:
+            return message.save(from_user, to_user, user_id, draft=True)
+        return message.save(from_user, to_user, user_id)

+ 49 - 21
flaskbb/user/models.py

@@ -20,7 +20,8 @@ from flaskbb.extensions import db, cache
 from flaskbb.forum.models import Post, Topic, topictracker
 
 
-groups_users = db.Table('groups_users',
+groups_users = db.Table(
+    'groups_users',
     db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
     db.Column('group_id', db.Integer(), db.ForeignKey('groups.id')))
 
@@ -84,6 +85,8 @@ class User(db.Model, UserMixin):
     posts = db.relationship("Post", backref="user", lazy="dynamic")
     topics = db.relationship("Topic", backref="user", lazy="dynamic")
 
+    post_count = db.Column(db.Integer, default=0)
+
     primary_group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
 
     primary_group = db.relationship('Group', lazy="joined",
@@ -103,25 +106,6 @@ class User(db.Model, UserMixin):
                         backref=db.backref("topicstracked", lazy="dynamic"),
                         lazy="dynamic")
 
-    # Properties
-    @property
-    def post_count(self):
-        """
-        Property interface for get_post_count method.
-
-        Method seperate for easy invalidation of cache.
-        """
-        return self.get_post_count()
-
-    @property
-    def last_post(self):
-        """
-        Property interface for get_last_post method.
-
-        Method seperate for easy invalidation of cache.
-        """
-        return self.get_last_post()
-
     # Methods
     def __repr__(self):
         """
@@ -253,7 +237,7 @@ class User(db.Model, UserMixin):
         return self.secondary_groups.filter(
             groups_users.c.group_id == group.id).count() > 0
 
-    @cache.memoize(60*5)
+    @cache.memoize(timeout=sys.maxint)
     def get_permissions(self, exclude=None):
         """
         Returns a dictionary with all the permissions the user has.
@@ -346,3 +330,47 @@ class Guest(AnonymousUserMixin):
                 continue
             perms[c.name] = getattr(group, c.name)
         return perms
+
+
+class PrivateMessage(db.Model):
+    __tablename__ = "privatemessages"
+
+    id = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
+    from_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
+    to_user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
+    subject = db.Column(db.String)
+    message = db.Column(db.Text)
+    date_created = db.Column(db.DateTime, default=datetime.utcnow())
+    trash = db.Column(db.Boolean, nullable=False, default=False)
+    draft = db.Column(db.Boolean, nullable=False, default=False)
+    unread = db.Column(db.Boolean, nullable=False, default=True)
+
+    user = db.relationship("User", backref="pms", lazy="joined",
+                           foreign_keys=[user_id])
+    from_user = db.relationship("User", lazy="joined",
+                                foreign_keys=[from_user_id])
+    to_user = db.relationship("User", lazy="joined", foreign_keys=[to_user_id])
+
+    def save(self, from_user=None, to_user=None, user_id=None, draft=False):
+        if self.id:
+            db.session.add(self)
+            db.session.commit()
+            return self
+
+        if draft:
+            self.draft = True
+
+        # Add the message to the user's pm box
+        self.user_id = user_id
+        self.from_user_id = from_user
+        self.to_user_id = to_user
+
+        db.session.add(self)
+        db.session.commit()
+        return self
+
+    def delete(self):
+        db.session.delete(self)
+        db.session.commit()
+        return self

+ 120 - 5
flaskbb/user/views.py

@@ -10,12 +10,14 @@
     :license: BSD, see LICENSE for more details.
 """
 from datetime import datetime
-from flask import Blueprint, render_template, flash, request
+from flask import Blueprint, render_template, flash, request, redirect, url_for
 from flask.ext.login import login_required, current_user
 
-from flaskbb.user.models import User
+from flaskbb.extensions import db
+from flaskbb.user.models import User, PrivateMessage
 from flaskbb.user.forms import (ChangePasswordForm, ChangeEmailForm,
-                                ChangeUserDetailsForm)
+                                ChangeUserDetailsForm, NewMessage)
+
 
 user = Blueprint("user", __name__)
 
@@ -34,7 +36,7 @@ def profile(username):
                            posts_per_day=posts_per_day)
 
 
-@user.route("/<username>/all_topics")
+@user.route("/<username>/topics")
 def view_all_topics(username):
     page = request.args.get("page", 1, type=int)
     user = User.query.filter_by(username=username).first_or_404()
@@ -42,7 +44,7 @@ def view_all_topics(username):
     return render_template("user/all_topics.html", user=user, topics=topics)
 
 
-@user.route("/<username>/all_posts")
+@user.route("/<username>/posts")
 def view_all_posts(username):
     page = request.args.get("page", 1, type=int)
     user = User.query.filter_by(username=username).first_or_404()
@@ -99,3 +101,116 @@ def change_user_details():
         form.notes.data = current_user.notes
 
     return render_template("user/change_user_details.html", form=form)
+
+
+@user.route("/messages")
+@user.route("/messages/inbox")
+@login_required
+def inbox():
+    messages = PrivateMessage.query.filter(
+        PrivateMessage.user_id == current_user.id,
+        PrivateMessage.draft == False,
+        PrivateMessage.trash == False,
+        db.not_(PrivateMessage.from_user_id == current_user.id)).all()
+    return render_template("message/inbox.html", messages=messages)
+
+
+@user.route("/messages/<int:id>/view")
+@login_required
+def view_message(id):
+    message = PrivateMessage.query.filter_by(id=id).first()
+    if message.unread:
+        message.unread=False
+        db.session.commit()
+    return render_template("message/view_message.html", message=message)
+
+
+@user.route("/messages/sent")
+@login_required
+def sent():
+    messages = PrivateMessage.query.filter(
+        PrivateMessage.user_id == current_user.id,
+        PrivateMessage.draft == False,
+        PrivateMessage.trash == False,
+        db.not_(PrivateMessage.to_user_id == current_user.id)).all()
+    return render_template("message/sent.html", messages=messages)
+
+
+@user.route("/messages/trash")
+@login_required
+def trash():
+    messages = PrivateMessage.query.filter(
+        PrivateMessage.user_id == current_user.id,
+        PrivateMessage.trash == True).all()
+    return render_template("message/trash.html", messages=messages)
+
+
+@user.route("/messages/draft")
+@login_required
+def drafts():
+    messages = PrivateMessage.query.filter(
+        PrivateMessage.user_id == current_user.id,
+        PrivateMessage.draft == True,
+        PrivateMessage.trash == False).all()
+    return render_template("message/drafts.html", messages=messages)
+
+
+@user.route("/messages/new", methods=["POST", "GET"])
+@login_required
+def new_message():
+    form = NewMessage()
+    to_user = request.args.get("to_user")
+
+    if request.method == "POST":
+        if "save_message" in request.form:
+            to_user = User.query.filter_by(username=form.to_user.data).first()
+
+            form.save(from_user=current_user.id,
+                      to_user=to_user.id,
+                      user_id=current_user.id,
+                      unread=False,
+                      as_draft=True)
+
+            flash("Message saved!", "success")
+            return redirect(url_for("user.drafts"))
+
+        if "send_message" in request.form and form.validate():
+            to_user = User.query.filter_by(username=form.to_user.data).first()
+
+            # 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)
+
+            # 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)
+
+            flash("Message sent!", "success")
+            return redirect(url_for("user.sent"))
+    else:
+        form.to_user.data = to_user
+
+    return render_template("message/new_message.html", form=form)
+
+
+@user.route("/messages/<int:id>/move")
+@login_required
+def move_message(id):
+    message = PrivateMessage.query.filter_by(id=id).first()
+    message.trash = True
+    message.save()
+    flash("Message moved to Trash!", "success")
+    return redirect(url_for("user.inbox"))
+
+
+@user.route("/messages/<int:id>/delete")
+@login_required
+def delete_message(id):
+    message = PrivateMessage.query.filter_by(id=id).first()
+    message.delete()
+    flash("Message deleted!", "success")
+    return redirect(url_for("user.inbox"))