Class: Moderate::Services::ResolveAppeal

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

Overview

ResolveAppeal — the human decision on a DSA Article 20 appeal, behind ‘appeal.uphold!` / `appeal.reject!`.

Art. 20 demands appeals be decided “in a timely, non-discriminatory, diligent and non-arbitrary manner” and crucially “NOT SOLELY ON THE BASIS OF AUTOMATED MEANS.” That last clause is why there is no auto-decide path here at all: ‘uphold!`/`reject!` REQUIRE a `by:` moderator and a `note:` — a human and a reason — and the model column for the moderator (`resolved_by`) makes the human decider part of the permanent record. See: eur-lex.europa.eu/eli/reg/2022/2065/oj (Article 20).

Same atomic discipline as ResolveReport: the transition runs under a row lock, re-checks ‘open?` inside the lock (so two moderators can’t both decide the same appeal), and the notification happens after the lock releases.

NOTE on enforcement: upholding an appeal means the ORIGINAL decision was wrong and should be reversed (Art. 20 outcomes must be acted on). Reversal is host-specific — re-publishing content, lifting a ban — and the gem can’t know how to undo an arbitrary host action. So this service records the upheld outcome and emits ‘appeal_decision`; the host wires the actual reversal off that event (or off its `audit` hook). We document this rather than pretend a generic “un-remove” exists.

Instance Method Summary collapse

Constructor Details

#initialize(appeal, by:) ⇒ ResolveAppeal

Returns a new instance of ResolveAppeal.



28
29
30
31
# File 'lib/moderate/services/resolve_appeal.rb', line 28

def initialize(appeal, by:)
  @appeal = appeal
  @moderator = by
end

Instance Method Details

#reject!(note:) ⇒ Object



37
38
39
# File 'lib/moderate/services/resolve_appeal.rb', line 37

def reject!(note:)
  transition!("rejected", note)
end

#uphold!(note:) ⇒ Object



33
34
35
# File 'lib/moderate/services/resolve_appeal.rb', line 33

def uphold!(note:)
  transition!("upheld", note)
end