|
# retoor <retoor@molodetz.nl>
|
|
|
|
import logging
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, Request
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
from devplacepy.database import (
|
|
REPORTABLE_TARGETS,
|
|
REPORT_SEVERITIES,
|
|
REPORT_STATUSES,
|
|
report_reason_options,
|
|
)
|
|
from devplacepy.dependencies import json_or_form
|
|
from devplacepy.models import ReportForm
|
|
from devplacepy.responses import action_result, json_error, respond
|
|
from devplacepy.schemas import ReportListOut, ReportReasonsOut
|
|
from devplacepy.seo import base_seo_context, site_url, website_schema
|
|
from devplacepy.services.audit import record as audit
|
|
from devplacepy.services.moderation import queue, sla
|
|
from devplacepy.utils import create_notification, get_current_user, require_user
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/reasons")
|
|
async def report_reasons(request: Request):
|
|
base = site_url(request)
|
|
return respond(
|
|
request,
|
|
"report_reasons.html",
|
|
{
|
|
**base_seo_context(
|
|
request,
|
|
title="Report reasons",
|
|
description="The categories DevPlace accepts content reports under.",
|
|
breadcrumbs=[
|
|
{"name": "Home", "url": "/feed"},
|
|
{"name": "Report reasons", "url": "/reports/reasons"},
|
|
],
|
|
schemas=[website_schema(base)],
|
|
),
|
|
"request": request,
|
|
"user": get_current_user(request),
|
|
"reasons": report_reason_options(),
|
|
"severities": list(REPORT_SEVERITIES),
|
|
},
|
|
model=ReportReasonsOut,
|
|
)
|
|
|
|
|
|
@router.get("/mine", response_class=HTMLResponse)
|
|
async def my_reports(request: Request, status: str = "", page: int = 1):
|
|
user = require_user(request)
|
|
if status not in REPORT_STATUSES:
|
|
status = ""
|
|
reports, pagination = queue.list_reports(
|
|
status=status, reporter_uid=user["uid"], page=page
|
|
)
|
|
base = site_url(request)
|
|
seo_ctx = base_seo_context(
|
|
request,
|
|
title="Your reports",
|
|
description="The reports you filed and the outcome of each.",
|
|
robots="noindex,nofollow",
|
|
breadcrumbs=[
|
|
{"name": "Home", "url": "/feed"},
|
|
{"name": "Your reports", "url": "/reports/mine"},
|
|
],
|
|
schemas=[website_schema(base)],
|
|
)
|
|
return respond(
|
|
request,
|
|
"reports_mine.html",
|
|
{
|
|
**seo_ctx,
|
|
"request": request,
|
|
"user": user,
|
|
"reports": reports,
|
|
"pagination": pagination,
|
|
"status": status,
|
|
"reasons": report_reason_options(),
|
|
},
|
|
model=ReportListOut,
|
|
)
|
|
|
|
|
|
@router.post("/{target_type}/{target_uid}")
|
|
async def submit_report(
|
|
request: Request,
|
|
target_type: str,
|
|
target_uid: str,
|
|
data: Annotated[ReportForm, Depends(json_or_form(ReportForm))],
|
|
):
|
|
user = require_user(request)
|
|
if target_type not in REPORTABLE_TARGETS:
|
|
return json_error(400, "Unknown report target")
|
|
owner_uid = queue.owner_uid_for(target_type, target_uid)
|
|
if owner_uid and owner_uid == user["uid"]:
|
|
return json_error(400, "You cannot report your own content")
|
|
report = queue.raise_report(
|
|
target_type=target_type,
|
|
target_uid=target_uid,
|
|
reporter_uid=user["uid"],
|
|
reason=data.reason,
|
|
detail=data.detail,
|
|
origin="member",
|
|
)
|
|
if not report:
|
|
return json_error(400, "Report could not be filed")
|
|
hours = sla.sla_hours()
|
|
logger.info(
|
|
f"{user['username']} reported {target_type} {target_uid} as {data.reason}"
|
|
)
|
|
audit.record(
|
|
request,
|
|
"report.create",
|
|
user=user,
|
|
target_type=target_type,
|
|
target_uid=target_uid,
|
|
metadata={"reason": data.reason, "severity": report["severity"]},
|
|
summary=f"{user['username']} reported {target_type} {target_uid} as {data.reason}",
|
|
links=[audit.target(target_type, target_uid)],
|
|
)
|
|
create_notification(
|
|
user["uid"],
|
|
"moderation",
|
|
f"Report received. A moderator reviews it within {hours} hours.",
|
|
user["uid"],
|
|
"/reports/mine",
|
|
)
|
|
return action_result(
|
|
request,
|
|
"/reports/mine",
|
|
data={
|
|
"uid": report["uid"],
|
|
"status": report["status"],
|
|
"severity": report["severity"],
|
|
"sla_hours": hours,
|
|
},
|
|
)
|