Browse Source

Require a reason when tagging comment as "malice"

merge-requests/40/head
Deimos 6 years ago
parent
commit
735a6e5556
  1. 24
      tildes/alembic/versions/1ade2bf86efc_comment_tags_add_reason_column.py
  2. 15
      tildes/static/js/behaviors/comment-tag-button.js
  3. 10
      tildes/tildes/enums.py
  4. 13
      tildes/tildes/models/comment/comment_tag.py
  5. 3
      tildes/tildes/schemas/comment.py
  6. 10
      tildes/tildes/templates/macros/comments.jinja2
  7. 5
      tildes/tildes/views/api/web/comment.py

24
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")

15
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);
});

10
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."""

13
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:

3
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."""

10
tildes/tildes/templates/macros/comments.jinja2

@ -104,7 +104,7 @@
<span class="comment-tag-count">
{{ 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 %}
</span>
</li>
@ -237,7 +237,13 @@
<template id="comment-tag-options">
<menu class="comment-tag-buttons">
{% for tag in options %}
<li><a class="btn-comment-tag btn-comment-tag-{{ tag.name|lower }}">{{ tag.name|lower }}</a></li>
<li>
<a class="btn-comment-tag btn-comment-tag-{{ tag.name|lower }}"
{% if tag.reason_prompt %}
data-js-reason-prompt="{{ tag.reason_prompt }}"
{% endif %}
>{{ tag.name|lower }}</a>
</li>
{% endfor %}
</ul>
</template>

5
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:

Loading…
Cancel
Save