Haytni.Plugin behaviour (Haytni v0.7.0) View Source
Defines a plugin to be used by Haytni
Link to this section Summary
Callbacks
Run at compile time before embedding plugin options once for all. It is a good place to realize some pre-computations.
Returns the Ecto.Schema.field/1
s as a quoted fragment to be injected in your user schema
Returns a list of files to be (un)installed by the mix tasks haytni.(un)install
Extract the user from the HTTP request (http authentication, cookies, ...).
Check if the user is in a valid state. This callback is intended to let know others plugins if we should reject the login (and why).
This callback is meant for a user to delete its own account.
This callback should be invoked when a user is editing its registration and change its email address.
Invoked when an authentication failed (wrong password). It receives the concerned account (as it is before calling any on_failed_authentication callback) and a Ecto.Multi where to add any additionnal treatment and a Keyword to return after updating it if any change have to be done to this user.
This callback is invoked when a user (manually) log out. Its purpose is mainly to do some cleanup like removing a cookie.
Invoked to accomplish a task right after user's registration (insert). This callback allows you to do some linked changes to the database, send an email or whatever by appending it to multi.
Invoked when an authentication is successful. Like on_failed_authentification/3
, it receives
the current user and a Keyword to return after updating it if you want to bring any change to this
user to the database.
Returns the routes as a quoted fragment to be injected in application's Router
This callback let you do any kind of change or additionnal validation on the changeset when a user is registering.
Performs validations of user's password. It is a convenient way to enforce your password policy.
Same as validate_create_registration
but registration's edition as logic between the two
may be completely different.
Link to this section Callbacks
Specs
Run at compile time before embedding plugin options once for all. It is a good place to realize some pre-computations.
Specs
Returns the Ecto.Schema.field/1
s as a quoted fragment to be injected in your user schema
Specs
files_to_install( base_path :: String.t(), web_path :: String.t(), scope :: String.t(), timestamp :: String.t() ) :: [{:eex | :text, String.t(), String.t()}]
Returns a list of files to be (un)installed by the mix tasks haytni.(un)install
Each file is a 3-elements tuple of the form:
{format, path relative to priv/ of the file to install, path where to install the file}
Format is one of the following atom:
:eex
: the file is an Eex template from which the content is evaluated before being copied where the following bindings are set:- scope (atom, default:
:user
): unsued for now - table (String.t, default:
"users"
): the name of the users table - otp_app (atom): inferred, the name of the current OTP application
- base_module (module): inferred, the name of the base non-web module of your Phoenix application (the YourApp in this documentation)
- web_module (module): inferred, the name of the base web module of your Phoenix application (YourAppWeb all over this documentation)
- plugins ([module]): the list of the enabled modules
- scope (atom, default:
:text
: to copy the file as is
Specs
find_user(conn :: Plug.Conn.t(), module :: module(), config :: Haytni.config()) :: {Plug.Conn.t(), Haytni.user() | nil}
Extract the user from the HTTP request (http authentication, cookies, ...).
Returns a tuple of the form {conn, user}
with user being nil
if no user could be found at
this early stage.
Specs
invalid?(user :: Haytni.user(), module :: module(), config :: Haytni.config()) :: false | {:error, atom()}
Check if the user is in a valid state. This callback is intended to let know others plugins if we should reject the login (and why).
Returns false
if the user is allowed to login else {:error, reason}
where reason is a string,
an informative to be directly served to the end user.
For example, you may want to have some kind of ban plugin. This is the way to decline the login:
def invalid?(%User{banned: true}, _module, _config), do: {:error, :banned} # or: {:error, dgettext("myapp", "you're banned")}
def invalid?(%User{banned: _}, _module, _config), do: false
Specs
on_delete_user( multi :: Ecto.Multi.t(), user :: Haytni.user(), module :: module(), config :: Haytni.config() ) :: Ecto.Multi.t()
This callback is meant for a user to delete its own account.
It could, for example, be used to soft-delete it:
def on_delete_user(multi = %Ecto.Multi{}, user = %_{}, _module, _config) do
Ecto.Multi.update(multi, :user, user, Ecto.Changeset.change(user, deleted: true))
end
Or remove associated files, like its avatar:
def on_delete_user(multi = %Ecto.Multi{}, user = %_{}, _module, _config) do
multi
# delete the user from the database
|> Ecto.Multi.delete(:user_deletion, user)
# then its avatar
|> Ecto.Multi.run(:avatar_deletion, fn _repo, _changes ->
case File.rm(user.avatar) do
:ok -> {:ok, nil}
error -> error
end
end)
end
Specs
on_email_change( multi :: Ecto.Multi.t(), changeset :: Ecto.Changeset.t(), module :: module(), config :: Haytni.config() ) :: {Ecto.Multi.t(), Ecto.Changeset.t()}
This callback should be invoked when a user is editing its registration and change its email address.
It returns a tuple of {Ecto.Multi, Ecto.Changeset}
, same as its arguments, to permit to the
callback to add any operation to multi or change to changeset.
This callback is called before updating the user but the actions added to multi will be run after its update.
Specs
on_failed_authentication( user :: Haytni.user() | nil, multi :: Ecto.Multi.t(), keywords :: Keyword.t(), module :: module(), config :: Haytni.config() ) :: {Ecto.Multi.t(), Keyword.t()}
Invoked when an authentication failed (wrong password). It receives the concerned account (as it is before calling any on_failed_authentication callback) and a Ecto.Multi where to add any additionnal treatment and a Keyword to return after updating it if any change have to be done to this user.
For example, you can use it as follows to count the number of failed attempts to login:
def on_failed_authentication(user = %_{}, multi, keyword, _module, _config) do
{multi, Keyword.put(keyword, :failed_attempts, user.failed_attempts + 1)}
end
Note: we choose to use and pass keyword as an accumulator to let the possibility to plugins
to deal themselves on a conflict (several different plugins which want to alter a same field).
Even if Keyword
allows a same key to be defined several times, you'll probably don't want it
to happen as the last defined value for a given key will (silently) override the others.
Specs
on_logout(conn :: Plug.Conn.t(), module :: module(), config :: Haytni.config()) :: Plug.Conn.t()
This callback is invoked when a user (manually) log out. Its purpose is mainly to do some cleanup like removing a cookie.
Specs
on_registration( multi :: Ecto.Multi.t(), module :: module(), config :: Haytni.config() ) :: Ecto.Multi.t()
Invoked to accomplish a task right after user's registration (insert). This callback allows you to do some linked changes to the database, send an email or whatever by appending it to multi.
Remember to comply to Ecto.Multi
functions. In particular Ecto.Multi.run
: the function
called by it have to return {:ok, your value}
or {:error, your value}
. Also note that
the inserted user will be passed to the function called by Ecto.Multi.run
as the :user
key to the map received by the last one as argument.
The following example illustrate how to send a welcome mail:
def on_registration(multi = %Ecto.Multi{}, _module, _config) do
multi
|> Ecto.Multi.run(:send_welcome_email, fn _repo, %{user: user} ->
send_welcome_email_to(user)
{:ok, true}
end)
end
on_successful_authentication(conn, user, multi, keywords, module, config)
View SourceSpecs
on_successful_authentication( conn :: Plug.Conn.t(), user :: Haytni.user(), multi :: Ecto.Multi.t(), keywords :: Keyword.t(), module :: module(), config :: Haytni.config() ) :: {Plug.Conn.t(), Ecto.Multi.t(), Keyword.t()}
Invoked when an authentication is successful. Like on_failed_authentification/3
, it receives
the current user and a Keyword to return after updating it if you want to bring any change to this
user to the database.
To continue our example with a failed attempts counter, on a successful authentication it may be a good idea to reset it in this scenario:
def on_successful_authentication(conn = %Plug.Conn{}, user = %_{}, multi, keywords, _module, _config) do
{conn, multi, Keyword.put(keywords, :failed_attempts, 0)}
end
Specs
routes(config :: Haytni.config(), prefix_name :: atom(), options :: Keyword.t()) :: Macro.t()
Returns the routes as a quoted fragment to be injected in application's Router
Specs
validate_create_registration( changeset :: Ecto.Changeset.t(), module :: module(), config :: Haytni.config() ) :: Ecto.Changeset.t()
This callback let you do any kind of change or additionnal validation on the changeset when a user is registering.
Specs
validate_password( changeset :: Ecto.Changeset.t(), module :: module(), config :: Haytni.config() ) :: Ecto.Changeset.t()
Performs validations of user's password. It is a convenient way to enforce your password policy.
Apply any custom validation(s) to the input %Ecto.Changeset{}
before returning it.
Specs
validate_update_registration( changeset :: Ecto.Changeset.t(), module :: module(), config :: Haytni.config() ) :: Ecto.Changeset.t()
Same as validate_create_registration
but registration's edition as logic between the two
may be completely different.