Add report categories
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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") }}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
|
||||
28
migrations/versions/1e08d7e4c15d_.py
Normal file
28
migrations/versions/1e08d7e4c15d_.py
Normal 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')
|
||||
Reference in New Issue
Block a user