analytics/lib/plausible_web/controllers/api/external_sites_controller.ex
Uku Taht e71de6dc1f
Invitations (#1122)
* Invite existing user to a site

* Add invitation flow for non-existing users

* Accept and reject invitations

* Use invitation flow for existing users

* Locking mechanism for sites

* Authorization for site settings

* Show usage based on site ownership

* Add ability to remove members from a site

* Do not show settings link to viewer roles

* Ability to remove invitations

* Remove `Plausible.Sites.count_for/1`

* Fix tests

* Do not show the trial banner after the trial

* Correct trial emails

* Transfer ownership

* Send invitation email to existing user

* Add invitation email flows

* Add plug for role-based authorization

* Rename AuthorizeStatsPlug -> AuthorizeSiteAccess

* Add email flow for ownership transfer

* Fix URLs in emails

* Fix small copy issues

* Make 'People' its own section in site settings

* Notify user via email if their access has been removed

* Check site lock status when invitation is accepted

* Check lock status when user subscribes

* Make sure only admins and owners can create shared links

* Changelog

* Add LockSites to daily cron

* Clean invitations after 48 hours

* Add notices about expiry

* Add invitation expired page

* Add doc link
2021-06-16 15:00:07 +03:00

82 lines
2.3 KiB
Elixir

defmodule PlausibleWeb.Api.ExternalSitesController do
use PlausibleWeb, :controller
use Plausible.Repo
use Plug.ErrorHandler
alias Plausible.Sites
alias PlausibleWeb.Api.Helpers, as: H
def create_site(conn, params) do
user = conn.assigns[:current_user]
case Sites.create(user, params) do
{:ok, %{site: site}} ->
json(conn, site)
{:error, :site, changeset, _} ->
conn
|> put_status(400)
|> json(serialize_errors(changeset))
{:error, :limit, limit} ->
conn
|> put_status(403)
|> json(%{
error:
"Your account has reached the limit of #{limit} sites per account. Please contact hello@plausible.io to unlock more sites."
})
end
end
defp expect_param_key(params, key) do
case Map.fetch(params, key) do
:error -> {:missing, key}
res -> res
end
end
def find_or_create_shared_link(conn, params) do
with {:ok, site_id} <- expect_param_key(params, "site_id"),
{:ok, link_name} <- expect_param_key(params, "name"),
site when not is_nil(site) <-
Sites.get_for_user(conn.assigns[:current_user].id, site_id, [:owner, :admin]) do
shared_link = Repo.get_by(Plausible.Site.SharedLink, site_id: site.id, name: link_name)
shared_link =
case shared_link do
nil -> Sites.create_shared_link(site, link_name)
link -> {:ok, link}
end
case shared_link do
{:ok, link} ->
json(conn, %{
name: link.name,
url: Sites.shared_link_url(site, link)
})
end
else
nil ->
H.not_found(conn, "Site could not be found")
{:missing, "site_id"} ->
H.bad_request(conn, "Parameter `site_id` is required to create a shared link")
{:missing, "name"} ->
H.bad_request(conn, "Parameter `name` is required to create a shared link")
e ->
H.bad_request(conn, "Something went wrong: #{inspect(e)}")
end
end
defp serialize_errors(changeset) do
{field, {msg, _opts}} = List.first(changeset.errors)
error_msg = Atom.to_string(field) <> " " <> msg
%{"error" => error_msg}
end
def handle_errors(conn, %{kind: kind, reason: reason}) do
json(conn, %{error: Exception.format_banner(kind, reason)})
end
end