Coverage for app / backend / src / couchers / servicers / reporting.py: 100%
21 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 14:14 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 14:14 +0000
1import grpc
2from google.protobuf import empty_pb2
3from sqlalchemy import select
4from sqlalchemy.orm import Session
6from couchers.context import CouchersContext
7from couchers.event_log import log_event
8from couchers.models import ContentReport, User
9from couchers.proto import reporting_pb2, reporting_pb2_grpc
10from couchers.sql import username_or_id
11from couchers.tasks import send_content_report_email
14class Reporting(reporting_pb2_grpc.ReportingServicer):
15 def Report(self, request: reporting_pb2.ReportReq, context: CouchersContext, session: Session) -> empty_pb2.Empty:
16 # note no filtering on visibility
17 author_user = session.execute(select(User).where(username_or_id(request.author_user))).scalar_one_or_none()
19 if not author_user:
20 context.abort_with_error_code(grpc.StatusCode.NOT_FOUND, "user_not_found")
22 content_report = ContentReport(
23 reporting_user_id=context.user_id,
24 reason=request.reason,
25 description=request.description,
26 content_ref=request.content_ref,
27 author_user_id=author_user.id,
28 user_agent=request.user_agent,
29 page=request.page,
30 )
32 session.add(content_report)
33 session.flush()
35 send_content_report_email(session, content_report)
37 log_event(
38 context,
39 session,
40 "content.reported",
41 {
42 "author_user_id": author_user.id,
43 "reason": request.reason,
44 "content_ref": request.content_ref,
45 "page": request.page,
46 },
47 )
49 return empty_pb2.Empty()