这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/authority_ecto.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ defmodule Authority.Ecto do
@moduledoc """
Provides `Ecto` integration for Authority.
"""
end
end
45 changes: 44 additions & 1 deletion lib/authority_ecto/changeset.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,47 @@ defmodule Authority.Ecto.Changeset do
@moduledoc """
Convenient authentication-related functions for `Ecto.Changeset`s.
"""
end

import Ecto.Changeset

@doc """
Based on the token's `purpose`, assign an `expires_at` timestamp. The value
of the `purpose` field should correspond to a key in the `config` list.

## Examples

iex> put_token_expiration(changeset, :expires_at, :purpose, recovery: {24, :hours})
%Ecto.Changeset{}

"""
def put_token_expiration(changeset, expiration_field, purpose_field, config)
when is_list(config) or is_map(config) do
expires_at =
config
|> get_in([get_change(changeset, purpose_field)])
|> parse_timespec()

if expires_at do
put_change(changeset, expiration_field, expires_at)
else
changeset
end
end

defp parse_timespec(nil), do: nil

defp parse_timespec({n, :hours}) do
parse_timespec({n * 60, :minutes})
end

defp parse_timespec({n, :minutes}) do
parse_timespec({n * 60, :seconds})
end

defp parse_timespec({n, :seconds}) do
DateTime.utc_now()
|> DateTime.to_unix()
|> Kernel.+(n)
|> DateTime.from_unix!()
end
end
2 changes: 1 addition & 1 deletion lib/authority_ecto/template.ex
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
defmodule Authority.Ecto.Template do
# TODO: Extract Authority.Template here
end
end
8 changes: 6 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ defmodule Authority.Ecto.MixProject do
[
app: :authority_ecto,
version: "0.1.0",
elixir: "~> 1.7-dev",
elixir: "~> 1.5",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps()
]
Expand All @@ -18,6 +19,9 @@ defmodule Authority.Ecto.MixProject do
]
end

defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_env), do: ["lib"]

# Run "mix help deps" to learn about dependencies.
defp deps do
[
Expand All @@ -26,4 +30,4 @@ defmodule Authority.Ecto.MixProject do
{:ex_doc, ">= 0.0.0", only: [:dev, :test]}
]
end
end
end
39 changes: 38 additions & 1 deletion test/authority_ecto/changeset_test.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
defmodule Authority.Ecto.ChangesetTest do
use ExUnit.Case, async: true
end

import Ecto.Changeset

alias Authority.Ecto.Changeset
alias Authority.Ecto.Test.Token

@expirations %{
"72_hours" => {72, :hours}
}

test "put_token_expiration/3 sets the expires_at" do
changeset =
%Token{}
|> Token.changeset(%{purpose: "72_hours"})
|> Changeset.put_token_expiration(:expires_at, :purpose, @expirations)

actual =
changeset
|> get_change(:expires_at)
|> DateTime.to_unix()

expected =
DateTime.utc_now()
|> DateTime.to_unix()
|> Kernel.+(259_200)

assert_in_delta actual, expected, 5
end

test "put_token_expiration/3 when no timespec is configured" do
changeset =
%Token{}
|> Token.changeset(%{purpose: "baloney"})
|> Changeset.put_token_expiration(:expires_at, :purpose, @expirations)

refute get_change(changeset, :expires_at)
end
end
2 changes: 1 addition & 1 deletion test/authority_ecto_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ defmodule Authority.EctoTest do
use ExUnit.Case

doctest Authority.Ecto
end
end
15 changes: 15 additions & 0 deletions test/support/token.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Authority.Ecto.Test.Token do
use Ecto.Schema
import Ecto.Changeset

schema "tokens" do
field(:token, :string)
field(:purpose, :string)
field(:expires_at, :utc_datetime)
end

def changeset(token, attrs \\ %{}) do
token
|> cast(attrs, [:purpose])
end
end