mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-22 14:02:24 +01:00
parent
a47e6e8998
commit
7f5656df08
66
app/blueprints/report/__init__.py
Normal file
66
app/blueprints/report/__init__.py
Normal file
@ -0,0 +1,66 @@
|
||||
# ContentDB
|
||||
# Copyright (C) 2022 rubenwardy
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# 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 import Blueprint, request, render_template, url_for
|
||||
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, BooleanField
|
||||
from wtforms.fields.html5 import URLField
|
||||
from wtforms.validators import InputRequired, Optional, Length
|
||||
|
||||
from app.models import User, UserRank
|
||||
from app.tasks.emails import send_user_email
|
||||
from app.tasks.webhooktasks import post_discord_webhook
|
||||
from app.utils import isYes, isNo
|
||||
|
||||
bp = Blueprint("report", __name__)
|
||||
|
||||
|
||||
class ReportForm(FlaskForm):
|
||||
url = URLField(lazy_gettext("URL"), [Optional()])
|
||||
message = TextAreaField(lazy_gettext("Message"), [InputRequired(), Length(10, 10000)])
|
||||
submit = SubmitField(lazy_gettext("Report"))
|
||||
|
||||
|
||||
@bp.route("/report/", methods=["GET", "POST"])
|
||||
def report():
|
||||
is_anon = not current_user.is_authenticated or not isNo(request.args.get("anon"))
|
||||
|
||||
form = ReportForm(formdata=request.form)
|
||||
if request.method == "GET":
|
||||
if "url" in request.args:
|
||||
form.url.data = request.args["url"]
|
||||
|
||||
if form.validate_on_submit():
|
||||
if current_user.is_authenticated:
|
||||
user_info = f"{current_user.username}"
|
||||
else:
|
||||
user_info = request.headers.get("X-Forwarded-For") or request.remote_addr
|
||||
|
||||
url = request.args.get("url") or form.url.data or "?"
|
||||
text = f"{url}\n\n{form.message.data}"
|
||||
|
||||
task = None
|
||||
for admin in User.query.filter_by(rank=UserRank.ADMIN).all():
|
||||
task = send_user_email.delay(admin.email, f"User report from {user_info}", text)
|
||||
|
||||
post_discord_webhook.delay(None if is_anon else current_user.username, f"**New Report**\n`{url}`\n\n{form.message.data}", True)
|
||||
|
||||
return redirect(url_for("tasks.check", id=task.id, r=url_for("homepage.home")))
|
||||
|
||||
return render_template("report/index.html", form=form, url=request.args.get("url"), is_anon=is_anon)
|
@ -9,7 +9,7 @@ toc: False
|
||||
* [Non-free Licenses](non_free)
|
||||
* [Why WTFPL is a terrible license](wtfpl)
|
||||
* [Ranks and Permissions](ranks_permissions)
|
||||
* [Reporting Content](reporting)
|
||||
* [Contact Us](contact_us)
|
||||
* [Top Packages Algorithm](top_packages)
|
||||
* [Featured Packages](featured)
|
||||
|
||||
|
14
app/flatpages/help/contact_us.md
Normal file
14
app/flatpages/help/contact_us.md
Normal file
@ -0,0 +1,14 @@
|
||||
title: Contact Us
|
||||
|
||||
## Reports
|
||||
|
||||
Please let us know if anything on the ContentDB violates our rules or any applicable
|
||||
laws.
|
||||
|
||||
We take copyright violation and other offenses very seriously.
|
||||
|
||||
<a href="/report/" class="btn btn-primary">Report</a>
|
||||
|
||||
## Other
|
||||
|
||||
<a href="https://rubenwardy.com/contact/" class="btn btn-primary">Contact the admin</a>
|
@ -1,8 +0,0 @@
|
||||
title: Reporting Content
|
||||
|
||||
Please let us know if anything on the ContentDB violates our rules or any applicable
|
||||
laws.
|
||||
|
||||
We take copyright violation and other offenses very seriously.
|
||||
|
||||
<a href="https://rubenwardy.com/contact/" class="btn btn-success">Contact</a>
|
@ -27,7 +27,7 @@ including ones not covered by this document, and to ban users who abuse this ser
|
||||
### 2.1. Acceptable Content
|
||||
|
||||
Sexually-orientated content is not permitted.
|
||||
If in doubt at what this means, [contact us by raising a report](/help/reporting/).
|
||||
If in doubt at what this means, [contact us by raising a report](/report/).
|
||||
|
||||
Mature content is permitted providing that it is labelled correctly.
|
||||
See [Content Flags](/help/content_flags/).
|
||||
@ -153,4 +153,4 @@ Doing so may result in temporary or permanent suspension from ContentDB.
|
||||
|
||||
## 7. Reporting Violations
|
||||
|
||||
See the [Reporting Content](/help/reporting/) page.
|
||||
Please click "Report" on the package page.
|
||||
|
@ -72,7 +72,7 @@ requested. See below.
|
||||
|
||||
## Removal Requests
|
||||
|
||||
Please [raise a report](https://content.minetest.net/help/reporting/) if you
|
||||
Please [raise a report](https://content.minetest.net/report/?anon=0) if you
|
||||
wish to remove your personal information.
|
||||
|
||||
ContentDB keeps a record of each username and forum topic on the forums,
|
||||
|
@ -124,6 +124,9 @@ class ThreadReply(db.Model):
|
||||
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
|
||||
|
||||
def get_url(self):
|
||||
return url_for('threads.view', id=self.thread.id) + "#reply-" + str(self.id)
|
||||
|
||||
def checkPerm(self, user, perm):
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
|
@ -15,7 +15,7 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from flask import render_template
|
||||
from flask import render_template, escape
|
||||
from flask_mail import Message
|
||||
from app import mail
|
||||
from app.models import Notification, db, EmailSubscription, User
|
||||
@ -86,7 +86,7 @@ def send_email_with_reason(email, subject, text, html, reason):
|
||||
msg = Message(subject, recipients=[email])
|
||||
|
||||
msg.body = text
|
||||
html = html or text
|
||||
html = html or f"<pre>{escape(text)}</pre>"
|
||||
msg.html = render_template("emails/base.html", subject=subject, content=html, reason=reason, sub=sub)
|
||||
mail.send(msg)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
from . import app, utils
|
||||
from .models import Permission, Package, PackageState, PackageRelease
|
||||
from .utils import abs_url_for, url_set_query, url_set_anchor
|
||||
from .utils import abs_url_for, url_set_query, url_set_anchor, url_current
|
||||
from flask_login import current_user
|
||||
from flask_babel import format_timedelta, gettext
|
||||
from urllib.parse import urlparse
|
||||
@ -17,7 +17,7 @@ def inject_debug():
|
||||
def inject_functions():
|
||||
check_global_perm = Permission.checkPerm
|
||||
return dict(abs_url_for=abs_url_for, url_set_query=url_set_query, url_set_anchor=url_set_anchor,
|
||||
check_global_perm=check_global_perm, get_headings=get_headings)
|
||||
check_global_perm=check_global_perm, get_headings=get_headings, url_current=url_current)
|
||||
|
||||
@app.context_processor
|
||||
def inject_todo():
|
||||
|
@ -234,7 +234,7 @@
|
||||
<li class="list-inline-item"><a href="{{ url_for('flatpage', path='policy_and_guidance') }}">{{ _("Policy and Guidance") }}</a></li>
|
||||
<li class="list-inline-item"><a href="{{ url_for('flatpage', path='help/api') }}">{{ _("API") }}</a></li>
|
||||
<li class="list-inline-item"><a href="{{ url_for('flatpage', path='privacy_policy') }}">{{ _("Privacy Policy") }}</a></li>
|
||||
<li class="list-inline-item"><a href="{{ url_for('flatpage', path='help/reporting') }}">{{ _("Report / DMCA") }}</a></li>
|
||||
<li class="list-inline-item"><a href="{{ url_for('report.report', url=url_current(True)) }}">{{ _("Report") }}</a></li>
|
||||
<li class="list-inline-item"><a href="https://monitor.rubenwardy.com/d/3ELzFy3Wz/contentdb">{{ _("Stats / Monitoring") }}</a></li>
|
||||
<li class="list-inline-item"><a href="{{ url_for('users.list_all') }}">{{ _("User List") }}</a></li>
|
||||
<li class="list-inline-item"><a href="https://github.com/minetest/contentdb">{{ _("Source Code") }}</a></li>
|
||||
|
@ -36,7 +36,7 @@
|
||||
{% endif %}
|
||||
|
||||
<a name="reply-{{ r.id }}" class="text-muted float-right"
|
||||
href="{{ url_for('threads.view', id=thread.id) }}#reply-{{ r.id }}">
|
||||
href="{{ r.get_url() }}">
|
||||
{{ r.created_at | datetime }}
|
||||
</a>
|
||||
</div>
|
||||
@ -48,10 +48,17 @@
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if current_user != r.author %}
|
||||
<a class="float-right btn-secondary btn-sm ml-2"
|
||||
title="{{ _('Report') }}"
|
||||
href="{{ url_for('report.report', url=r.get_url()) }}">
|
||||
<i class="fas fa-flag mr-1"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if current_user == thread.author and thread.review and thread.replies[0] == r %}
|
||||
<a class="float-right btn btn-primary btn-sm ml-2"
|
||||
href="{{ thread.review.package.getURL("packages.review") }}">
|
||||
href="{{ thread.review.package.getURL('packages.review') }}">
|
||||
<i class="fas fa-pen"></i>
|
||||
</a>
|
||||
{% elif r.checkPerm(current_user, "EDIT_REPLY") %}
|
||||
|
@ -473,13 +473,16 @@
|
||||
|
||||
<p class="mt-3">
|
||||
{% if package.approved and current_user != package.author %}
|
||||
<a class="float-right"
|
||||
href="{{ url_for('threads.new', pid=package.id) }}">
|
||||
{{ _("Report a problem with this listing") }}
|
||||
<a href="{{ url_for('report.report', url=url_current(True)) }}">
|
||||
<i class="fas fa-flag mr-1"></i>
|
||||
{{ _("Report") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if package.checkPerm(current_user, "EDIT_PACKAGE") or package.checkPerm(current_user, "APPROVE_NEW") %}
|
||||
<a class="float-right" href="{{ package.getURL("packages.audit") }}">
|
||||
{% if package.approved and current_user != package.author %}
|
||||
|
|
||||
{% endif %}
|
||||
<a href="{{ package.getURL("packages.audit") }}">
|
||||
{{ _("See audit log") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
32
app/templates/report/index.html
Normal file
32
app/templates/report/index.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ _("Report") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% from "macros/forms.html" import render_field, render_submit_field, render_checkbox_field %}
|
||||
<h1>{{ _("Report") }}</h1>
|
||||
|
||||
<form method="POST" action="" enctype="multipart/form-data">
|
||||
{{ form.hidden_tag() }}
|
||||
{% if url %}
|
||||
<p>
|
||||
URL: <code>{{ url }}</code>
|
||||
</p>
|
||||
{% else %}
|
||||
{{ render_field(form.url, hint=_("URL to the thing you're reporting")) }}
|
||||
{% endif %}
|
||||
{{ render_field(form.message, hint=_("What are you reporting? Why are you reporting it?")) }}
|
||||
{{ render_submit_field(form.submit) }}
|
||||
|
||||
<p class="mt-5 text-muted">
|
||||
{{ _("Reports will be shared with ContentDB stuff.") }}
|
||||
{% if is_anon %}
|
||||
{{ _("Only the admin will be able to see who made the report.") }}
|
||||
{% endif %}
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -21,7 +21,12 @@
|
||||
<i class="fas fa-tasks mr-1"></i>
|
||||
{{ _("To Do List") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<a class="btn btn-secondary float-right mr-3" href="{{ url_for('report.report', url=url_current(True)) }}">
|
||||
<i class="fas fa-flag mr-1"></i>
|
||||
{{ _("Report") }}
|
||||
</a>
|
||||
|
||||
{% if current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.MODERATOR) and user.email %}
|
||||
<a class="btn btn-secondary float-right mr-3" href="{{ url_for('admin.send_single_email', username=user.username) }}">
|
||||
|
@ -40,6 +40,15 @@ def abs_url_for(path, **kwargs):
|
||||
def abs_url(path):
|
||||
return urljoin(app.config["BASE_URL"], path)
|
||||
|
||||
def url_current(abs=False):
|
||||
args = MultiDict(request.args)
|
||||
dargs = dict(args.lists())
|
||||
dargs.update(request.view_args)
|
||||
if abs:
|
||||
return abs_url_for(request.endpoint, **dargs)
|
||||
else:
|
||||
return url_for(request.endpoint, **dargs)
|
||||
|
||||
def url_set_anchor(anchor):
|
||||
args = MultiDict(request.args)
|
||||
dargs = dict(args.lists())
|
||||
|
Loading…
Reference in New Issue
Block a user