From 9727c2a98600219a768fa5ccc3e2b082193bf33b Mon Sep 17 00:00:00 2001 From: Lephe Date: Mon, 12 Jul 2021 17:49:54 +0200 Subject: [PATCH] forum: add an action to change the top comment of a topic This also prepares the thread_leader macro for top comments of topics, programs, etc. which have extra stuff to render and more specific actions. --- app/data/groups.yaml | 2 +- app/models/user.py | 7 +++++ app/routes/posts/edit.py | 15 ++++++++++ app/static/css/table.css | 7 +++++ app/templates/forum/topic.html | 5 +++- app/templates/widgets/thread.html | 48 ++++++++++++++++++++++++------- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/app/data/groups.yaml b/app/data/groups.yaml index 79fd3b0..f81d603 100644 --- a/app/data/groups.yaml +++ b/app/data/groups.yaml @@ -16,7 +16,7 @@ # publish.shared-files # # Moderation: -# edit.posts +# edit.posts (includes top comment selection) # edit.tests # edit.accounts # edit.trophies diff --git a/app/models/user.py b/app/models/user.py index d0a4390..7b2fe72 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -227,6 +227,13 @@ class Member(User): return self.can_access_post(post) and \ ((post.author == self) or self.priv("delete.posts")) + def can_set_topcomment(self, comment): + """Whether this member can designate the comment as top comment.""" + if comment.type != "comment": + return False + post = comment.thread.owner_post + return self.can_edit_post(post) and (comment.author == post.author) + def update(self, **data): """ Update all or part of the user's metadata. The [data] dictionary diff --git a/app/routes/posts/edit.py b/app/routes/posts/edit.py index c1aee89..11b0a45 100644 --- a/app/routes/posts/edit.py +++ b/app/routes/posts/edit.py @@ -2,6 +2,8 @@ from app import app, db from app.models.user import Member from app.models.post import Post from app.models.attachment import Attachment +from app.models.topic import Topic +from app.models.program import Program from app.utils.render import render from app.utils.check_csrf import check_csrf from app.forms.forum import CommentEditForm, AnonymousCommentEditForm @@ -78,3 +80,16 @@ def delete_post(postid): p.delete() db.session.commit() return redirect(request.referrer) + +@app.route('/post/entete/', 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) diff --git a/app/static/css/table.css b/app/static/css/table.css index 691920f..2e9a54f 100644 --- a/app/static/css/table.css +++ b/app/static/css/table.css @@ -128,6 +128,12 @@ table.thread td.message img { max-width: 100%; } +table.thread .topcomment-placeholder div { + font-style: italic; + opacity: 0.5; + padding: 8px 0; +} + table.thread div.info { text-align: right; position: relative; @@ -147,6 +153,7 @@ table.thread div.info summary { cursor: pointer; user-select: none; } + table.thread .context-menu { position: absolute; right: 0; diff --git a/app/templates/forum/topic.html b/app/templates/forum/topic.html index 712ac86..468949c 100644 --- a/app/templates/forum/topic.html +++ b/app/templates/forum/topic.html @@ -11,7 +11,10 @@ {% block content %}

{{ t.title }}

- {{ widget_thread.thread([t.thread.top_comment], None) }} + + {% call widget_thread.thread_leader(t.thread.top_comment) %} + {{ t.thread.top_comment.text | md }} + {% endcall %} {{ widget_pagination.paginate(comments, 'forum_topic', t, {'f': t.forum}) }} diff --git a/app/templates/widgets/thread.html b/app/templates/widgets/thread.html index 47ec9f0..486ecea 100644 --- a/app/templates/widgets/thread.html +++ b/app/templates/widgets/thread.html @@ -1,11 +1,14 @@ {% import "widgets/user.html" as widget_user %} {% import "widgets/attachments.html" as widget_attachments %} -{% macro thread(comments, top_comment) %} - -{% if top_comment == None %} - -{% endif %} +{# Thread widget: this widget expands to a table that shows a list of comments + from a thread, along with message controls. + + comments: List of comments to render + top_comment: Thread's top comment (will be elided if encountered) #} + +{% macro thread(comments, top_comment, owner=None) %} +
{% for c in comments %} {% if c != top_comment %} @@ -18,9 +21,10 @@ {% endif %} {# TODO: Let guests edit their posts #} - {% set can_edit = current_user.is_authenticated and current_user.can_edit_post(c) %} - {% set can_delete = current_user.is_authenticated and current_user.can_delete_post(c) %} - {% set can_punish = current_user.is_authenticated and current_user.priv("delete.posts") %} + {% set can_edit = current_user.is_authenticated and current_user.can_edit_post(c) %} + {% set can_delete = current_user.is_authenticated and current_user.can_delete_post(c) %} + {% set can_punish = current_user.is_authenticated and current_user.priv("delete.posts") %} + {% set can_topcomm = current_user.is_authenticated and current_user.can_set_topcomment(c) %} {% if can_edit or can_delete or can_punish %}
@@ -29,12 +33,17 @@ {% if can_edit %} Modifier {% endif %} + {% if can_punish %} Supprimer (normal) Supprimer (pénalité) {% elif can_delete %} Supprimer {% endif %} + + {% if can_topcomm %} + Utiliser comme en-tête + {% endif %}
{% endif %} @@ -51,11 +60,28 @@ {% elif loop.index0 != 0 %} - -
Ce message est le top comment
+ + + {% endif %} - {% endfor %}
Le commentaire à cet endroit est actuellement utilisé comme en-tête.
{% endmacro %} + +{# Thread leader widget: this widget expands to a single-message thread which + can show more text when called. This is intended for programs and similar + objects which display metadata before description and comments. + + leader: Posts's top comment (actual rendering is delegated to caller) #} + +{% macro thread_leader(leader) %} + + {# Empty line to get normal background (instead of alternate one) #} + + + + + +
{{ widget_user.profile(leader.author) }}{{ caller() }}
+{% endmacro %}