diff --git a/app/forms/post.py b/app/forms/post.py new file mode 100644 index 0000000..2cd810e --- /dev/null +++ b/app/forms/post.py @@ -0,0 +1,12 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SelectField, SubmitField + + +class MovePost(FlaskForm): + # List of threads is generated at runtime + thread = SelectField('Fil de discussion', coerce=int, validators=[]) + submit = SubmitField('Déplacer') + +class SearchThread(FlaskForm): + name = StringField("Nom d'un topic, programme, …") + search = SubmitField('Rechercher') diff --git a/app/models/comment.py b/app/models/comment.py index 5b29629..f5cb42a 100644 --- a/app/models/comment.py +++ b/app/models/comment.py @@ -22,6 +22,9 @@ class Comment(Post): # attachments (relation from Attachment) + @property + def is_top_comment(self): + return self.id == self.thread.top_comment_id def __init__(self, author, text, thread): """ diff --git a/app/routes/posts/edit.py b/app/routes/posts/edit.py index da4d703..b62b2ee 100644 --- a/app/routes/posts/edit.py +++ b/app/routes/posts/edit.py @@ -4,17 +4,20 @@ 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 +from flask import redirect, url_for, abort, request, flash from flask_login import login_required, current_user +from sqlalchemy import text -@app.route('/post/', methods=['GET','POST']) +@app.route('/post/editer/', methods=['GET','POST']) @login_required def edit_post(postid): # TODO: Maybe not safe @@ -23,8 +26,8 @@ def edit_post(postid): p = Post.query.filter_by(id=postid).first_or_404() - # Check permissions. TODO: Allow guests to edit their posts - if current_user.is_anonymous or not current_user.can_edit_post(p): + # Check permissions. TODO: Allow guests to edit their posts? + if not current_user.can_edit_post(p): abort(403) if isinstance(p, Comment): @@ -103,7 +106,7 @@ def delete_post(postid): p = Post.query.filter_by(id=postid).first_or_404() xp = -1 - if current_user.is_anonymous or not current_user.can_delete_post(p): + if not current_user.can_delete_post(p): abort(403) # Users who need to have their trophies updated @@ -146,3 +149,45 @@ def set_post_topcomment(postid): db.session.commit() return redirect(request.referrer) + + +@app.route('/post/deplacer/', 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) diff --git a/app/templates/post/move_post.html b/app/templates/post/move_post.html new file mode 100644 index 0000000..9b4a212 --- /dev/null +++ b/app/templates/post/move_post.html @@ -0,0 +1,52 @@ +{% extends "base/base.html" %} +{% import "widgets/editor.html" as widget_editor %} +{% import "widgets/user.html" as widget_user %} + +{% block title %} +Forum de Planète Casio » Édition de commentaire +{% endblock %} + +{% block content %} +
+

Déplacer un commentaire

+ + + + + + +
{{ widget_user.profile(comment.author) }}
{{ comment.text | md }}
+ +
+
+

Chercher un thread

+ {{ search_form.hidden_tag() }} + +
+ {{ search_form.name.label }} + {{ search_form.name() }} + {% for error in search_form.name.errors %} + {{ error }} + {% endfor %} +
+ +
{{ search_form.search(class_='bg-ok') }}
+
+ +
+

Nouveau thread

+ {{ move_form.hidden_tag() }} + +
+ {{ move_form.thread.label }} + {{ move_form.thread }} + {% for error in move_form.thread.errors %} + {{ error }} + {% endfor %} +
+ +
{{ move_form.submit(class_='bg-ok') }}
+
+
+
+{% endblock %} diff --git a/app/templates/widgets/thread.html b/app/templates/widgets/thread.html index f95fdc8..c315060 100644 --- a/app/templates/widgets/thread.html +++ b/app/templates/widgets/thread.html @@ -11,6 +11,7 @@ {% set can_delete = auth and current_user.can_delete_post(post) %} {% set can_punish = auth and current_user.can_punish_post(post) %} {% set can_topcomm = auth and current_user.can_set_topcomment(post) %} + {% set can_move = auth and current_user.can_edit_post(post) and post.type == "comment" %} {% if post.type == "topic" %} {% set suffix = " le sujet" %} @@ -26,6 +27,10 @@ Modifier{{ suffix }} {% endif %} + {% if can_move %} + Déplacer + {% endif %} + {% if can_punish %} Supprimer{{ suffix }} (normal) Supprimer{{ suffix }} (pénalité)