analytics/lib/plausible/site/admin.ex

160 lines
4.2 KiB
Elixir

defmodule Plausible.SiteAdmin do
use Plausible.Repo
import Ecto.Query
def ordering(_schema) do
[desc: :inserted_at]
end
def search_fields(_schema) do
[
:domain,
members: [:name, :email]
]
end
def custom_index_query(_conn, _schema, query) do
from(r in query, preload: [memberships: :user])
end
def form_fields(_) do
[
domain: %{update: :readonly},
timezone: %{choices: Plausible.Timezones.options()},
public: nil,
stats_start_date: nil,
ingest_rate_limit_scale_seconds: %{
help_text: "Time scale for which events rate-limiting is calculated. Default: 60"
},
ingest_rate_limit_threshold: %{
help_text:
"Keep empty to disable rate limiting, set to 0 to bar all events. Any positive number sets the limit."
}
]
end
def index(_) do
[
domain: nil,
inserted_at: %{name: "Created at", value: &format_date(&1.inserted_at)},
timezone: nil,
public: nil,
owner: %{value: &get_owner_email/1},
other_members: %{value: &get_other_members/1},
limits: %{
value: fn site ->
case site.ingest_rate_limit_threshold do
nil -> ""
0 -> "🛑 BLOCKED"
n -> "#{n}/#{site.ingest_rate_limit_scale_seconds}s (per server)"
end
end
}
]
end
def list_actions(_conn) do
[
transfer_ownership: %{
name: "Transfer ownership",
inputs: [
%{name: "email", title: "New Owner Email", default: nil}
],
action: fn conn, sites, params -> transfer_ownership(conn, sites, params) end
},
transfer_ownership_direct: %{
name: "Transfer ownership without invite",
inputs: [
%{name: "email", title: "New Owner Email", default: nil}
],
action: fn conn, sites, params -> transfer_ownership_direct(conn, sites, params) end
}
]
end
defp transfer_ownership(_conn, [], _params) do
{:error, "Please select at least one site from the list"}
end
defp transfer_ownership(conn, sites, %{"email" => email}) do
new_owner = Plausible.Auth.find_user_by(email: email)
inviter = conn.assigns[:current_user]
if new_owner do
result =
Plausible.Site.Memberships.bulk_create_invitation(
sites,
inviter,
new_owner.email,
:owner,
check_permissions: false
)
case result do
{:ok, _} ->
:ok
{:error, :transfer_to_self} ->
{:error, "User is already an owner of one of the sites"}
end
else
{:error, "User could not be found"}
end
end
defp transfer_ownership_direct(_conn, [], _params) do
{:error, "Please select at least one site from the list"}
end
defp transfer_ownership_direct(_conn, sites, %{"email" => email}) do
new_owner = Plausible.Auth.find_user_by(email: email)
if new_owner do
case Plausible.Site.Memberships.bulk_transfer_ownership_direct(sites, new_owner) do
{:ok, _} ->
:ok
{:error, :transfer_to_self} ->
{:error, "User is already an owner of one of the sites"}
{:error, :no_plan} ->
{:error, "The new owner does not have a subscription"}
{:error, {:over_plan_limits, limits}} ->
{:error, "Plan limits exceeded for one of the sites: #{Enum.join(limits, ", ")}"}
end
else
{:error, "User could not be found"}
end
end
defp format_date(date) do
Timex.format!(date, "{Mshort} {D}, {YYYY}")
end
defp get_owner_email(site) do
owner = Enum.find(site.memberships, fn m -> m.role == :owner end)
if owner do
owner.user.email
end
end
defp get_other_members(site) do
Enum.filter(site.memberships, &(&1.role != :owner))
|> Enum.map(fn m -> m.user.email <> "(#{to_string(m.role)})" end)
|> Enum.join(", ")
end
def get_struct_fields(module) do
module.__struct__()
|> Map.drop([:__meta__, :__struct__])
|> Map.keys()
|> Enum.map(&Atom.to_string/1)
|> Enum.sort()
end
def create_changeset(schema, attrs), do: Plausible.Site.crm_changeset(schema, attrs)
def update_changeset(schema, attrs), do: Plausible.Site.crm_changeset(schema, attrs)
end