File size: 5,413 Bytes
8da2481 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | defmodule PlausibleWeb.Site.MembershipController do
@moduledoc """
This controller deals with user management via the UI in Site Settings -> People. It's important to enforce permissions in this controller.
Owner and Admin - Can manage users, can trigger a 'transfer ownership' request
Editor and Viewer - Can not access user management settings
Anyone - Can accept invitations
Everything else should be explicitly disallowed.
"""
use PlausibleWeb, :controller
use Plausible.Repo
use Plausible
alias Plausible.Teams
plug PlausibleWeb.RequireAccountPlug
plug PlausibleWeb.Plugs.AuthorizeSiteAccess, [:owner, :admin]
def invite_member_form(conn, _params) do
site =
conn.assigns.current_user
|> Plausible.Sites.get_for_user!(conn.assigns.site.domain)
|> Plausible.Repo.preload(:owners)
limit = Teams.Billing.team_member_limit(site.team)
usage = Teams.Billing.team_member_usage(site.team)
below_limit? = Plausible.Billing.Quota.below_limit?(usage, limit)
render(
conn,
"invite_member_form.html",
site: site,
team_member_limit: limit,
is_at_limit: not below_limit?,
skip_plausible_tracking: true
)
end
def invite_member(conn, %{"email" => email, "role" => role}) do
site_domain = conn.assigns.site.domain
site =
Plausible.Sites.get_for_user!(conn.assigns.current_user, site_domain)
|> Plausible.Repo.preload(:owners)
case Teams.Invitations.InviteToSite.invite(
site,
conn.assigns.current_user,
email,
role
) do
{:ok, invitation} ->
conn
|> put_flash(
:success,
"#{email} has been invited to #{site_domain} as #{PlausibleWeb.SiteView.with_indefinite_article("#{invitation.role}")}"
)
|> redirect(to: Routes.site_path(conn, :settings_people, site.domain))
{:error, :already_a_member} ->
render(conn, "invite_member_form.html",
error: "Cannot send invite because #{email} is already a member of #{site.domain}",
site: site,
skip_plausible_tracking: true
)
{:error, {:over_limit, limit}} ->
render(conn, "invite_member_form.html",
error:
"Your account is limited to #{limit} team members. You can upgrade your plan to increase this limit.",
site: site,
skip_plausible_tracking: true,
is_at_limit: true,
team_member_limit: limit
)
{:error, %Ecto.Changeset{} = changeset} ->
error_msg =
case changeset.errors[:invitation] do
{"already sent", _} ->
"This invitation has been already sent. To send again, remove it from pending invitations first."
_ ->
"Something went wrong."
end
conn
|> put_flash(:error, error_msg)
|> redirect(to: Routes.site_path(conn, :settings_people, site.domain))
end
end
@doc """
Updates the role of a user. The user being updated could be the same or different from the user taking
the action. When updating the role, it's important to enforce permissions:
Owner - Can update anyone's role except for themselves. If they want to change their own role, they have to use the 'transfer ownership' feature.
Admin - Can update anyone's role except for owners. Can downgrade their own access to 'viewer'. Can promote a viewer to admin.
"""
def update_role_by_user(conn, %{"id" => user_id, "new_role" => new_role_str}) do
%{site: site, current_user: current_user, site_role: site_role} = conn.assigns
case Teams.Memberships.update_role(
site,
user_id,
new_role_str,
current_user,
site_role
) do
{:ok, guest_membership} ->
redirect_target =
if guest_membership.team_membership.user_id == current_user.id and
guest_membership.role == :viewer do
Routes.stats_path(conn, :stats, site.domain, [])
else
Routes.site_path(conn, :settings_people, site.domain)
end
conn
|> put_flash(
:success,
"#{guest_membership.team_membership.user.name} is now #{PlausibleWeb.SiteView.with_indefinite_article(to_string(guest_membership.role))}"
)
|> redirect(to: redirect_target)
{:error, _} ->
conn
|> put_flash(:error, "You are not allowed to grant the #{new_role_str} role")
|> redirect(to: Routes.site_path(conn, :settings_people, site.domain))
end
end
def remove_member_by_user(conn, %{"id" => user_id} = _params) do
site = conn.assigns.site
if user = Repo.get(Plausible.Auth.User, user_id) do
Teams.Memberships.remove(site, user)
redirect_target =
if user_id == conn.assigns[:current_user].id do
Routes.site_path(conn, :index)
else
Routes.site_path(conn, :settings_people, site.domain)
end
conn
|> put_flash(
:success,
"#{user.name} has been removed from #{site.domain}"
)
|> redirect(to: redirect_target)
else
conn
|> put_flash(
:success,
"User has been removed from #{site.domain}"
)
|> redirect(to: Routes.site_path(conn, :settings_people, site.domain))
end
end
end
|