From 08054175bf55f310aef302efeab05b3a3cecb948 Mon Sep 17 00:00:00 2001 From: Eragon Date: Sun, 10 Mar 2024 19:29:46 +0100 Subject: [PATCH] Allow to merge a comment with a comment which was posted later --- app/forms/post.py | 5 +++ app/models/user.py | 5 +++ app/routes/posts/edit.py | 55 +++++++++++++++++++++++++++--- app/templates/post/merge_post.html | 37 ++++++++++++++++++++ app/templates/widgets/thread.html | 5 +++ config.py | 3 ++ 6 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 app/templates/post/merge_post.html diff --git a/app/forms/post.py b/app/forms/post.py index 2cd810e..b0ff598 100644 --- a/app/forms/post.py +++ b/app/forms/post.py @@ -10,3 +10,8 @@ class MovePost(FlaskForm): class SearchThread(FlaskForm): name = StringField("Nom d'un topic, programme, …") search = SubmitField('Rechercher') + +class MergePost(FlaskForm): + # List of posts is generated at runtime + post = SelectField('Fusionner avec', coerce=int, validators=[]) + submit = SubmitField('Fusionner') diff --git a/app/models/user.py b/app/models/user.py index 37baf04..9b9f946 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -270,6 +270,11 @@ class Member(User): return False return self.priv("lock.threads") + def can_merge_post(self, post): + """Whether this member can merge the post""" + # NOTE: Might need more check than this + return self.can_edit_post(post) + def can_access_file(self, file): """Whether this member can access the file.""" return self.can_access_post(file.comment) diff --git a/app/routes/posts/edit.py b/app/routes/posts/edit.py index bade1d1..637c1a3 100644 --- a/app/routes/posts/edit.py +++ b/app/routes/posts/edit.py @@ -1,4 +1,4 @@ -from app import app, db +from app import app, db, V5Config from app.models.attachment import Attachment from app.models.comment import Comment from app.models.forum import Forum @@ -11,17 +11,18 @@ from app.utils.render import render from app.utils.check_csrf import check_csrf from app.utils.priv_required import priv_required from app.forms.forum import CommentEditForm, AnonymousCommentEditForm, TopicEditForm -from app.forms.post import MovePost, SearchThread +from app.forms.post import MovePost, SearchThread, MergePost 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 +from sqlalchemy import text, and_ +from datetime import timedelta @app.route('/post/editer/', methods=['GET','POST']) @login_required def edit_post(postid): - # TODO: Maybe not safe + # FIXME: Maybe not safe referrer = urlparse(request.args.get('r', default = '/', type = str)).path print(referrer) @@ -244,4 +245,48 @@ def lock_thread(postid): flash(f"Le thread a été déverrouillé", 'ok') app.v5logger.info(f"[admin] <{current_user.name}> has unlocked the thread #{post.thread.id}") - return redirect(request.referrer) \ No newline at end of file + return redirect(request.referrer) + +@app.route('/post/fusionner/', methods=['GET', 'POST']) +@login_required +def merge_post(postid): + comment = Comment.query.get_or_404(postid) + + # Get the posts from the same user in the same topic that are separated + # by less than V5Config.MERGE_AGE_THRESHOLD + compatible_comments = Comment.query.filter(and_( + Comment.thread_id == comment.thread_id, + and_( + Post.author_id == comment.author_id, + and_( + Post.date_created > comment.date_created, + Post.date_created <= comment.date_created + timedelta(0, V5Config.MERGE_AGE_THRESHOLD) + ) + ) + )) + + merge_form = MergePost() + merge_form.post.choices = [(t.id, f"{t.text[:30]}[…]") for t in list(compatible_comments)] + + if merge_form.validate_on_submit(): + merge_comment = Comment.query.filter_by(id=merge_form.post.data).first_or_404() + + comment.text += f"\n\n---\n\n{merge_comment.text}" + + # Change the modification date only if the other post is more recent + if merge_comment.date_created > comment.date_modified: + comment.date_modified = merge_comment.date_created + + if merge_comment.is_top_comment: + comment.thread.set_top_comment(comment) + + db.session.add(comment) + merge_comment.delete() + db.session.commit() + + if isinstance(comment.thread.owner_post, Topic): + return redirect(url_for('forum_topic', f=comment.thread.owner_post.forum_id, page=comment.thread_id)) + elif isinstance(comment.thread.owner_post, Program): + return redirect(url_for('program_view', page=[comment.thread.owner_post, -1])) + + return render('post/merge_post.html', comment=comment, merge_form=merge_form) diff --git a/app/templates/post/merge_post.html b/app/templates/post/merge_post.html new file mode 100644 index 0000000..cf4821f --- /dev/null +++ b/app/templates/post/merge_post.html @@ -0,0 +1,37 @@ +{% extends "base/base.html" %} +{% import "widgets/editor.html" as widget_editor %} +{% import "widgets/user.html" as widget_user %} + +{% set tabtitle = "Déplacer un commentaire" %} + +{% block title %} +Forum de Planète Casio » Fusion de commentaire +{% endblock %} + +{% block content %} +
+

Fusionner deux commentaires

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

+ {{ merge_form.hidden_tag() }} + +
+ {{ merge_form.post.label }} + {{ merge_form.post }} + {% for error in merge_form.post.errors %} + {{ error }} + {% endfor %} +
+ +
{{ merge_form.submit(class_='bg-ok') }}
+
+
+{% endblock %} diff --git a/app/templates/widgets/thread.html b/app/templates/widgets/thread.html index b6012fb..33e2cd5 100644 --- a/app/templates/widgets/thread.html +++ b/app/templates/widgets/thread.html @@ -13,6 +13,7 @@ {% 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" %} {% set can_lock = auth and current_user.can_lock_thread(post) %} + {% set can_merge = auth and current_user.can_merge_post(post) %} {% if post.type == "topic" %} {% set suffix = " le sujet" %} @@ -32,6 +33,10 @@ Déplacer {% endif %} + {% if can_merge %} + Fusioner + {% endif %} + {% if can_punish and post.author.type == "member"%} Supprimer{{ suffix }} (normal) Supprimer{{ suffix }} (pénalité) diff --git a/config.py b/config.py index 838a300..f47a429 100644 --- a/config.py +++ b/config.py @@ -86,6 +86,9 @@ class DefaultConfig(object): ENABLE_FLASK_DEBUG_TOOLBAR = False # Tab title prefix. Useful to dissociate local/dev/prod tabs TABTITLE_PREFIX = "" + # Posts which are separated by more than this value (in seconds) + # can't be merged together (I thought that 10 minutes was a good default) + MERGE_AGE_THRESHOLD = 600 @staticmethod def v5logger():