PCv5/app/routes/posts/edit.py

194 lines
6.2 KiB
Python

from app import app, db
from app.models.attachment import Attachment
from app.models.comment import Comment
from app.models.forum import Forum
from app.models.post import Post
from app.models.program import Program
from app.models.thread import Thread
from app.models.topic import Topic
from app.models.user import Member
from app.utils.render import render
from app.utils.check_csrf import check_csrf
from app.forms.forum import CommentEditForm, AnonymousCommentEditForm, TopicEditForm
from app.forms.post import MovePost, SearchThread
from wtforms import BooleanField
from urllib.parse import urlparse
from flask import redirect, url_for, abort, request, flash
from flask_login import login_required, current_user
from sqlalchemy import text
@app.route('/post/editer/<int:postid>', methods=['GET','POST'])
@login_required
def edit_post(postid):
# TODO: Maybe not safe
referrer = urlparse(request.args.get('r', default = '/', type = str)).path
print(referrer)
p = Post.query.filter_by(id=postid).first_or_404()
# Check permissions. TODO: Allow guests to edit their posts?
if not current_user.can_edit_post(p):
abort(403)
if isinstance(p, Comment):
base = CommentEditForm
comment = p
elif isinstance(p, Topic):
base = TopicEditForm
comment = p.thread.top_comment
else:
abort(404)
class TheForm(base):
pass
for a in comment.attachments:
setattr(TheForm, f'a{a.id}', BooleanField(f'a{a.id}'))
setattr(TheForm, 'attachment_list',
{ f'a{a.id}': a for a in comment.attachments })
form = TheForm()
if isinstance(p, Topic):
forums = sorted(Forum.query.all(), key=lambda f: f.url)
forums = [f for f in forums if current_user.can_post_in_forum(f)]
form.forum.choices = [(f.url, f"{f.url}: {f.name}") for f in forums]
if form.validate_on_submit():
comment.text = form.message.data
# Remove attachments
for id, a in form.attachment_list.items():
if form[id].data:
a.delete()
# Add new attachments
attachments = []
for file in form.attachments.data:
if file.filename != "":
a = Attachment(file, comment)
attachments.append((a, file))
db.session.add(a)
db.session.add(comment)
if isinstance(p, Topic):
p.title = form.title.data
f = Forum.query.filter_by(url=form.forum.data).first_or_404()
if current_user.can_post_in_forum(f):
p.forum = f
db.session.merge(p)
db.session.commit()
for a, file in attachments:
a.set_file(file)
# Determine topic URL now, in case forum was changed
if isinstance(p, Topic):
return redirect(url_for('forum_topic', f=p.forum, page=(p,1)))
else:
return redirect(referrer)
# Non-submitted form
if isinstance(p, Comment):
form.message.data = p.text
return render('forum/edit_comment.html', comment=p, form=form)
elif isinstance(p, Topic):
form.message.data = p.thread.top_comment.text
form.title.data = p.title
form.forum.data = p.forum.url
return render('forum/edit_topic.html', t=p, form=form)
@app.route('/post/supprimer/<int:postid>', methods=['GET','POST'])
@login_required
@check_csrf
def delete_post(postid):
next_page = request.referrer
p = Post.query.filter_by(id=postid).first_or_404()
xp = -1
if not current_user.can_delete_post(p):
abort(403)
# Users who need to have their trophies updated
authors = set()
# When deleting topics, return to forum page
if isinstance(p, Topic):
next_page = url_for('forum_page', f=p.forum)
xp = -2
for comment in p.thread.comments:
if isinstance(comment.author, Member):
comment.author.add_xp(-1)
db.session.merge(comment.author)
authors.add(comment.author)
if isinstance(p.author, Member):
factor = 3 if request.args.get('penalty') == 'True' else 1
p.author.add_xp(xp * factor)
db.session.merge(p.author)
authors.add(p.author)
p.delete()
db.session.commit()
for author in authors:
author.update_trophies("new-post")
return redirect(next_page)
@app.route('/post/entete/<int:postid>', methods=['GET'])
@login_required
@check_csrf
def set_post_topcomment(postid):
comment = Post.query.filter_by(id=postid).first_or_404()
if current_user.can_set_topcomment(comment):
comment.thread.top_comment = comment
db.session.add(comment.thread)
db.session.commit()
return redirect(request.referrer)
@app.route('/post/deplacer/<int:postid>', methods=['GET', 'POST'])
@login_required
def move_post(postid):
comment = Post.query.filter_by(id=postid).first_or_404()
if not current_user.can_edit_post(comment):
abort(403)
if not isinstance(comment, Comment):
flash("Vous ne pouvez pas déplacer un message principal", 'error')
abort(403)
move_form = MovePost(prefix="move_")
search_form = SearchThread(prefix="thread_")
keyword = search_form.name.data if search_form.validate_on_submit() else ""
# Get 10 last corresponding threads
# TODO: add support for every MainPost
req = text("""SELECT thread.id, topic.title FROM thread
INNER JOIN topic ON topic.thread_id = thread.id
WHERE lower(topic.title) LIKE lower(:keyword)
ORDER BY thread.id DESC LIMIT 10""")
threads = list(db.session.execute(req, {'keyword': '%'+keyword+'%'}))
move_form.thread.choices = [(t[0], f"{t[1]}") for t in threads]
if move_form.validate_on_submit():
thread = Thread.query.get_or_404(move_form.thread.data)
owner_post = thread.owner_post
if isinstance(owner_post, Topic):
t = owner_post
if not current_user.can_access_forum(t.forum):
abort(403)
comment.thread = thread
db.session.add(comment)
db.session.commit()
return redirect(url_for('forum_topic', f=t.forum, page=(t,1)))
return render('post/move_post.html', comment=comment,
search_form=search_form, move_form=move_form)