Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
139 lines
4.1 KiB
Elixir
139 lines
4.1 KiB
Elixir
defmodule TarakanWeb.ExploreLive do
|
|
use TarakanWeb, :live_view
|
|
|
|
alias Tarakan.Activity
|
|
alias Tarakan.Infestations
|
|
alias Tarakan.Reputation
|
|
alias TarakanWeb.Presence
|
|
|
|
@wire_limit 50
|
|
# A search sweeps a wider slice of history than the visible window.
|
|
@search_scan_limit 200
|
|
@presence_topic "explore:observers"
|
|
|
|
# Product language: Reports / Checks. Wire kinds stay :scan / :verdict internally.
|
|
@kinds %{
|
|
"all" => nil,
|
|
"registrations" => :registration,
|
|
"reports" => :scan,
|
|
"checks" => :verdict,
|
|
"comments" => :comment
|
|
}
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
if connected?(socket) do
|
|
Activity.subscribe()
|
|
Reputation.subscribe()
|
|
Phoenix.PubSub.subscribe(Tarakan.PubSub, @presence_topic)
|
|
{:ok, _ref} = Presence.track(self(), @presence_topic, socket.id, %{})
|
|
end
|
|
|
|
{:ok,
|
|
socket
|
|
|> assign(:page_title, "Explore")
|
|
|> assign(
|
|
:meta_description,
|
|
"Public record: Reports, Checks, registrations, discussion."
|
|
)
|
|
|> assign(:canonical_path, ~p"/explore")
|
|
|> assign(:kind, "all")
|
|
|> assign(:query, "")
|
|
|> assign(:watcher_count, watcher_count())
|
|
|> assign(:hot_findings, Activity.hot_findings())
|
|
|> assign(:infestations, Infestations.list_infestations(min_repos: 2, days: 30, limit: 5))
|
|
|> load_wire()}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("filter", %{"kind" => kind}, socket) when is_map_key(@kinds, kind) do
|
|
{:noreply, socket |> assign(:kind, kind) |> load_wire()}
|
|
end
|
|
|
|
def handle_event("search", params, socket) do
|
|
query = params |> Map.get("q", "") |> String.trim()
|
|
{:noreply, socket |> assign(:query, query) |> load_wire()}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info({:activity, entry}, socket) do
|
|
if matches?(entry, socket.assigns.kind, socket.assigns.query) do
|
|
{:noreply, stream_insert(socket, :wire, entry, at: 0, limit: @wire_limit)}
|
|
else
|
|
{:noreply, socket}
|
|
end
|
|
end
|
|
|
|
def handle_info({:vote_changed, "canonical_finding", _id}, socket) do
|
|
{:noreply, assign(socket, :hot_findings, Activity.hot_findings())}
|
|
end
|
|
|
|
def handle_info({:vote_changed, _subject_type, _id}, socket), do: {:noreply, socket}
|
|
|
|
def handle_info(%Phoenix.Socket.Broadcast{event: "presence_diff"}, socket) do
|
|
{:noreply, assign(socket, :watcher_count, watcher_count())}
|
|
end
|
|
|
|
defp load_wire(socket) do
|
|
%{kind: kind, query: query} = socket.assigns
|
|
scan_limit = if query == "", do: @wire_limit, else: @search_scan_limit
|
|
|
|
# Scope the kind in the query so a rare kind returns its own `scan_limit`
|
|
# rows instead of being crowded out of the merged newest-N window.
|
|
entries =
|
|
scan_limit
|
|
|> Activity.recent(verified_only: false, kind: Map.fetch!(@kinds, kind))
|
|
|> Enum.filter(&matches_query?(&1, query))
|
|
|> Enum.take(@wire_limit)
|
|
|
|
stream(socket, :wire, entries, reset: true)
|
|
end
|
|
|
|
defp matches?(entry, kind, query) do
|
|
matches_kind?(entry, kind) and matches_query?(entry, query)
|
|
end
|
|
|
|
defp matches_kind?(_entry, "all"), do: true
|
|
defp matches_kind?(entry, kind), do: entry.kind == Map.fetch!(@kinds, kind)
|
|
|
|
defp matches_query?(_entry, ""), do: true
|
|
|
|
defp matches_query?(entry, query) do
|
|
haystack =
|
|
[
|
|
Map.get(entry, :handle),
|
|
Map.get(entry, :finding_title),
|
|
entry.host,
|
|
"#{entry.owner}/#{entry.name}"
|
|
]
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.join(" ")
|
|
|> String.downcase()
|
|
|
|
String.contains?(haystack, String.downcase(query))
|
|
end
|
|
|
|
defp watcher_count do
|
|
@presence_topic |> Presence.list() |> map_size()
|
|
end
|
|
|
|
# Reviews and verdicts live on the security tab; comments on the finding
|
|
# page; a registration points at the repository itself.
|
|
defp wire_entry_path(%{kind: :registration} = entry) do
|
|
TarakanWeb.RepositoryPaths.repository_path(entry)
|
|
end
|
|
|
|
defp wire_entry_path(%{kind: :comment} = entry) do
|
|
"/findings/#{entry.finding_public_id}"
|
|
end
|
|
|
|
defp wire_entry_path(entry) do
|
|
TarakanWeb.RepositoryPaths.repository_security_path(entry)
|
|
end
|
|
|
|
defp ledger_time(%DateTime{} = datetime) do
|
|
Calendar.strftime(datetime, "%Y-%m-%d %H:%M")
|
|
end
|
|
|
|
defp filter_active?(current, value), do: current == value
|
|
end
|