defmodule GitGudWeb.RepoLive.Moderation do
@moduledoc """
Repo admins' moderation page: reports about content in this repo, and
bans that apply to it.
An org-wide ban set by the owning org also stops someone here, but is
listed and lifted on the org's own page — a repo admin shouldn't be
able to undo a decision made above them.
"""
use GitGudWeb, :live_view
import GitGudWeb.ModerationAdminComponents
alias GitGud.Moderation
alias GitGud.Reports
alias GitGud.Repositories
alias GitGud.Repositories.Storage
alias GitGudWeb.ModerationActions
@impl true
def mount(%{"owner" => owner, "name" => name}, _session, socket) do
repo =
Repositories.get_repository_by_path!(owner, name)
|> GitGud.Repo.preload([:owner, :organization])
user = socket.assigns.current_scope.user
if admin?(user, repo) do
{:ok,
socket
|> assign(:repo, repo)
|> assign(:handle, Storage.repo_handle(repo))
|> assign(:scope, repo)
|> assign(:moderator, user)
|> GitGudWeb.RepoLive.Header.assign_chrome(repo)
|> assign(:page_title, "Moderation — #{repo.name}")
|> reload()}
else
{:ok,
socket
|> put_flash(:error, "Admins only.")
|> push_navigate(to: ~p"/r/#{Storage.repo_handle(repo)}/#{repo.name}")}
end
end
defp admin?(user, %{owner_id: uid, organization_id: nil}), do: user.id == uid
defp admin?(user, %{organization: %{} = org}),
do: GitGud.Organizations.org_admin?(org, user)
defp admin?(_user, _repo), do: false
defp reload(socket) do
repo = socket.assigns.repo
reports = Reports.list_open_for_repo(repo)
socket
|> assign(:reports, reports)
|> assign(:previews, Map.new(reports, &{&1.id, Reports.preview(&1)}))
|> assign(:bans, Moderation.list_bans(repo))
end
@impl true
def handle_event("dismiss_report", %{"id" => id}, socket),
do: {:noreply, ModerationActions.dismiss_report(socket, id, &reload/1)}
def handle_event("action_report", %{"id" => id}, socket),
do: {:noreply, ModerationActions.action_report(socket, id, &reload/1)}
def handle_event("moderate_report", %{"id" => id}, socket),
do: {:noreply, ModerationActions.moderate_report(socket, id, &reload/1)}
def handle_event("ban_reported_author", %{"id" => id}, socket),
do: {:noreply, ModerationActions.ban_reported_author(socket, id, &reload/1)}
def handle_event("ban_user", params, socket),
do: {:noreply, ModerationActions.ban_user(socket, params, &reload/1)}
def handle_event("lift_ban", %{"id" => id}, socket),
do: {:noreply, ModerationActions.lift_ban(socket, id, &reload/1)}
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="space-y-6 max-w-3xl">
<GitGudWeb.RepoLive.Header.header
repo={@repo}
handle={@handle}
current_scope={@current_scope}
has_packages?={@has_packages?}
can_admin?={@can_admin?}
latest_run={@latest_run}
open_pulls={@open_pulls}
/>
<header>
<h1 class="text-xl font-semibold">Moderation</h1>
<p :if={@repo.organization} class="text-sm opacity-70 mt-1">
{@repo.organization.handle} may also ban people across all its
repositories —
<.link
navigate={~p"/orgs/#{@repo.organization.handle}/settings/moderation"}
class="link link-hover"
>
its moderation page
</.link>
lists those.
</p>
</header>
<section>
<h2 class="font-semibold text-sm mb-2">
Open reports
<span :if={@reports != []} class="badge badge-sm badge-warning ml-1">
{length(@reports)}
</span>
</h2>
<.report_queue reports={@reports} previews={@previews} />
</section>
<section>
<h2 class="font-semibold text-sm mb-2">Ban someone</h2>
<.ban_form scope_label="repository" />
</section>
<section>
<h2 class="font-semibold text-sm mb-2">Bans</h2>
<.ban_list bans={@bans} scope_label="repository" />
</section>
</div>
</Layouts.app>
"""
end
end
neiam /gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Packages
⭐
Log in to mark this repository.
4.2 KiB · text
History
6280797