Class: Moderate::Services::IntakeNotice

Inherits:
Object
  • Object
show all
Defined in:
lib/moderate/services/intake_notice.rb

Overview

IntakeNotice — persistence path for a public DSA Article 16 notice.

This is the regulator-facing intake: the “Report illegal content (EU)” form you see at the bottom of X / YouTube / Reddit, open to ANYONE (not just logged-in users), by electronic means, with a confirmation of receipt. It is legally distinct from the in-app “Report” button:

- it carries a `legal_reason` from the DSA statement-of-reasons taxonomy
  (the law's vocabulary) rather than a community `category` (your rules);
- the notifier may be anonymous (a name+email, not a User);
- it requires the exact electronic location (URL) of the content — Art.16(2)(b);
- it requires a good-faith attestation — Art.16(2)(d).

See: eur-lex.europa.eu/eli/reg/2022/2065/oj (Article 16).

A notice is NOT a fourth table: it’s a ‘Moderate::Report` with `intake_kind: “dsa”`, so it shares the same queue, evidence snapshot, appeal window, statement-of-reasons path, and Art. 24 transparency counters as an in-app report. One queue, one decision workflow, two front doors. This service builds that notice-kind Report and hands it to IntakeReport for the shared persistence + side effects, then emits the notice-specific `notice_received` event whose delivery boolean gates the Art. 16(4) “confirmation of receipt”.

HOST-AGNOSTIC: no concrete content type is named. The URL is resolved to a reportable record (if the host can) by the Report model’s snapshot logic; this service only owns intake orchestration and the legal-email gating.

Defined Under Namespace

Classes: NotifierRecipient

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes:, reporter: nil) ⇒ IntakeNotice

Returns a new instance of IntakeNotice.

Parameters:

  • attributes (Hash)

    the public-form attributes, already strong-param’d by the controller: notifier_name, notifier_email, good_faith_confirmed, legal_reason, legal_country_code, subject_url(s), content_type, message (the substantiated explanation), anonymous, reported_account_identifier.

  • reporter (user_class, nil) (defaults to: nil)

    the submitter IF they happened to be logged in (the form is public, so usually nil).



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/moderate/services/intake_notice.rb', line 36

def initialize(attributes:, reporter: nil)
  # Force the DSA shape regardless of what the form posted: a public notice is
  # always intake_kind "dsa". We default the community `category` to a neutral
  # "illegal_content" because the column is NOT NULL and a notice's real
  # taxonomy lives in `legal_reason` — the category is just the bucket that
  # keeps a notice in the same queue as community reports.
  @report = Moderate::Report.new(attributes)
  @report.assign_attributes(
    intake_kind: "dsa",
    category: @report.category.presence || "illegal_content"
  )
  @report.skip_received_notice = true
  @reporter = reporter
end

Instance Attribute Details

#reportObject (readonly)

Returns the value of attribute report.



51
52
53
# File 'lib/moderate/services/intake_notice.rb', line 51

def report
  @report
end

Instance Method Details

#saveObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/moderate/services/intake_notice.rb', line 53

def save
  # Reuse the shared intake (save + acknowledge! + audit). We pass the report
  # straight through — it already carries the notice attributes and the forced
  # DSA shape. The reporter is the actor when present (a logged-in submitter);
  # for a truly anonymous notice the actor is nil, which the event envelope
  # handles (system/no-actor events are normal).
  intake = IntakeReport.new(
    report: report,
    reporter: reporter,
    reportable: report.reportable,
    reported_field: report.reported_field,
    actor: reporter
  )
  return false unless intake.save

  deliver_confirmation_of_receipt
  true
end