Add report categories

This commit is contained in:
rubenwardy
2025-08-26 15:46:41 +01:00
parent 8db72faf3c
commit 8d1268bd19
6 changed files with 99 additions and 6 deletions

View File

@@ -19,10 +19,10 @@ from flask_babel import lazy_gettext
from flask_login import current_user
from flask_wtf import FlaskForm
from werkzeug.utils import redirect
from wtforms import TextAreaField, SubmitField, URLField, StringField, RadioField
from wtforms import TextAreaField, SubmitField, URLField, StringField, RadioField, SelectField
from wtforms.validators import InputRequired, Length, Optional
from app.models import User, UserRank, Report, db, AuditSeverity, Thread
from app.models import User, UserRank, Report, db, AuditSeverity, Thread, ReportCategory
from app.tasks.webhooktasks import post_discord_webhook
from app.utils import is_no, abs_url_samesite, normalize_line_endings, rank_required, add_audit_log, abs_url_for, \
add_replies, random_string
@@ -31,6 +31,8 @@ bp = Blueprint("report", __name__)
class ReportForm(FlaskForm):
category = SelectField(lazy_gettext("Category"), [InputRequired()], choices=ReportCategory.choices(with_none=True), coerce=ReportCategory.coerce)
url = URLField(lazy_gettext("URL"), [Optional()])
title = StringField(lazy_gettext("Subject / Title"), [InputRequired(), Length(10, 300)])
message = TextAreaField(lazy_gettext("Message"), [Optional(), Length(0, 10000)], filters=[normalize_line_endings])
@@ -50,8 +52,12 @@ def report():
form = ReportForm(formdata=request.form) if current_user.is_authenticated else None
if form and request.method == "GET":
try:
form.category.data = ReportCategory.coerce(request.args.get("category"))
except KeyError:
pass
form.url.data = url
form.message.data = request.args.get("message", "")
form.title.data = request.args.get("title", "")
if form and form.validate_on_submit():
report = Report()

View File

@@ -13,8 +13,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from flask_babel import LazyString
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy_searchable import make_searchable
@@ -130,6 +129,58 @@ class AuditLogEntry(db.Model):
raise Exception("Permission {} is not related to audit log entries".format(perm.name))
class ReportCategory(enum.Enum):
ACCOUNT_DELETION = "account_deletion"
COPYRIGHT = "copyright"
USER_CONDUCT = "user_conduct"
ILLEGAL_HARMFUL = "illegal_harmful"
APPEAL = "appeal"
OTHER = "other"
def __str__(self):
return self.name
@property
def title(self) -> LazyString:
if self == ReportCategory.ACCOUNT_DELETION:
return lazy_gettext("Account deletion")
elif self == ReportCategory.COPYRIGHT:
return lazy_gettext("Copyright infringement / DMCA")
elif self == ReportCategory.USER_CONDUCT:
return lazy_gettext("User behaviour, bullying, or abuse")
elif self == ReportCategory.ILLEGAL_HARMFUL:
return lazy_gettext("Illegal or harmful content")
elif self == ReportCategory.APPEAL:
return lazy_gettext("Appeal")
elif self == ReportCategory.OTHER:
return lazy_gettext("Other")
else:
raise Exception("Unknown report category")
@classmethod
def get(cls, name):
try:
return ReportCategory[name.upper()]
except KeyError:
return None
@classmethod
def choices(cls, with_none):
ret = [(choice, choice.title) for choice in cls]
if with_none:
ret.insert(0, (None, ""))
return ret
@classmethod
def coerce(cls, item):
if item is None or (isinstance(item, str) and item.upper() == "NONE"):
return None
return item if type(item) == ReportCategory else ReportCategory[item.upper()]
class Report(db.Model):
id = db.Column(db.String(24), primary_key=True)
@@ -141,6 +192,7 @@ class Report(db.Model):
thread_id = db.Column(db.Integer, db.ForeignKey("thread.id"), nullable=True)
thread = db.relationship("Thread", foreign_keys=[thread_id])
category = db.Column(db.Enum(ReportCategory), nullable=False)
url = db.Column(db.String, nullable=True)
title = db.Column(db.Unicode(300), nullable=False)
message = db.Column(db.UnicodeText, nullable=False)

View File

@@ -28,6 +28,7 @@
<form method="POST" action="" enctype="multipart/form-data">
{{ form.hidden_tag() }}
{{ render_field(form.category) }}
{{ render_field(form.url) }}
{{ render_field(form.title) }}
{{ render_field(form.message, class_="m-0", fieldclass="form-control markdown", data_enter_submit="1") }}

View File

@@ -38,6 +38,12 @@
</div>
<aside class="col-md-3 info-sidebar">
<dl>
<dt>Category</dt>
<dd>
{{ report.category.title }}
</dd>
</dl>
<dl>
<dt>URL</dt>
<dd>

View File

@@ -87,7 +87,7 @@
{{ _("Please raise a report to request account deletion.") }}
</p>
<p>
<a class="btn btn-secondary" href="{{ url_for('report.report', url=url_current(), message="Delete my account") }}">{{ _("Report") }}</a>
<a class="btn btn-secondary" href="{{ url_for('report.report', url=url_current(), title='Delete my account', category='account_deletion') }}">{{ _("Report") }}</a>
</p>
{% endif %}

View File

@@ -0,0 +1,28 @@
"""empty message
Revision ID: 1e08d7e4c15d
Revises: 9689a71efe88
Create Date: 2025-08-26 14:43:30.501823
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '1e08d7e4c15d'
down_revision = '9689a71efe88'
branch_labels = None
depends_on = None
def upgrade():
status = postgresql.ENUM('ACCOUNT_DELETION', 'COPYRIGHT', 'USER_CONDUCT', 'ILLEGAL_HARMFUL', 'APPEAL', 'OTHER', name='reportcategory')
status.create(op.get_bind())
with op.batch_alter_table('report', schema=None) as batch_op:
batch_op.add_column(sa.Column('category', sa.Enum('ACCOUNT_DELETION', 'COPYRIGHT', 'USER_CONDUCT', 'ILLEGAL_HARMFUL', 'APPEAL', 'OTHER', name='reportcategory'), nullable=False, server_default="OTHER"))
def downgrade():
with op.batch_alter_table('report', schema=None) as batch_op:
batch_op.drop_column('category')