if Code.ensure_loaded?(Plug) do
defmodule GlificWeb.Plug do
@moduledoc """
This file and the below files have been "borrowed and modified" from triplex: https://github.com/ateliware/triplex
The original copyright and license - MIT belong to the authors and contributors of Triplex
* plug.ex
* ensure_plug.ex
* ensure_plug_config.ex
* subdomain_plug.ex
* subdomain_plug_config.ex
* param_plug.ex
* param_plug_config.ex
This module have some basic functions for our triplex plugs.
The plugs we have for now are:
- `GlificWeb.ParamPlug` - loads the organization from a body or query param
- `GlificWeb.SubdomainPlug` - loads the organization from the url subdomain
- `GlificWeb.EnsurePlug` - ensures the current organization is loaded and halts if not
"""
alias Plug.Conn
require Logger
@raw_organization_assign :raw_organization_name
@doc """
Global unauthorized error handler
"""
@spec send_error(Conn.t()) :: Conn.t()
def send_error(conn) do
conn
|> Conn.put_status(403)
|> Conn.send_resp(403, "Unauthorized")
|> Conn.halt()
end
@doc """
Puts the given `organization` as an assign on the given `conn`, but only if the
organization is not reserved.
The `config` map/struct must have:
- `organization_handler`: function to handle the organization param. Its return will
be used as the organization.
- `assign`: the name of the assign where we must save the organization.
"""
@spec put_organization(Conn.t(), any(), map()) :: Conn.t()
def put_organization(conn, organization, config) do
if conn.assigns[config.assign] do
conn
else
conn = Conn.assign(conn, @raw_organization_assign, organization)
organization_id = organization_handler(organization, config.organization_handler)
cond do
GlificWeb.Tenants.reserved_organization?(organization) ->
conn
organization_id == 0 ->
Logger.info("Halting on failure to retrive #{organization}")
send_error(conn)
true ->
Glific.Repo.put_organization_id(organization_id)
Conn.assign(conn, config.assign, organization_id)
end
end
end
@doc """
Ensure the organization is loaded, and if not, halts the `conn`.
The `config` map/struct must have:
- `assign`: the name of the assign where we must save the organization.
"""
@spec ensure_organization(Conn.t(), map()) :: Conn.t()
def ensure_organization(conn, config) do
if loaded_organization = conn.assigns[config.assign] do
callback(conn, loaded_organization, config.callback)
else
conn
|> callback(conn.assigns[@raw_organization_assign], config.failure_callback)
|> send_error()
end
end
@spec organization_handler(any(), any()) :: any()
defp organization_handler(organization, nil),
do: organization
defp organization_handler(organization, handler) when is_function(handler),
do: handler.(organization)
defp callback(conn, _, nil),
do: conn
defp callback(conn, organization, callback) when is_function(callback),
do: callback.(conn, organization)
end
end