replace coherence with guardian

This commit is contained in:
Thomas Citharel 2017-12-09 14:58:37 +01:00
parent 90ceb4f6fe
commit 8ac705d8c2
52 changed files with 208 additions and 1254 deletions

View file

@ -26,21 +26,6 @@ config :logger, :console,
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs" import_config "#{Mix.env}.exs"
# %% Coherence Configuration %% Don't remove this line config :eventos, EventosWeb.Guardian,
config :coherence, issuer: "Eventos",
user_schema: Eventos.Accounts.User, secret_key: "ty0WM7YBE3ojvxoUQxo8AERrNpfbXnIJ82ovkPdqbUFw31T5LcK8wGjaOiReVQjo"
repo: Eventos.Repo,
module: Eventos,
web_module: EventosWeb,
router: EventosWeb.Router,
messages_backend: EventosWeb.Coherence.Messages,
logged_out_url: "/",
user_active_field: true,
email_from_name: "Your Name",
email_from_email: "yourname@example.com",
opts: [:invitable, :confirmable, :rememberable, :authenticatable, :recoverable, :lockable, :trackable, :unlockable_with_token, :registerable]
config :coherence, EventosWeb.Coherence.Mailer,
adapter: Swoosh.Adapters.Sendgrid,
api_key: "your api key here"
# %% End Coherence Configuration %%

View file

@ -12,8 +12,8 @@ config :logger, level: :warn
# Configure your database # Configure your database
config :eventos, Eventos.Repo, config :eventos, Eventos.Repo,
adapter: Ecto.Adapters.Postgres, adapter: Ecto.Adapters.Postgres,
username: "postgres", username: "elixir",
password: "postgres", password: "elixir",
database: "eventos_test", database: "eventos_test",
hostname: "localhost", hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox pool: Ecto.Adapters.SQL.Sandbox

View file

@ -4,6 +4,7 @@ defmodule Eventos.Accounts do
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
import Logger
alias Eventos.Repo alias Eventos.Repo
alias Eventos.Accounts.User alias Eventos.Accounts.User
@ -37,6 +38,32 @@ defmodule Eventos.Accounts do
""" """
def get_user!(id), do: Repo.get!(User, id) def get_user!(id), do: Repo.get!(User, id)
@doc """
Get an user by email
"""
def find(email) do
Repo.get_by!(User, email: email)
end
@doc """
Authenticate user
"""
def authenticate(%{user: user, password: password}) do
# Does password match the one stored in the database?
Logger.debug(user.password_hash)
Logger.debug(password)
case Comeonin.Argon2.checkpw(password, user.password_hash) do
true ->
# Yes, create and return the token
EventosWeb.Guardian.encode_and_sign(user)
_ ->
# No, return an error
{:error, :unauthorized}
end
end
@doc """ @doc """
Creates a user. Creates a user.

View file

@ -1,6 +1,5 @@
defmodule Eventos.Accounts.User do defmodule Eventos.Accounts.User do
use Ecto.Schema use Ecto.Schema
use Coherence.Schema
import Ecto.Changeset import Ecto.Changeset
alias Eventos.Accounts.{User} alias Eventos.Accounts.{User}
@ -8,36 +7,40 @@ defmodule Eventos.Accounts.User do
schema "users" do schema "users" do
field :email, :string field :email, :string
field :role, :integer, default: 0 field :role, :integer, default: 0
field :username, :string field :password, :string, virtual: true
field :password_hash, :string
field :account_id, :integer field :account_id, :integer
coherence_schema()
timestamps() timestamps()
end end
def changeset(user, attrs, :password) do
user
|> cast(attrs, ~w(password password_confirmation reset_password_token reset_password_sent_at))
|> validate_coherence_password_reset(attrs)
end
def changeset(user, attrs, :registration) do
user
|> cast(attrs, [:username, :email] ++ coherence_fields())
|> validate_required([:username, :email])
|> validate_format(:email, ~r/@/)
|> unique_constraint(:username)
|> validate_coherence(attrs)
end
@doc false @doc false
def changeset(%User{} = user, attrs) do def changeset(%User{} = user, attrs) do
user user
|> cast(attrs, [:username, :email, :password_hash, :role] ++ coherence_fields()) |> cast(attrs, [:email, :password_hash, :role])
|> validate_required([:username, :email]) |> validate_required([:email])
|> unique_constraint(:username) |> unique_constraint(:email)
|> validate_format(:email, ~r/@/) |> validate_format(:email, ~r/@/)
|> validate_coherence(attrs) end
def registration_changeset(struct, params) do
struct
|> changeset(params)
|> cast(params, ~w(password)a, [])
|> validate_length(:password, min: 6, max: 100)
|> hash_password
end
defp hash_password(changeset) do
case changeset do
%Ecto.Changeset{valid?: true,
changes: %{password: password}} ->
put_change(changeset,
:password_hash,
Comeonin.Argon2.hashpwsalt(password))
_ ->
changeset
end
end end
end end

View file

@ -1,40 +0,0 @@
defmodule Eventos.Coherence.Invitation do
@moduledoc """
Schema to support inviting a someone to create an account.
"""
use Ecto.Schema
import Ecto.Changeset
schema "invitations" do
field :name, :string
field :email, :string
field :token, :string
timestamps()
end
@doc """
Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned
with no validation performed.
"""
@spec changeset(Ecto.Schema.t, Map.t) :: Ecto.Changeset.t
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w(name email token))
|> validate_required([:name, :email])
|> unique_constraint(:email)
|> validate_format(:email, ~r/@/)
end
@doc """
Creates a changeset for a new schema
"""
@spec new_changeset(Map.t) :: Ecto.Changeset.t
def new_changeset(params \\ %{}) do
changeset %__MODULE__{}, params
end
end

View file

@ -1,44 +0,0 @@
defmodule Eventos.Coherence.Rememberable do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias Coherence.Config
schema "rememberables" do
field :series_hash, :string
field :token_hash, :string
field :token_created_at, Timex.Ecto.DateTime
belongs_to :user, Module.concat(Config.module, Config.user_schema)
timestamps()
end
use Coherence.Rememberable
@doc """
Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned
with no validation performed.
"""
@spec changeset(Ecto.Schema.t, Map.t) :: Ecto.Changeset.t
def changeset(model, params \\ %{}) do
model
|> cast(params, ~w(series_hash token_hash token_created_at user_id))
|> validate_required(~w(series_hash token_hash token_created_at user_id)a)
end
@doc """
Creates a changeset for a new schema
"""
@spec new_changeset(Map.t) :: Ecto.Changeset.t
def new_changeset(params \\ %{}) do
changeset %Rememberable{}, params
end
end

View file

@ -1,141 +0,0 @@
defmodule Eventos.Coherence.Schemas do
use Coherence.Config
import Ecto.Query
@user_schema Config.user_schema
@repo Config.repo
def list_user do
@repo.all @user_schema
end
def get_by_user(opts) do
@repo.get_by @user_schema, opts
end
def get_user(id) do
@repo.get @user_schema, id
end
def get_user!(id) do
@repo.get! @user_schema, id
end
def get_user_by_email(email) do
@repo.get_by @user_schema, email: email
end
def change_user(struct, params) do
@user_schema.changeset struct, params
end
def change_user(params) do
@user_schema.changeset @user_schema.__struct__, params
end
def change_user do
@user_schema.changeset @user_schema.__struct__, %{}
end
def update_user(user, params) do
@repo.update change_user(user, params)
end
def create_user(params) do
@repo.insert change_user(params)
end
Enum.each [Eventos.Coherence.Invitation, Eventos.Coherence.Rememberable], fn module ->
name =
module
|> Module.split
|> List.last
|> String.downcase
def unquote(String.to_atom("list_#{name}"))() do
@repo.all unquote(module)
end
def unquote(String.to_atom("list_#{name}"))(%Ecto.Query{} = query) do
@repo.all query
end
def unquote(String.to_atom("get_#{name}"))(id) do
@repo.get unquote(module), id
end
def unquote(String.to_atom("get_#{name}!"))(id) do
@repo.get! unquote(module), id
end
def unquote(String.to_atom("get_by_#{name}"))(opts) do
@repo.get_by unquote(module), opts
end
def unquote(String.to_atom("change_#{name}"))(struct, params) do
unquote(module).changeset(struct, params)
end
def unquote(String.to_atom("change_#{name}"))(params) do
unquote(module).new_changeset(params)
end
def unquote(String.to_atom("change_#{name}"))() do
unquote(module).new_changeset(%{})
end
def unquote(String.to_atom("create_#{name}"))(params) do
@repo.insert unquote(module).new_changeset(params)
end
def unquote(String.to_atom("update_#{name}"))(struct, params) do
@repo.update unquote(module).changeset(struct, params)
end
def unquote(String.to_atom("delete_#{name}"))(struct) do
@repo.delete struct
end
end
def query_by(schema, opts) do
Enum.reduce opts, schema, fn {k, v}, query ->
where(query, [b], field(b, ^k) == ^v)
end
end
def delete_all(%Ecto.Query{} = query) do
@repo.delete_all query
end
def delete_all(module) when is_atom(module) do
@repo.delete_all module
end
def create(%Ecto.Changeset{} = changeset) do
@repo.insert changeset
end
def create!(%Ecto.Changeset{} = changeset) do
@repo.insert! changeset
end
def update(%Ecto.Changeset{} = changeset) do
@repo.update changeset
end
def update!(%Ecto.Changeset{} = changeset) do
@repo.update! changeset
end
def delete(schema) do
@repo.delete schema
end
def delete!(schema) do
@repo.delete! schema
end
end

View file

@ -0,0 +1,8 @@
defmodule EventosWeb.AuthErrorHandler do
import Plug.Conn
def auth_error(conn, {type, _reason}, _opts) do
body = Poison.encode!(%{message: to_string(type)})
send_resp(conn, 401, body)
end
end

View file

@ -0,0 +1,11 @@
defmodule EventosWeb.AuthPipeline do
use Guardian.Plug.Pipeline, otp_app: :eventos,
module: EventosWeb.Guradian,
error_handler: EventosWeb.AuthErrorHandler
plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"}, realm: :none
plug Guardian.Plug.EnsureAuthenticated
plug Guardian.Plug.LoadResource, ensure: true
end

View file

@ -1,79 +0,0 @@
defmodule EventosWeb.Coherence.Messages do
@moduledoc """
Application facing messages generated by the Coherence application.
This module was created by the coh.install mix task. It contains all the
messages used in the coherence application except those in other generated
files like the view and templates.
To assist in upgrading Coherence, the `Coherence.Messages behaviour will
alway contain every message for the current version. This will help in upgrades
to ensure the user had added new the new messages from the current version.
"""
@behaviour Coherence.Messages
import EventosWeb.Gettext
# Change this to override the "coherence" gettext domain. If you would like
# the coherence message to be part of your projects domain change it to "default"
@domain "coherence"
##################
# Messages
def account_already_confirmed, do: dgettext(@domain, "Account already confirmed.")
def account_is_not_locked, do: dgettext(@domain, "Account is not locked.")
def account_updated_successfully, do: dgettext(@domain, "Account updated successfully.")
def already_confirmed, do: dgettext(@domain, "already confirmed")
def already_locked, do: dgettext(@domain, "already locked")
def already_logged_in, do: dgettext(@domain, "Already logged in.")
def cant_be_blank, do: dgettext(@domain, "can't be blank")
def cant_find_that_token, do: dgettext(@domain, "Can't find that token")
def confirmation_email_sent, do: dgettext(@domain, "Confirmation email sent.")
def confirmation_token_expired, do: dgettext(@domain, "Confirmation token expired.")
def could_not_find_that_email_address, do: dgettext(@domain, "Could not find that email address")
def forgot_your_password, do: dgettext(@domain, "Forgot your password?")
def http_authentication_required, do: dgettext(@domain, "HTTP Authentication Required")
def incorrect_login_or_password(opts), do: dgettext(@domain, "Incorrect %{login_field} or password.", opts)
def invalid_current_password, do: dgettext(@domain, "invalid current password")
def invalid_invitation, do: dgettext(@domain, "Invalid Invitation. Please contact the site administrator.")
def invalid_request, do: dgettext(@domain, "Invalid Request.")
def invalid_confirmation_token, do: dgettext(@domain, "Invalid confirmation token.")
def invalid_email_or_password, do: dgettext(@domain, "Invalid email or password.")
def invalid_invitation_token, do: dgettext(@domain, "Invalid invitation token.")
def invalid_reset_token, do: dgettext(@domain, "Invalid reset token.")
def invalid_unlock_token, do: dgettext(@domain, "Invalid unlock token.")
def invitation_already_sent, do: dgettext(@domain, "Invitation already sent.")
def invitation_sent, do: dgettext(@domain, "Invitation sent.")
def invite_someone, do: dgettext(@domain, "Invite Someone")
def maximum_login_attempts_exceeded, do: dgettext(@domain, "Maximum Login attempts exceeded. Your account has been locked.")
def need_an_account, do: dgettext(@domain, "Need An Account?")
def not_locked, do: dgettext(@domain, "not locked")
def password_reset_token_expired, do: dgettext(@domain, "Password reset token expired.")
def password_updated_successfully, do: dgettext(@domain, "Password updated successfully.")
def problem_confirming_user_account, do: dgettext(@domain, "Problem confirming user account. Please contact the system administrator.")
def registration_created_successfully, do: dgettext(@domain, "Registration created successfully.")
def required, do: dgettext(@domain, "required")
def resend_confirmation_email, do: dgettext(@domain, "Resend confirmation email")
def reset_email_sent, do: dgettext(@domain, "Reset email sent. Check your email for a reset link.")
def restricted_area, do: dgettext(@domain, "Restricted Area")
def send_an_unlock_email, do: dgettext(@domain, "Send an unlock email")
def sign_in, do: dgettext(@domain, "Sign In")
def sign_out, do: dgettext(@domain, "Sign Out")
def signed_in_successfully, do: dgettext(@domain, "Signed in successfully.")
def too_many_failed_login_attempts, do: dgettext(@domain, "Too many failed login attempts. Account has been locked.")
def unauthorized_ip_address, do: dgettext(@domain, "Unauthorized IP Address")
def unlock_instructions_sent, do: dgettext(@domain, "Unlock Instructions sent.")
def user_account_confirmed_successfully, do: dgettext(@domain, "User account confirmed successfully.")
def user_already_has_an_account, do: dgettext(@domain, "User already has an account!")
def you_must_confirm_your_account, do: dgettext(@domain, "You must confirm your account before you can login.")
def your_account_has_been_unlocked, do: dgettext(@domain, "Your account has been unlocked")
def your_account_is_not_locked, do: dgettext(@domain, "Your account is not locked.")
def verify_user_token(opts),
do: dgettext(@domain, "Invalid %{user_token} error: %{error}", opts)
def you_are_using_an_invalid_security_token,
do: dgettext(@domain, "You are using an invalid security token for this site! This security\n" <>
"violation has been logged.\n")
def mailer_required, do: dgettext(@domain, "Mailer configuration required!")
def account_is_inactive(), do: dgettext(@domain, "Account is inactive!")
end

View file

@ -1,47 +0,0 @@
defmodule EventosWeb.Coherence do
@moduledoc false
def view do
quote do
use Phoenix.View, root: "lib/eventos_web/templates"
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
# Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML
import EventosWeb.Router.Helpers
import EventosWeb.ErrorHelpers
import EventosWeb.Gettext
import EventosWeb.Coherence.ViewHelpers
end
end
def controller do
quote do
use Phoenix.Controller, except: [layout_view: 2]
use Coherence.Config
use Timex
import Ecto
import Ecto.Query
import Plug.Conn
import EventosWeb.Router.Helpers
import EventosWeb.Gettext
import Coherence.ControllerHelpers
alias Coherence.Config
alias Coherence.ControllerHelpers, as: Helpers
require Redirects
end
end
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end

View file

@ -1,54 +0,0 @@
defmodule Coherence.Redirects do
@moduledoc """
Define controller action redirection functions.
This module contains default redirect functions for each of the controller
actions that perform redirects. By using this Module you get the following
functions:
* session_create/2
* session_delete/2
* password_create/2
* password_update/2,
* unlock_create_not_locked/2
* unlock_create_invalid/2
* unlock_create/2
* unlock_edit_not_locked/2
* unlock_edit/2
* unlock_edit_invalid/2
* registration_create/2
* invitation_create/2
* confirmation_create/2
* confirmation_edit_invalid/2
* confirmation_edit_expired/2
* confirmation_edit/2
* confirmation_edit_error/2
You can override any of the functions to customize the redirect path. Each
function is passed the `conn` and `params` arguments from the controller.
## Examples
import EventosWeb.Router.Helpers
# override the log out action back to the log in page
def session_delete(conn, _), do: redirect(conn, to: session_path(conn, :new))
# redirect the user to the login page after registering
def registration_create(conn, _), do: redirect(conn, to: session_path(conn, :new))
# disable the user_return_to feature on login
def session_create(conn, _), do: redirect(conn, to: landing_path(conn, :index))
"""
use Redirects
# Uncomment the import below if adding overrides
# import EventosWeb.Router.Helpers
# Add function overrides below
# Example usage
# Uncomment the following line to return the user to the login form after logging out
# def session_delete(conn, _), do: redirect(conn, to: session_path(conn, :new))
end

View file

@ -4,4 +4,8 @@ defmodule EventosWeb.PageController do
def index(conn, _params) do def index(conn, _params) do
render conn, "index.html" render conn, "index.html"
end end
def app(conn, _params) do
render conn, "index.html"
end
end end

View file

@ -0,0 +1,27 @@
defmodule EventosWeb.SessionController do
use EventosWeb, :controller
alias Eventos.Accounts.User
alias Eventos.Accounts
def sign_in(conn, %{"email" => email, "password" => password}) do
with %User{} = user <- Accounts.find(email) do
# Attempt to authenticate the user
with {:ok, token, _claims} <- Accounts.authenticate(%{user: user, password: password}) do
# Render the token
render conn, "token.json", token: token
end
end
end
def sign_out(conn, _params) do
conn
|> Eventos.Guardian.Plug.sign_out()
|> send_resp(204, "")
end
def show(conn, _params) do
user = Eventos.Guardian.Plug.current_resource(conn)
send_resp(conn, 200, Poison.encode!(%{user: user}))
end
end

View file

@ -1,6 +0,0 @@
defmodule EventosWeb.Coherence.Mailer do
@moduledoc false
if Coherence.Config.mailer?() do
use Swoosh.Mailer, otp_app: :coherence
end
end

View file

@ -1,82 +0,0 @@
Code.ensure_loaded Phoenix.Swoosh
defmodule EventosWeb.Coherence.UserEmail do
@moduledoc false
use Phoenix.Swoosh, view: EventosWeb.Coherence.EmailView, layout: {EventosWeb.Coherence.LayoutView, :email}
alias Swoosh.Email
require Logger
alias Coherence.Config
import EventosWeb.Gettext
defp site_name, do: Config.site_name(inspect Config.module)
def password(user, url) do
%Email{}
|> from(from_email())
|> to(user_email(user))
|> add_reply_to()
|> subject(dgettext("coherence", "%{site_name} - Reset password instructions", site_name: site_name()))
|> render_body("password.html", %{url: url, name: first_name(user.username)})
end
def confirmation(user, url) do
%Email{}
|> from(from_email())
|> to(user_email(user))
|> add_reply_to()
|> subject(dgettext("coherence", "%{site_name} - Confirm your new account", site_name: site_name()))
|> render_body("confirmation.html", %{url: url, name: first_name(user.username)})
end
def invitation(invitation, url) do
%Email{}
|> from(from_email())
|> to(user_email(invitation))
|> add_reply_to()
|> subject(dgettext("coherence", "%{site_name} - Invitation to create a new account", site_name: site_name()))
|> render_body("invitation.html", %{url: url, name: first_name(invitation.name)})
end
def unlock(user, url) do
%Email{}
|> from(from_email())
|> to(user_email(user))
|> add_reply_to()
|> subject(dgettext("coherence", "%{site_name} - Unlock Instructions", site_name: site_name()))
|> render_body("unlock.html", %{url: url, name: first_name(user.username)})
end
defp add_reply_to(mail) do
case Coherence.Config.email_reply_to do
nil -> mail
true -> reply_to mail, from_email()
address -> reply_to mail, address
end
end
defp first_name(name) do
case String.split(name, " ") do
[first_name | _] -> first_name
_ -> name
end
end
defp user_email(user) do
{user.username, user.email}
end
defp from_email do
case Coherence.Config.email_from do
nil ->
Logger.error ~s|Need to configure :coherence, :email_from_name, "Name", and :email_from_email, "me@example.com"|
nil
{name, email} = email_tuple ->
if is_nil(name) or is_nil(email) do
Logger.error ~s|Need to configure :coherence, :email_from_name, "Name", and :email_from_email, "me@example.com"|
nil
else
email_tuple
end
end
end
end

View file

@ -0,0 +1,40 @@
defmodule EventosWeb.Guardian do
use Guardian, otp_app: :eventos, permissions: %{
superuser: [:moderate, :super],
user: [:base]
}
alias Eventos.Accounts
alias Eventos.Accounts.User
def subject_for_token(user = %User{}, _claims) do
{:ok, "User:" <> to_string(user.id)}
end
def subject_for_token(_, _) do
{:error, :unknown_resource}
end
def resource_from_claims(%{"sub" => "User:" <> uid_str}) do
try do
case Integer.parse(uid_str) do
{uid, ""} ->
{:ok, Accounts.get_user!(uid)}
_ ->
{:error, :invalid_id}
end
rescue
Ecto.NoResultsError -> {:error, :no_result}
end
end
def resource_from_claims(_claims) do
{:error, :reason_for_error}
end
# def build_claims(claims, _resource, opts) do
# claims = claims
# |> encode_permissions_into_claims!(Keyword.get(opts, :permissions))
# {:ok, claims}
# end
end

View file

@ -1,44 +1,27 @@
defmodule EventosWeb.Router do defmodule EventosWeb.Router do
use EventosWeb, :router use EventosWeb, :router
use Coherence.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Coherence.Authentication.Session
end
pipeline :protected do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Coherence.Authentication.Session, protected: true
end
pipeline :api do pipeline :api do
plug :accepts, ["json"] plug :accepts, ["json"]
end end
scope "/" do pipeline :api_auth do
pipe_through :browser plug EventosWeb.AuthPipeline
coherence_routes()
end end
# Add this block scope "/api" do
scope "/" do pipe_through :api
pipe_through :protected
coherence_routes :protected resources "/users", UserController, only: [:create]
post "/sign-in", EventosWeb.SessionController, :sign_in
end end
scope "/", EventosWeb do # Other scopes may use custom stacks.
pipe_through :browser # Use the default browser stack scope "/api", EventosWeb do
pipe_through :api_auth
get "/", PageController, :index
post "/sign-out", SessionController, :sign_out
resources "/users", UserController resources "/users", UserController
resources "/accounts", AccountController resources "/accounts", AccountController
resources "/events", EventController resources "/events", EventController
@ -50,14 +33,4 @@ defmodule EventosWeb.Router do
resources "/group_accounts", GroupAccountController resources "/group_accounts", GroupAccountController
resources "/group_requests", GroupRequestController resources "/group_requests", GroupRequestController
end end
scope "/", EventosWeb do
pipe_through :protected
# Add protected routes below
end
# Other scopes may use custom stacks.
scope "/api", EventosWeb do
pipe_through :api
end
end end

View file

@ -1,17 +0,0 @@
<br \>
<h3><%= dgettext "coherence", "Resend Confirmation Instructions" %></h3>
<%= form_for @changeset, confirmation_path(@conn, :create), [as: :confirmation], fn f -> %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Resend Email"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,11 +0,0 @@
<div>
<p><%= dgettext "coherence", "Hello %{name}!", name: @name %><p>
<p>
<%= dgettext "coherence", "Your new account is almost ready. Click the link below to confirm you new account." %>
</p>
<p>
<a href="<%= @url %>"><%= dgettext "coherence", "Confirm my Account" %></a>
</p>
<p><%= dgettext "coherence", "Thank you!" %></p>
</div>

View file

@ -1,11 +0,0 @@
<div>
<p><%= dgettext "coherence", "Hello %{name}!", name: @name %><p>
<p>
<%= dgettext "coherence", "You have been invited to create an Account. Use the link below to create an account." %>
</p>
<p>
<a href="<%= @url %>"><%= dgettext "coherence", "Create my Account" %></a>
</p>
<p><%= dgettext "coherence", "Thank you!" %></p>
</div>

View file

@ -1,16 +0,0 @@
<div>
<p><%= dgettext "coherence", "Hello %{name}!", name: @name %><p>
<p>
<%= dgettext "coherence", "Someone has requested a link to change your password, and you can do this through the link below." %>
</p>
<p>
<a href="<%= @url %>"><%= dgettext "coherence", "Change my password" %></a>
</p>
<p>
<%= dgettext "coherence", "If you didn't request this, please ignore this email." %>
</p>
<p>
<%= dgettext "coherence", "Your password won't change until you access the link above and create a new one." %>
</p>
</div>

View file

@ -1,11 +0,0 @@
<div>
<p><%= dgettext "coherence", "Hello %{name}!", name: @name %><p>
<p>
<%= dgettext "coherence", "You requested unlock instructions for your locked account. Please click the link below to unlock your account." %>
</p>
<p>
<a href="<%= @url %>"><%= dgettext "coherence", "Unlock my Account" %></a>
</p>
<p><%= dgettext "coherence", "Thank you!" %></p>
</div>

View file

@ -1,49 +0,0 @@
<br \>
<%= form_for @changeset, invitation_path(@conn, :create_user), fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p><%= dgettext "coherence", "Oops, something went wrong! Please check the errors below." %></p>
</div>
<% end %>
<input type="hidden" name="token" value="<%= @token %>">
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :name, class: "form-control", required: "" %>
<%= error_tag f, :name %>
</div>
<%= unless (login_field = Coherence.Config.login_field) == :email do %>
<div class="form-group">
<%= required_label f, login_field, class: "control-label" %>
<%= text_input f, login_field, class: "form-control", required: "" %>
<%= error_tag f, login_field %>
</div>
<% end %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password"), class: "control-label" %>
<%= password_input f, :password, class: "form-control", required: "" %>
<%= error_tag f, :password %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password Confirmation"), class: "control-label" %>
<%= password_input f, :password_confirmation, class: "form-control", required: "" %>
<%= error_tag f, :password_confirmation %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Create"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,26 +0,0 @@
<%= form_for @changeset, invitation_path(@conn, :create), [as: :invitation], fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p><%= dgettext "coherence", "Oops, something went wrong! Please check the errors below." %></p>
</div>
<% end %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Name"), class: "control-label" %>
<%= text_input f, :name, class: "form-control", required: "" %>
<%= error_tag f, :name %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Send Invitation"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
<%= if invitation = @conn.assigns[:invitation] do %>
<%= link dgettext("coherence", "Resend Invitation!"), to: invitation_path(@conn, :resend, invitation.id), class: "btn" %>
<% end %>
</div>
<% end %>

View file

@ -1,8 +0,0 @@
<html>
<head>
<title><%= @email.subject %></title>
</head>
<body>
<%= render @view_module, @view_template, assigns %>
</body>
</html>

View file

@ -1,25 +0,0 @@
<br \>
<h3><%= dgettext "coherence", "Create a New Password" %></h3>
<%= form_for @changeset, password_path(@conn, :update, @changeset.data), [as: :password], fn f -> %>
<%= hidden_input f, :reset_password_token %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password"), class: "control-label" %>
<%= password_input f, :password, class: "form-control", required: "" %>
<%= error_tag f, :password %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password Confirmation"), class: "control-label" %>
<%= password_input f, :password_confirmation, class: "form-control", required: "" %>
<%= error_tag f, :password_confirmation %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Update Password"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,17 +0,0 @@
<br \>
<h3><%= dgettext "coherence", "Send reset password link" %></h3>
<%= form_for @changeset, password_path(@conn, :create), [as: :password], fn f -> %>
<div class="form-group">
<%= required_label f, :email, class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Reset Password"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,5 +0,0 @@
<h3><%= dgettext "coherence", "Edit Account" %></h3>
<%= render "form.html", changeset: @changeset,
label: dgettext("coherence", "Update"), required: [],
action: registration_path(@conn, :update) %>

View file

@ -1,58 +0,0 @@
<%= form_for @changeset, @action, [as: :registration], fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p><%= dgettext "coherence", "Oops, something went wrong! Please check the errors below." %></p>
<ul>
<%= for error <- @changeset.errors do %>
<li><%= error %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Name"), class: "control-label" %>
<%= text_input f, :username, class: "form-control", required: "" %>
<%= error_tag f, :username %>
</div>
<%= unless (login_field = Coherence.Config.login_field) == :email do %>
<div class="form-group">
<%= required_label f, login_field, class: "control-label" %>
<%= text_input f, login_field, class: "form-control", required: "" %>
<%= error_tag f, login_field %>
</div>
<% end %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<%= if Coherence.Config.require_current_password and not is_nil(@changeset.data.id) do %>
<div class="form-group">
<%= required_label f, :current_password, class: "control-label" %>
<%= password_input f, :current_password, [class: "form-control"] ++ @required %>
<%= error_tag f, :current_password %>
</div>
<% end %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password"), class: "control-label" %>
<%= password_input f, :password, [class: "form-control"] ++ @required %>
<%= error_tag f, :password %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password Confirmation"), class: "control-label" %>
<%= password_input f, :password_confirmation, [class: "form-control"] ++ @required %>
<%= error_tag f, :password_confirmation %>
</div>
<div class="form-group">
<%= submit @label, class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,5 +0,0 @@
<h3><%= dgettext "coherence", "Register Account" %></h3>
<%= render "form.html", changeset: @changeset,
label: dgettext("coherence", "Register"), required: [required: ""],
action: registration_path(@conn, :create) %>

View file

@ -1,25 +0,0 @@
<h2><%= dgettext "coherence", "Show account" %></h2>
<ul>
<li>
<strong><%= dgettext "coherence", "Name:" %></strong>
<%= @user.username %>
</li>
<%= unless (login_field = Coherence.Config.login_field) == :email do %>
<li>
<strong><%= humanize login_field %></strong>
<%= Map.get(@user, login_field) %>
</li>
<% end %>
<li>
<strong><%= dgettext "coherence", "Email:" %></strong>
<%= @user.email %>
</li>
</ul>
<%= link dgettext("coherence", "Edit"), to: registration_path(@conn, :edit) %> |
<%= link dgettext("coherence", "Delete"),
to: registration_path(@conn, :delete),
method: :delete,
data: [confirm: dgettext("coherence", "Are you sure?")] %>

View file

@ -1,35 +0,0 @@
<br \>
<%= form_for @conn, session_path(@conn, :create), [as: :session], fn f -> %>
<% login_field = Coherence.Config.login_field %>
<div class="form-group">
<%= required_label f, login_field, class: "control-label" %>
<%= text_input f, login_field, class: "form-control", required: "" %>
<%= error_tag f, login_field %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password"), class: "control-label" %>
<%= password_input f, :password, class: "form-control", required: "" %>
<%= error_tag f, :password %>
</div>
<%= if @remember do %>
<div class="form-group">
<input type="checkbox" name="remember" id="remember">
<label for="remember"><%= dgettext "coherence", "Remember Me?" %></label>
</div>
<br />
<% end %>
<div class="form-group">
<%= submit dgettext("coherence", "Sign In"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<div class="form-group">
<%= coherence_links(@conn, :new_session) %>
</div>
<% end %>

View file

@ -1,22 +0,0 @@
<br \>
<%= form_for @conn, unlock_path(@conn, :create), [as: :unlock], fn f -> %>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Email"), class: "control-label" %>
<%= text_input f, :email, class: "form-control", required: "" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= required_label f, dgettext("coherence", "Password"), class: "control-label" %>
<%= password_input f, :password, class: "form-control", required: "" %>
<%= error_tag f, :password %>
</div>
<div class="form-group">
<%= submit dgettext("coherence", "Send Instructions"), class: "btn btn-primary" %>
<%= link dgettext("coherence", "Cancel"), to: Coherence.Config.logged_out_url("/"), class: "btn" %>
</div>
<% end %>

View file

@ -1,3 +0,0 @@
defmodule Coherence.CoherenceView do
use EventosWeb.Coherence, :view
end

View file

@ -1,210 +0,0 @@
defmodule EventosWeb.Coherence.ViewHelpers do
@moduledoc """
Helper functions for Coherence Views.
"""
use Phoenix.HTML
alias Coherence.Config
import EventosWeb.Gettext
@type conn :: Plug.Conn.t
@type schema :: Ecto.Schema.t
@seperator {:safe, "&nbsp; | &nbsp;"}
@helpers EventosWeb.Router.Helpers
@recover_link dgettext("coherence", "Forgot your password?")
@unlock_link dgettext("coherence", "Send an unlock email")
@register_link dgettext("coherence", "Need An Account?")
@invite_link dgettext("coherence", "Invite Someone")
@confirm_link dgettext("coherence", "Resend confirmation email")
@signin_link dgettext("coherence", "Sign In")
@signout_link dgettext("coherence", "Sign Out")
@doc """
Create coherence template links.
Generates links if the appropriate option is installed. This function
can be used to:
* create links for the new session page `:new_session`
* create links for your layout template `:layout`
Defaults are provided based on the options configured for Coherence.
However, the defaults can be overridden by passing the following options.
## Customize the links
### :new_session Options
* :recover - customize the recover link (#{@recover_link})
* :unlock - customize the unlock link (#{@unlock_link})
* :register - customize the register link (#{@register_link})
* :confirm - customize the confirm link (#{@confirm_link})
### :layout Options
* :list_tag - customize the list tag (:li)
* :signout_class - customize the class on the signout link ("navbar-form")
* :signin - customize the signin link text (#{@signin_link})
* :signout - customize the signout link text (#{@signout_link})
* :register - customize the register link text (#{@register_link})
### Disable links
If you set an option to false, the link will not be shown. For example, to
disable the register link on the layout, use the following in your layout template:
coherence_links(conn, :layout, register: false)
## Examples
coherence_links(conn, :new_session)
Generates: #{@recover_link} #{@unlock_link} #{@register_link} #{@confirm_link}
coherence_links(conn, :new_session, recover: "Password reset", register: false
Generates: Password reset #{@unlock_link}
coherence_links(conn, :layout) # when logged in
Generates: User's Name #{@signout_link}
coherence_links(conn, :layout) # when not logged in
Generates: #{@register_link} #{@signin_link}
"""
@spec coherence_links(conn, atom, Keyword.t) :: tuple
def coherence_links(conn, which, opts \\ [])
def coherence_links(conn, :new_session, opts) do
recover_link = Keyword.get opts, :recover, @recover_link
unlock_link = Keyword.get opts, :unlock, @unlock_link
register_link = Keyword.get opts, :register, @register_link
confirm_link = Keyword.get opts, :confirm, @confirm_link
user_schema = Coherence.Config.user_schema
[
recover_link(conn, user_schema, recover_link),
unlock_link(conn, user_schema, unlock_link),
register_link(conn, user_schema, register_link),
confirmation_link(conn, user_schema, confirm_link)
]
|> List.flatten
|> concat([])
end
def coherence_links(conn, :layout, opts) do
list_tag = Keyword.get opts, :list_tag, :li
signout_class = Keyword.get opts, :signout_class, "navbar-form"
signin = Keyword.get opts, :signin, @signin_link
signout = Keyword.get opts, :signout, @signout_link
register = Keyword.get opts, :register, @register_link
if Coherence.logged_in?(conn) do
current_user = Coherence.current_user(conn)
[
content_tag(list_tag, profile_link(current_user, conn)),
content_tag(list_tag, signout_link(conn, signout, signout_class))
]
else
signin_link = content_tag(list_tag, link(signin, to: coherence_path(@helpers, :session_path, conn, :new)))
if Config.has_option(:registerable) && register do
[content_tag(list_tag, link(register, to: coherence_path(@helpers, :registration_path, conn, :new))), signin_link]
else
signin_link
end
end
end
@doc """
Helper to avoid compile warnings when options are disabled.
"""
@spec coherence_path(module, atom, conn, atom) :: String.t
def coherence_path(module, route_name, conn, action) do
apply(module, route_name, [conn, action])
end
def coherence_path(module, route_name, conn, action, opts) do
apply(module, route_name, [conn, action, opts])
end
defp concat([], acc), do: Enum.reverse(acc)
defp concat([h|t], []), do: concat(t, [h])
defp concat([h|t], acc), do: concat(t, [h, @seperator | acc])
@spec recover_link(conn, module, false | String.t) :: [any] | []
def recover_link(_conn, _user_schema, false), do: []
def recover_link(conn, user_schema, text) do
if user_schema.recoverable?, do: [recover_link(conn, text)], else: []
end
@spec recover_link(conn, String.t) :: tuple
def recover_link(conn, text \\ @recover_link), do:
link(text, to: coherence_path(@helpers, :password_path, conn, :new))
@spec register_link(conn, module, false | String.t) :: [any] | []
def register_link(_conn, _user_schema, false), do: []
def register_link(conn, user_schema, text) do
if user_schema.registerable?, do: [register_link(conn, text)], else: []
end
@spec register_link(conn, String.t) :: tuple
def register_link(conn, text \\ @register_link), do:
link(text, to: coherence_path(@helpers, :registration_path, conn, :new))
@spec unlock_link(conn, module, false | String.t) :: [any] | []
def unlock_link(_conn, _user_schema, false), do: []
def unlock_link(conn, _user_schema, text) do
if conn.assigns[:locked], do: [unlock_link(conn, text)], else: []
end
@spec unlock_link(conn, String.t) :: tuple
def unlock_link(conn, text \\ @unlock_link), do:
link(text, to: coherence_path(@helpers, :unlock_path, conn, :new))
@spec invitation_link(conn, String.t) :: tuple
def invitation_link(conn, text \\ @invite_link) do
link text, to: coherence_path(@helpers, :invitation_path, conn, :new)
end
@spec signout_link(conn, String.t, String.t) :: tuple
def signout_link(conn, text \\ @signout_link, signout_class \\ "") do
link(text, to: coherence_path(@helpers, :session_path, conn, :delete), method: :delete, class: signout_class)
end
@spec confirmation_link(conn, module, false | String.t) :: [any] | []
def confirmation_link(_conn, _user_schema, false), do: []
def confirmation_link(conn, user_schema, text) do
if user_schema.confirmable?, do: [confirmation_link(conn, text)], else: []
end
@spec confirmation_link(conn, String.t) :: tuple
def confirmation_link(conn, text \\ @confirm_link) do
link(text, to: coherence_path(@helpers, :confirmation_path, conn, :new))
end
@spec required_label(atom, String.t | atom, Keyword.t) :: tuple
def required_label(f, name, opts \\ []) do
label f, name, opts do
[
"#{humanize(name)}\n",
content_tag(:abbr, "*", class: "required", title: "required")
]
end
end
@spec current_user(conn) :: schema
def current_user(conn) do
Coherence.current_user(conn)
end
@spec logged_in?(conn) :: boolean
def logged_in?(conn) do
Coherence.logged_in?(conn)
end
defp profile_link(current_user, conn) do
if Config.user_schema.registerable? do
link current_user.name, to: coherence_path(@helpers, :registration_path, conn, :show)
else
current_user.name
end
end
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.ConfirmationView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.EmailView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.InvitationView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.LayoutView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.PasswordView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.RegistrationView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.SessionView do
use EventosWeb.Coherence, :view
end

View file

@ -1,3 +0,0 @@
defmodule EventosWeb.Coherence.UnlockView do
use EventosWeb.Coherence, :view
end

View file

@ -0,0 +1,7 @@
defmodule EventosWeb.SessionView do
use EventosWeb, :view
def render("token.json", %{token: token}) do
%{token: token}
end
end

View file

@ -20,7 +20,7 @@ defmodule Eventos.Mixfile do
def application do def application do
[ [
mod: {Eventos.Application, []}, mod: {Eventos.Application, []},
extra_applications: [:logger, :runtime_tools, :coherence] extra_applications: [:logger, :runtime_tools, :guardian]
] ]
end end
@ -41,7 +41,9 @@ defmodule Eventos.Mixfile do
{:phoenix_live_reload, "~> 1.0", only: :dev}, {:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"}, {:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"}, {:cowboy, "~> 1.0"},
{:coherence, "~> 0.5"} {:guardian, "~> 1.0"},
{:comeonin, "~> 4.0"},
{:argon2_elixir, "~> 1.2"}
] ]
end end

View file

@ -1,32 +1,36 @@
%{"certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [], [], "hexpm"}, %{"argon2_elixir": {:hex, :argon2_elixir, "1.2.14", "0fc4bfbc1b7e459954987d3d2f3836befd72d63f3a355e3978f5005dd6e80816", [], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [], [], "hexpm"},
"certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [], [], "hexpm"},
"coherence": {:hex, :coherence, "0.5.0", "aaa785aa29e47d140030502b66b08fb58ec84e8120acbfaa6e6a61d3322ffa76", [], [{:comeonin, "~> 3.0", [hex: :comeonin, repo: "hexpm", optional: false]}, {:ecto, "~> 2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_swoosh, "~> 0.2", [hex: :phoenix_swoosh, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}, {:timex_ecto, "~> 3.1", [hex: :timex_ecto, repo: "hexpm", optional: false]}, {:uuid, "~> 1.0", [hex: :uuid, repo: "hexpm", optional: false]}], "hexpm"}, "coherence": {:hex, :coherence, "0.5.0", "aaa785aa29e47d140030502b66b08fb58ec84e8120acbfaa6e6a61d3322ffa76", [], [{:comeonin, "~> 3.0", [hex: :comeonin, repo: "hexpm", optional: false]}, {:ecto, "~> 2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_swoosh, "~> 0.2", [hex: :phoenix_swoosh, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}, {:timex_ecto, "~> 3.1", [hex: :timex_ecto, repo: "hexpm", optional: false]}, {:uuid, "~> 1.0", [hex: :uuid, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [], [], "hexpm"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [], [], "hexpm"},
"comeonin": {:hex, :comeonin, "3.2.0", "cb10995a22aed6812667efb3856f548818c85d85394d8132bc116fbd6995c1ef", [], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"}, "comeonin": {:hex, :comeonin, "4.0.3", "4e257dcb748ed1ca2651b7ba24fdbd1bd24efd12482accf8079141e3fda23a10", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [], [], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [], [], "hexpm"}, "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "db_connection": {:hex, :db_connection, "1.1.2", "2865c2a4bae0714e2213a0ce60a1b12d76a6efba0c51fbda59c9ab8d1accc7a8", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [], [], "hexpm"}, "decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.7", "2074106ff4a5cd9cb2b54b12ca087c4b659ddb3f6b50be4562883c1d763fb031", [], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "2.2.7", "2074106ff4a5cd9cb2b54b12ca087c4b659ddb3f6b50be4562883c1d763fb031", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.4.0", "992f38fabe705bb45821a728f20914c554b276838433349d4f2341f7a687cddf", [], [], "hexpm"}, "elixir_make": {:hex, :elixir_make, "0.4.0", "992f38fabe705bb45821a728f20914c554b276838433349d4f2341f7a687cddf", [], [], "hexpm"},
"file_system": {:hex, :file_system, "0.2.2", "7f1e9de4746f4eb8a4ca8f2fbab582d84a4e40fa394cce7bfcb068b988625b06", [], [], "hexpm"}, "file_system": {:hex, :file_system, "0.2.2", "7f1e9de4746f4eb8a4ca8f2fbab582d84a4e40fa394cce7bfcb068b988625b06", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [], [], "hexpm"}, "gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], [], "hexpm"},
"guardian": {:hex, :guardian, "1.0.0", "21bae2a8c0b4ed5943d9da0c6aeb16e52874c1f675de5d7920ae35471c6263f9", [], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}, {:uuid, ">= 1.1.1", [hex: :uuid, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [], [], "hexpm"},
"mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [], [], "hexpm"}, "mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "3.3.0", "702f6e164512853d29f9d20763493f2b3bcfcb44f118af2bc37bb95d0801b480", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.10.5", "4f9df6b0fb7422a9440a73182a566cb9cbe0e3ffe8884ef9337ccf284fc1ef0a", [], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.10.5", "4f9df6b0fb7422a9440a73182a566cb9cbe0e3ffe8884ef9337ccf284fc1ef0a", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.3", "1d178429fc8950b12457d09c6afec247bfe1fcb6f36209e18fbb0221bdfe4d41", [], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.3", "1d178429fc8950b12457d09c6afec247bfe1fcb6f36209e18fbb0221bdfe4d41", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [], [], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [:mix], [], "hexpm"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"},
"plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"}, "plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [], [], "hexpm"}, "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}, "postgrex": {:hex, :postgrex, "0.13.3", "c277cfb2a9c5034d445a722494c13359e361d344ef6f25d604c2353185682bfc", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"},
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [], [], "hexpm"}, "ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [], [], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [], [], "hexpm"},
"swoosh": {:hex, :swoosh, "0.11.0", "5317c3df2708d14f6ce53aa96b38233aa73ff67c41fac26d8aacc733c116d7a4", [], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.12", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, "swoosh": {:hex, :swoosh, "0.11.0", "5317c3df2708d14f6ce53aa96b38233aa73ff67c41fac26d8aacc733c116d7a4", [], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.12", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"timex": {:hex, :timex, "3.1.24", "d198ae9783ac807721cca0c5535384ebdf99da4976be8cefb9665a9262a1e9e3", [], [{:combine, "~> 0.7", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "timex": {:hex, :timex, "3.1.24", "d198ae9783ac807721cca0c5535384ebdf99da4976be8cefb9665a9262a1e9e3", [], [{:combine, "~> 0.7", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},

View file

@ -3,14 +3,14 @@ defmodule Eventos.Repo.Migrations.CreateUsers do
def change do def change do
create table(:users) do create table(:users) do
add :username, :string add :email, :string, null: false
add :email, :string add :role, :integer, default: 0, null: false
add :role, :integer, default: 0 add :password_hash, :string
add :account_id, references(:accounts, on_delete: :delete_all, null: false) add :account_id, references(:accounts, on_delete: :delete_all, null: false)
timestamps() timestamps()
end end
create unique_index(:users, [:username]) create unique_index(:users, [:email])
end end
end end

View file

@ -1,32 +0,0 @@
defmodule Eventos.Repo.Migrations.AddCoherenceToUser do
use Ecto.Migration
def change do
alter table(:users) do
# confirmable
add :confirmation_token, :string
add :confirmed_at, :utc_datetime
add :confirmation_sent_at, :utc_datetime
# rememberable
add :remember_created_at, :utc_datetime
# authenticatable
add :password_hash, :string
add :active, :boolean, null: false, default: true
# recoverable
add :reset_password_token, :string
add :reset_password_sent_at, :utc_datetime
# lockable
add :failed_attempts, :integer, default: 0
add :locked_at, :utc_datetime
# trackable
add :sign_in_count, :integer, default: 0
add :current_sign_in_at, :utc_datetime
add :last_sign_in_at, :utc_datetime
add :current_sign_in_ip, :string
add :last_sign_in_ip, :string
# unlockable_with_token
add :unlock_token, :string
end
end
end

View file

@ -1,15 +0,0 @@
defmodule Eventos.Repo.Migrations.CreateCoherenceInvitable do
use Ecto.Migration
def change do
create table(:invitations) do
add :name, :string
add :email, :string
add :token, :string
timestamps()
end
create unique_index(:invitations, [:email])
create index(:invitations, [:token])
end
end

View file

@ -1,19 +0,0 @@
defmodule Eventos.Repo.Migrations.CreateCoherenceRememberable do
use Ecto.Migration
def change do
create table(:rememberables) do
add :series_hash, :string
add :token_hash, :string
add :token_created_at, :utc_datetime
add :user_id, references(:users, on_delete: :delete_all)
timestamps()
end
create index(:rememberables, [:user_id])
create index(:rememberables, [:series_hash])
create index(:rememberables, [:token_hash])
create unique_index(:rememberables, [:user_id, :series_hash, :token_hash])
end
end

View file

@ -12,6 +12,6 @@
Eventos.Repo.delete_all Eventos.Accounts.User Eventos.Repo.delete_all Eventos.Accounts.User
Eventos.Accounts.User.changeset(%Eventos.Accounts.User{}, %{username: "Test User", email: "testuser@example.com", password: "secret", password_confirmation: "secret"}) Eventos.Accounts.User.registration_changeset(%Eventos.Accounts.User{}, %{email: "testuser@example.com", password: "secret", password_confirmation: "secret"})
|> Eventos.Repo.insert! |> Eventos.Repo.insert!