From 735a6e5556f0177a9f97af15aacf8f53233309a4 Mon Sep 17 00:00:00 2001 From: Deimos Date: Tue, 18 Sep 2018 15:54:20 -0600 Subject: [PATCH] Require a reason when tagging comment as "malice" --- ...2bf86efc_comment_tags_add_reason_column.py | 24 +++++++++++++++++++ .../static/js/behaviors/comment-tag-button.js | 15 ++++++++++++ tildes/tildes/enums.py | 10 ++++++++ tildes/tildes/models/comment/comment_tag.py | 13 ++++++++-- tildes/tildes/schemas/comment.py | 3 ++- .../tildes/templates/macros/comments.jinja2 | 10 ++++++-- tildes/tildes/views/api/web/comment.py | 5 ++-- 7 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 tildes/alembic/versions/1ade2bf86efc_comment_tags_add_reason_column.py diff --git a/tildes/alembic/versions/1ade2bf86efc_comment_tags_add_reason_column.py b/tildes/alembic/versions/1ade2bf86efc_comment_tags_add_reason_column.py new file mode 100644 index 0000000..206f181 --- /dev/null +++ b/tildes/alembic/versions/1ade2bf86efc_comment_tags_add_reason_column.py @@ -0,0 +1,24 @@ +"""comment_tags: add reason column + +Revision ID: 1ade2bf86efc +Revises: 1996feae620d +Create Date: 2018-09-18 20:44:19.357105 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "1ade2bf86efc" +down_revision = "1996feae620d" +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column("comment_tags", sa.Column("reason", sa.Text(), nullable=True)) + + +def downgrade(): + op.drop_column("comment_tags", "reason") diff --git a/tildes/static/js/behaviors/comment-tag-button.js b/tildes/static/js/behaviors/comment-tag-button.js index 4c354f8..d18f1e0 100644 --- a/tildes/static/js/behaviors/comment-tag-button.js +++ b/tildes/static/js/behaviors/comment-tag-button.js @@ -31,14 +31,29 @@ $.onmount('[data-js-comment-tag-button]', function() { tagOptionActive = true; } + var tagPrompt = tag.getAttribute("data-js-reason-prompt"); + if (tagOptionActive) { tag.className += " btn btn-used"; tag.setAttribute('data-ic-delete-from', tagURL + tagName); + + // if the tag requires a prompt, confirm that they want to remove it + // (since we don't want to accidentally lose the reason they typed in) + if (tagPrompt) { + tag.setAttribute("data-ic-confirm", "Remove your "+tagName+" tag?"); + } + $(tag).on('after.success.ic', function(evt) { Tildes.removeUserTag(commentID, evt.target.textContent); }); } else { tag.setAttribute('data-ic-put-to', tagURL + tagName); + + if (tagPrompt) { + tag.setAttribute("data-ic-prompt", tagPrompt); + tag.setAttribute("data-ic-prompt-name", "reason"); + } + $(tag).on('after.success.ic', function(evt) { Tildes.addUserTag(commentID, evt.target.textContent); }); diff --git a/tildes/tildes/enums.py b/tildes/tildes/enums.py index 20a9714..f8d566c 100644 --- a/tildes/tildes/enums.py +++ b/tildes/tildes/enums.py @@ -3,6 +3,8 @@ """Contains Enum classes.""" +from typing import Optional + import enum @@ -43,6 +45,14 @@ class CommentTagOption(enum.Enum): OFFTOPIC = enum.auto() MALICE = enum.auto() + @property + def reason_prompt(self) -> Optional[str]: + """Return the reason prompt for this tag, if any.""" + if self.name == "MALICE": + return "Why is this malicious? (required, will only be visible to admins)" + + return None + class LogEventType(enum.Enum): """Enum for the types of events stored in logs.""" diff --git a/tildes/tildes/models/comment/comment_tag.py b/tildes/tildes/models/comment/comment_tag.py index 9783fe4..a4e8413 100644 --- a/tildes/tildes/models/comment/comment_tag.py +++ b/tildes/tildes/models/comment/comment_tag.py @@ -4,8 +4,9 @@ """Contains the CommentTag class.""" from datetime import datetime +from typing import Optional -from sqlalchemy import Column, ForeignKey, Integer, REAL, TIMESTAMP +from sqlalchemy import Column, ForeignKey, Integer, REAL, Text, TIMESTAMP from sqlalchemy.dialects.postgresql import ENUM from sqlalchemy.orm import backref, relationship from sqlalchemy.sql.expression import text @@ -34,18 +35,26 @@ class CommentTag(DatabaseModel): TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()") ) weight: float = Column(REAL, nullable=False, server_default=text("1.0")) + reason: Optional[str] = Column(Text) comment: Comment = relationship(Comment, backref=backref("tags", lazy=False)) user: User = relationship(User, lazy=False, innerjoin=True) def __init__( - self, comment: Comment, user: User, tag: CommentTagOption, weight: float + self, + comment: Comment, + user: User, + tag: CommentTagOption, + weight: float, + reason: Optional[str] = None, ) -> None: """Add a new tag to a comment.""" + # pylint: disable=too-many-arguments self.comment_id = comment.comment_id self.user_id = user.user_id self.tag = tag self.weight = weight + self.reason = reason @property def name(self) -> str: diff --git a/tildes/tildes/schemas/comment.py b/tildes/tildes/schemas/comment.py index 130787b..f215d80 100644 --- a/tildes/tildes/schemas/comment.py +++ b/tildes/tildes/schemas/comment.py @@ -6,7 +6,7 @@ from marshmallow import Schema from tildes.enums import CommentTagOption -from tildes.schemas.fields import Enum, ID36, Markdown +from tildes.schemas.fields import Enum, ID36, Markdown, SimpleString class CommentSchema(Schema): @@ -25,6 +25,7 @@ class CommentTagSchema(Schema): """Marshmallow schema for comment tags.""" name = Enum(CommentTagOption) + reason = SimpleString(missing=None) class Meta: """Always use strict checking so error handlers are invoked.""" diff --git a/tildes/tildes/templates/macros/comments.jinja2 b/tildes/tildes/templates/macros/comments.jinja2 index afa24b1..1560e1e 100644 --- a/tildes/tildes/templates/macros/comments.jinja2 +++ b/tildes/tildes/templates/macros/comments.jinja2 @@ -104,7 +104,7 @@ {{ weight }}: {% for tag in comment.tags if tag.name == tag_name %} - {{ username_linked(tag.user.username) }} ({{ tag.weight }}) + {{ username_linked(tag.user.username) }} ({{ tag.weight }}{{ ' "%s"' % tag.reason if tag.reason else '' }}) {% endfor %} @@ -237,7 +237,13 @@ diff --git a/tildes/tildes/views/api/web/comment.py b/tildes/tildes/views/api/web/comment.py index fddca33..4ef321b 100644 --- a/tildes/tildes/views/api/web/comment.py +++ b/tildes/tildes/views/api/web/comment.py @@ -253,7 +253,8 @@ def delete_vote_comment(request: Request) -> dict: renderer="comment_contents.jinja2", ) @use_kwargs(CommentTagSchema(only=("name",)), locations=("matchdict",)) -def put_tag_comment(request: Request, name: CommentTagOption) -> Response: +@use_kwargs(CommentTagSchema(only=("reason",))) +def put_tag_comment(request: Request, name: CommentTagOption, reason: str) -> Response: """Add a tag to a comment.""" comment = request.context @@ -263,7 +264,7 @@ def put_tag_comment(request: Request, name: CommentTagOption) -> Response: if weight is None: weight = request.registry.settings["tildes.default_user_comment_tag_weight"] - tag = CommentTag(comment, request.user, name, weight) + tag = CommentTag(comment, request.user, name, weight, reason) request.db_session.add(tag) try: