Allow to merge a comment with a comment which was posted later

This commit is contained in:
Eragon 2024-03-10 19:29:46 +01:00
parent 2685ffcbc7
commit 08054175bf
Signed by: Eragon
GPG Key ID: 087126EBFC725006
6 changed files with 105 additions and 5 deletions

View File

@ -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')

View File

@ -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)

View File

@ -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/<int:postid>', 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)
return redirect(request.referrer)
@app.route('/post/fusionner/<int:postid>', 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)

View File

@ -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 %}
<a href='/forum'>Forum de Planète Casio</a> » Fusion de commentaire</h1>
{% endblock %}
{% block content %}
<section>
<h1>Fusionner deux commentaires</h1>
<table class="thread comment">
<tr>
<td class="author">{{ widget_user.profile(comment.author) }}</td>
<td><div>{{ comment.text | md }}</div></td>
</tr>
</table>
<form action="" method="post">
<h3></h3>
{{ merge_form.hidden_tag() }}
<div>
{{ merge_form.post.label }}
{{ merge_form.post }}
{% for error in merge_form.post.errors %}
<span class="msgerror">{{ error }}</span>
{% endfor %}
</div>
<div>{{ merge_form.submit(class_='bg-ok') }}</div>
</form>
</section>
{% endblock %}

View File

@ -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 @@
<a href="{{ url_for('move_post', postid=post.id) }}">Déplacer</a>
{% endif %}
{% if can_merge %}
<a href="{{ url_for('merge_post', postid=post.id) }}">Fusioner</a>
{% endif %}
{% if can_punish and post.author.type == "member"%}
<a href="{{ url_for('delete_post', postid=post.id, penalty=False, csrf_token=csrf_token()) }}" onclick="return confirm('Le post sera supprimé.')">Supprimer{{ suffix }} (normal)</a>
<a href="{{ url_for('delete_post', postid=post.id, penalty=True, csrf_token=csrf_token()) }}" onclick="return confirm('Le post sera supprimé avec pénalité d\'XP.')">Supprimer{{ suffix }} (pénalité)</a>

View File

@ -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():