syntaxwebsite/app/pages/messages/messages.py

148 lines
6.4 KiB
Python

from flask import Blueprint, render_template, request, redirect, url_for, flash, make_response, jsonify, abort
from app.models.messages import Message
from app.util import auth, turnstile, websiteFeatures
from app.extensions import db, csrf, limiter, redis_controller
from app.models.user import User
from app.util.textfilter import FilterText
from sqlalchemy import or_
MessageRoute = Blueprint('message', __name__, template_folder="pages")
def CreateSystemMessage( subject : str, message : str, userid : int ):
"""
Creates a system message from the system user to the specified user
"""
TargetUser = User.query.filter_by(id=userid).first()
if TargetUser is None:
return False
NewMessage : Message = Message(
subject=subject,
content=message,
sender_id=1,
recipient_id=userid
)
db.session.add(NewMessage)
db.session.commit()
return True
@MessageRoute.route("/my/messages", methods=["GET"])
@auth.authenticated_required
def my_messages():
return redirect("/messages")
@MessageRoute.route("/new/<userid>", methods=["GET"])
@auth.authenticated_required
def new_message(userid):
TargetUser = User.query.filter_by(id=userid).first()
if TargetUser is None:
return "User not found",404
if TargetUser.accountstatus == 4 or TargetUser.accountstatus == 3:
abort(404)
AuthenticatedUser = auth.GetCurrentUser()
if AuthenticatedUser.id == TargetUser.id:
return "You cannot message yourself",400
MessageReplyContext = request.args.get("reply", default=None, type=int)
if MessageReplyContext is not None:
ReplyMessage = Message.query.filter_by( id = MessageReplyContext ).filter( or_( Message.sender_id == AuthenticatedUser.id, Message.recipient_id == AuthenticatedUser.id ) ).first()
else:
ReplyMessage = None
return render_template("messages/new.html", targetuser=TargetUser, replymessage=ReplyMessage)
@MessageRoute.route("/new/<userid>", methods=["POST"])
@auth.authenticated_required
@limiter.limit("10/minute")
def send_message(userid):
if 'cf-turnstile-response' not in request.form or request.form.get('cf-turnstile-response') == '':
flash("Please complete the captcha", "error")
return redirect(f"/messages/new/{userid}")
if 'message' not in request.form or request.form.get('message') == '':
flash("Please enter a message", "error")
return redirect(f"/messages/new/{userid}")
if 'subject' not in request.form or request.form.get('subject') == '':
flash("Please enter a subject", "error")
return redirect(f"/messages/new/{userid}")
if not websiteFeatures.GetWebsiteFeature("MessageSending"):
flash("Message sending is temporarily disabled", "error")
return redirect(f"/messages/new/{userid}")
TargetUser : User | None = User.query.filter_by(id=userid).first()
if TargetUser is None:
abort(404)
if TargetUser.accountstatus == 4 or TargetUser.accountstatus == 3:
abort(404)
AuthenticatedUser = auth.GetCurrentUser()
if AuthenticatedUser.id == TargetUser.id:
abort(400)
if len(request.form.get("message")) > 1024:
flash("Your message is too long", "error")
return redirect(f"/messages/new/{TargetUser.id}")
if len(request.form.get('subject')) > 64:
flash("Your subject is too long", "error")
return redirect(f"/messages/new/{TargetUser.id}")
if not turnstile.VerifyToken(request.form.get('cf-turnstile-response')):
flash("Invalid captcha", "error")
return redirect(f"/messages/new/{TargetUser.id}")
if redis_controller.get(f"message:{TargetUser.id}:{AuthenticatedUser.id}") is not None:
flash("You are sending messages too quickly", "error")
return redirect(f"/messages/new/{TargetUser.id}")
NewLineCount = request.form.get('message').count("\n")
if NewLineCount > 10:
flash("Your message has too many newlines", "error")
return redirect(f"/messages/new/{TargetUser.id}")
redis_controller.set(f"message:{TargetUser.id}:{AuthenticatedUser.id}", "1", ex=60)
FilteredSubject = FilterText(request.form.get('subject'))
FilteredMessage = FilterText(request.form.get('message'))
NewMessage = Message(
sender_id=AuthenticatedUser.id,
recipient_id=TargetUser.id,
subject=FilteredSubject,
content=FilteredMessage
)
db.session.add(NewMessage)
db.session.commit()
return redirect(f"/messages/view/{NewMessage.id}")
@MessageRoute.route("/view/<messageid>", methods=["GET"])
@auth.authenticated_required
def view_message(messageid):
MessageObj : Message = Message.query.filter_by(id=messageid).first()
if MessageObj is None:
abort(404)
AuthenicatatedUser = auth.GetCurrentUser()
if AuthenicatatedUser.id != MessageObj.sender_id and AuthenicatatedUser.id != MessageObj.recipient_id:
abort(404)
if AuthenicatatedUser.id == MessageObj.recipient_id:
MessageObj.read = True
db.session.commit()
SenderObj = User.query.filter_by(id=MessageObj.sender_id).first()
RecieverObj = User.query.filter_by(id=MessageObj.recipient_id).first()
MessageCreated = MessageObj.created.strftime("%b %d, %Y %I:%M %p")
messagelines = MessageObj.content.split("\n")
return render_template("messages/view.html", message=MessageObj, created=MessageCreated,sender=SenderObj, reciever=RecieverObj, messagelines=messagelines)
@MessageRoute.route("/", methods=['GET'])
@auth.authenticated_required
def messages():
AuthenticatedUser : User = auth.GetCurrentUser()
PageNumber = max( request.args.get('page', default=1, type=int), 1 )
UserMessagesList = Message.query.filter_by(recipient_id = AuthenticatedUser.id).order_by(Message.created.desc()).paginate(page = PageNumber, per_page = 10, error_out = False)
return render_template("messages/index.html", UserMessages=UserMessagesList, isOutgoing=False)
@MessageRoute.route("/outgoing", methods=['GET'])
@auth.authenticated_required
def outgoing_messages():
AuthenticatedUser : User = auth.GetCurrentUser()
PageNumber = max( request.args.get('page', default=1, type=int), 1 )
UserMessagesList = Message.query.filter_by(sender_id = AuthenticatedUser.id).order_by(Message.created.desc()).paginate(page = PageNumber, per_page = 10, error_out = False)
return render_template("messages/index.html", UserMessages=UserMessagesList, isOutgoing=True)