diff --git a/.travis.yml b/.travis.yml
index af78bc1d..7f3f7c55 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: elixir
elixir:
- - 1.7
+ - 1.9
otp_release:
- 22.0
env:
diff --git a/README.md b/README.md
index f2a0e7e2..6d72c812 100644
--- a/README.md
+++ b/README.md
@@ -499,6 +499,11 @@ To start your Phoenix server:
export URL=dwylapp.herokuapp.com
export SECRET_KEY_BASE=l1Uyq50pB+q7NYDtSSNOJOxZJugfsnXoGmjTV1ShtdG/dPo2BxD9A9JzLHbjpR2j
```
+ - ENCRYPTION_KEYS: The keys used to encrypt google tokens. You can create a new key with the following iex code:
+ ```elixir
+ :crypto.strong_rand_bytes(32) |> :base64.encode
+ ```
+
* run `source .env` to load the enviroment variables
* Make sure you have Postgres installed, see: https://github.com/dwyl/learn-postgresql
* Install dependencies with `mix deps.get`
diff --git a/assets/css/app.css b/assets/css/app.css
index 9111c628..f2851648 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -10,10 +10,14 @@ body {
margin: 0;
}
-main {
- height: 90%;
-}
+/* from https://git.io/Je174 */
+.dwyl-teal {
+ color: #4BC0A9;
+}
+.dwyl-bg-teal {
+ background-color: #4BC0A9;
+}
.resize-none { resize: none; }
\ No newline at end of file
diff --git a/config/config.exs b/config/config.exs
index 52ce71c8..f902f1c9 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -27,4 +27,18 @@ config :phoenix, :json_library, Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
+
+config :fields, Fields.AES,
+ keys:
+ System.get_env("ENCRYPTION_KEYS")
+ # remove single-quotes around key list in .env
+ |> String.replace("'", "")
+ # split the CSV list of keys
+ |> String.split(",")
+ # decode the key.
+ |> Enum.map(fn key -> :base64.decode(key) end)
+
+config :fields, Fields,
+ secret_key_base: System.get_env("SECRET_KEY_BASE")
+
import_config "#{Mix.env()}.exs"
diff --git a/config/test.exs b/config/test.exs
index 918d0999..2dbfcbd6 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -16,3 +16,6 @@ config :app, AppWeb.Endpoint,
# Print only warnings and errors during test
config :logger, level: :warn
+
+# mock elixir_auth_google
+config :app, :elixir_auth_google, App.ElixirAuthGoogle.Mock
diff --git a/elixir_buildpack.config b/elixir_buildpack.config
index 0d0eef77..cbde1b79 100644
--- a/elixir_buildpack.config
+++ b/elixir_buildpack.config
@@ -1,5 +1,5 @@
-erlang_version=20.1
-elixir_version=1.7.0
+erlang_version=22.0
+elixir_version=1.9.0
always_rebuild=false
runtime_path=/app
hook_post_compile="mix ecto.migrate"
diff --git a/lib/app/ctx.ex b/lib/app/ctx.ex
index 9da06098..6f74ab54 100644
--- a/lib/app/ctx.ex
+++ b/lib/app/ctx.ex
@@ -185,6 +185,10 @@ defmodule App.Ctx do
Repo.delete(status)
end
+ def get_status_verified() do
+ Repo.get_by(Status, text: "verified")
+ end
+
@doc """
Returns an `%Ecto.Changeset{}` for tracking status changes.
@@ -227,7 +231,17 @@ defmodule App.Ctx do
** (Ecto.NoResultsError)
"""
- def get_person!(id), do: Repo.get!(Person, id)
+ def get_person!(id) do
+ Repo.get!(Person, id)
+ # |> Repo.preload(sessions: :person)
+ end
+
+ @doc """
+ Get a person by email
+ """
+ def get_person_by_email(email) do
+ Repo.get_by(Person, email_hash: email)
+ end
@doc """
Creates a person.
@@ -247,6 +261,25 @@ defmodule App.Ctx do
|> Repo.insert()
end
+
+ @doc """
+ Create a person from Google profile
+ """
+ def create_google_person(attrs \\ %{}) do
+ %Person{}
+ |> Person.google_changeset(attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Register a person with email/password
+ """
+ def register_person(attrs \\ %{}) do
+ %Person{}
+ |> Person.changeset_registration(attrs)
+ |> Repo.insert()
+ end
+
@doc """
Updates a person.
@@ -581,4 +614,23 @@ defmodule App.Ctx do
def change_timer(%Timer{} = timer) do
Timer.changeset(timer, %{})
end
+
+ alias App.Ctx.Session
+ @doc """
+ Create a session
+ """
+ def create_session(user, attrs \\ %{}) do
+ Session.changeset(user, attrs)
+ |> Repo.insert()
+ end
+
+ @doc """
+ Create a basic session
+ """
+ def create_basic_session(user, attrs \\ %{}) do
+ Session.basic_changeset(user, attrs)
+ |> Repo.insert()
+ end
+
+
end
diff --git a/lib/app/ctx/person.ex b/lib/app/ctx/person.ex
index 14a2b75b..ceb679b3 100644
--- a/lib/app/ctx/person.ex
+++ b/lib/app/ctx/person.ex
@@ -3,24 +3,118 @@ defmodule App.Ctx.Person do
import Ecto.Changeset
schema "people" do
- field :email, :binary
- field :email_hash, :binary
- field :familyName, :binary
- field :givenName, :binary
- field :key_id, :integer
- field :password_hash, :binary
+ field :email, Fields.EmailEncrypted
+ field :email_hash, Fields.EmailHash
+ field :familyName, Fields.Encrypted
+ field :givenName, Fields.Encrypted
+ field :locale, :string
+ field :password, :string, virtual: true
+ field :password_hash, Fields.Password
+ field :picture, :binary
field :username, :binary
- field :username_hash, :binary
+ field :username_hash, Fields.Hash
field :status, :id
field :tag, :id
+ field :key_id, :integer
+ has_many :sessions, App.Ctx.Session, on_delete: :delete_all
timestamps()
end
@doc false
def changeset(person, attrs) do
person
- |> cast(attrs, [:username, :username_hash, :email, :email_hash, :givenName, :familyName, :password_hash, :key_id])
- |> validate_required([:username, :username_hash, :email, :email_hash, :givenName, :familyName, :password_hash, :key_id])
+ |> cast(attrs, [:username, :email, :givenName, :familyName, :password_hash, :key_id, :locale, :picture])
+ |> validate_required([:username, :email, :givenName, :familyName, :password_hash, :key_id])
+ |> put_email_hash()
+ end
+
+ def google_changeset(profile, attrs) do
+ profile
+ |> cast(attrs, [:email, :givenName, :familyName, :picture, :locale])
+ |> validate_required([:email])
+ |> put_email_hash()
+ |> put_email_status_verified()
+ end
+
+ defp put_email_hash(changeset) do
+ case changeset do
+ %{valid?: true, changes: %{email: email}} ->
+ put_change(changeset, :email_hash, email)
+
+ _ ->
+ changeset
+ end
+ end
+
+ defp put_email_status_verified(changeset) do
+ status_verified = App.Ctx.get_status_verified()
+ case changeset do
+ %{valid?: true} ->
+ put_change(changeset, :status, status_verified.id)
+
+ _ ->
+ changeset
+ end
end
+
+ @doc """
+ `transform_profile_data_to_person/1` transforms the profile data
+ received from invoking `ElixirAuthGoogle.get_user_profile/1`
+ into a `person` record that can be inserted into the people table.
+
+ ## Example
+
+ iex> transform_profile_data_to_person(%{
+ "email" => "nelson@gmail.com",
+ "email_verified" => true,
+ "family_name" => "Correia",
+ "given_name" => "Nelson",
+ "locale" => "en",
+ "name" => "Nelson Correia",
+ "picture" => "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7a",
+ "sub" => "940732358705212133793"
+ })
+ %{
+ "email" => "nelson@gmail.com",
+ "email_verified" => true,
+ "family_name" => "Correia",
+ "given_name" => "Nelson",
+ "locale" => "en",
+ "name" => "Nelson Correia",
+ "picture" => "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7a",
+ "sub" => "940732358705212133793"
+ "status" => 1,
+ "familyName" => "Correia",
+ "givenName" => "Nelson"
+ }
+ """
+ def transform_profile_data_to_person(profile) do
+ profile
+ |> Map.put(:familyName, profile.family_name)
+ |> Map.put(:givenName, profile.given_name)
+ |> Map.put(:locale, profile.locale)
+ |> Map.put(:picture, profile.picture)
+ end
+
+ @doc false
+ def changeset_registration(profile, attrs) do
+ profile
+ |> cast(attrs, [:email, :password])
+ |> validate_required([:email, :password])
+ |> validate_length(:password, min: 6, max: 100)
+ |> unique_constraint(:email)
+ |> put_email_hash()
+ |> put_pass_hash()
+ end
+
+ defp put_pass_hash(changeset) do
+ case changeset do
+ %Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
+ put_change(changeset, :password_hash, pass)
+ _ ->
+ changeset
+ end
+ end
+
end
diff --git a/lib/app/ctx/session.ex b/lib/app/ctx/session.ex
new file mode 100644
index 00000000..34aa88dd
--- /dev/null
+++ b/lib/app/ctx/session.ex
@@ -0,0 +1,25 @@
+defmodule App.Ctx.Session do
+ use Ecto.Schema
+ import Ecto.Changeset
+
+ schema "sessions" do
+ field :auth_token, Fields.Encrypted
+ field :refresh_token, Fields.Encrypted
+ field :key_id, :integer
+
+ belongs_to :person, App.Ctx.Person
+ timestamps()
+ end
+
+
+ def changeset(people, attrs) do
+ Ecto.build_assoc(people, :sessions)
+ |> cast(attrs, [:auth_token, :refresh_token])
+ |> validate_required([:auth_token, :refresh_token])
+ end
+
+ def basic_changeset(people, _attrs) do
+ Ecto.build_assoc(people, :sessions)
+ end
+
+end
diff --git a/lib/app_web/controllers/auth_controller.ex b/lib/app_web/controllers/auth_controller.ex
new file mode 100644
index 00000000..54cc2e84
--- /dev/null
+++ b/lib/app_web/controllers/auth_controller.ex
@@ -0,0 +1,45 @@
+defmodule AppWeb.Auth do
+ use AppWeb, :controller
+ # use AppWeb, :router
+ import Plug.Conn
+ # alias App.Repo
+
+ def init(opts), do: opts
+
+ def call(conn, _opts) do
+ person_id = get_session(conn, :person_id)
+ cond do
+ person = conn.assigns[:current_person] ->
+ assign(conn, :current_person, person)
+
+ person = person_id && App.Ctx.get_person!(person_id) ->
+ assign(conn, :current_person, person)
+
+ true ->
+ assign(conn, :current_person, nil)
+ end
+ end
+
+ def login(conn, person) do
+ conn
+ |> assign(:current_person, person)
+ |> put_session(:person_id, person.id)
+ |> configure_session(renew: true)
+ end
+
+ def logout(conn) do
+ configure_session(conn, drop: true)
+ end
+
+
+ def authenticate_person(conn, _opts) do
+ if conn.assigns.current_person do
+ conn
+ else
+ conn
+ # redirect to login page
+ |> redirect(to: Routes.page_path(conn, :index))
+ |> halt()
+ end
+ end
+end
diff --git a/lib/app_web/controllers/google_auth_controller.ex b/lib/app_web/controllers/google_auth_controller.ex
new file mode 100644
index 00000000..d7bc26d0
--- /dev/null
+++ b/lib/app_web/controllers/google_auth_controller.ex
@@ -0,0 +1,39 @@
+defmodule AppWeb.GoogleAuthController do
+ use AppWeb, :controller
+
+ @elixir_auth_google Application.get_env(:app, :elixir_auth_google) || ElixirAuthGoogle
+
+ def index(conn, %{"code" => code}) do
+ {:ok, token} = @elixir_auth_google.get_token(code, conn)
+ {:ok, profile} = @elixir_auth_google.get_user_profile(token.access_token)
+ person = App.Ctx.Person.transform_profile_data_to_person(profile)
+
+ # get the person by email
+ case App.Ctx.get_person_by_email(person.email) do
+ nil ->
+ # Create the person
+ {:ok, person} = App.Ctx.create_google_person(person)
+ create_session(conn, person, token)
+ person ->
+ create_session(conn, person, token)
+ end
+ end
+
+ def create_session(conn, person, token) do
+ # Create session
+ session_attrs = %{
+ "auth_token" => token.access_token,
+ "refresh_token" => if Map.has_key?(token, :refresh_token) do
+ token.refresh_token
+ else
+ nil
+ end
+ }
+ App.Ctx.create_session(person, session_attrs)
+
+ # login and redirect to welcome page:
+ AppWeb.Auth.login(conn, person)
+ |> redirect(to: Routes.person_path(conn, :info))
+ end
+end
+
diff --git a/lib/app_web/controllers/page_controller.ex b/lib/app_web/controllers/page_controller.ex
index 2941548d..a4668688 100644
--- a/lib/app_web/controllers/page_controller.ex
+++ b/lib/app_web/controllers/page_controller.ex
@@ -1,7 +1,58 @@
defmodule AppWeb.PageController do
use AppWeb, :controller
+ alias App.Ctx.Person
+ alias App.Ctx
+
+ # auth_controller assign current_person on each request
+ # when the person is loggedin, otherwise the value doesn't exists or is nil
+ def index(%{assigns: %{current_person: person}} = conn, _params) when not is_nil(person) do
+ redirect(conn, to: Routes.person_path(conn, :info))
+ end
def index(conn, _params) do
- render(conn, "index.html")
+ url_oauth_google = ElixirAuthGoogle.generate_oauth_url(conn)
+ changeset = Person.changeset_registration(%Person{}, %{})
+ render(conn, "index.html",
+ [url_oauth_google: url_oauth_google, changeset: changeset])
+ end
+
+
+ def register(conn, %{"person" => person_params}) do
+ person = Ctx.get_person_by_email(person_params["email"])
+
+ if is_nil(person) do #create new person
+ case Ctx.register_person(person_params) do
+ {:ok, person} ->
+ create_basic_session(conn, person)
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ url_oauth_google = ElixirAuthGoogle.generate_oauth_url(conn)
+ render(conn, "index.html",
+ [url_oauth_google: url_oauth_google, changeset: changeset])
+ end
+ else # Login person if password ok
+ login(conn, person, person_params)
+ end
+ end
+
+ # verify provided password
+ # create Phx session
+ # and redirect to correct page:
+ # user info page if password ok or index page if it doesn't match
+ defp login(conn, person, person_params) do
+ if Argon2.verify_pass(person_params["password"], person.password_hash) do
+ create_basic_session(conn, person)
+ else
+ redirect(conn, to: Routes.page_path(conn, :index))
+ end
+ end
+
+ # Insert a new basic session in Postgres
+ defp create_basic_session(conn, person) do
+ App.Ctx.create_basic_session(person, %{})
+
+ AppWeb.Auth.login(conn, person)
+ |> redirect(to: Routes.person_path(conn, :info))
end
end
+
diff --git a/lib/app_web/controllers/person_controller.ex b/lib/app_web/controllers/person_controller.ex
index a0967fc9..b2f906c6 100644
--- a/lib/app_web/controllers/person_controller.ex
+++ b/lib/app_web/controllers/person_controller.ex
@@ -59,4 +59,8 @@ defmodule AppWeb.PersonController do
|> put_flash(:info, "Person deleted successfully.")
|> redirect(to: Routes.person_path(conn, :index))
end
+
+ def info(%{assigns: %{current_person: person}} = conn, _params) do
+ render(conn, "info.html", person: person)
+ end
end
diff --git a/lib/app_web/controllers/sessions_controller.ex b/lib/app_web/controllers/sessions_controller.ex
new file mode 100644
index 00000000..a13631cf
--- /dev/null
+++ b/lib/app_web/controllers/sessions_controller.ex
@@ -0,0 +1,9 @@
+defmodule AppWeb.SessionController do
+ use AppWeb, :controller
+
+ def delete(conn, _params) do
+ conn
+ |> AppWeb.Auth.logout()
+ |> redirect(to: Routes.page_path(conn, :index))
+ end
+end
diff --git a/lib/app_web/router.ex b/lib/app_web/router.ex
index d5b73282..b2e5d9a6 100644
--- a/lib/app_web/router.ex
+++ b/lib/app_web/router.ex
@@ -1,5 +1,6 @@
defmodule AppWeb.Router do
use AppWeb, :router
+ import AppWeb.Auth
pipeline :browser do
plug :accepts, ["html"]
@@ -7,16 +8,30 @@ defmodule AppWeb.Router do
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
+ plug AppWeb.Auth
end
pipeline :api do
plug :accepts, ["json"]
end
+ pipeline :person do
+ plug :authenticate_person
+ end
+
scope "/", AppWeb do
pipe_through :browser
get "/", PageController, :index
+ post "/register", PageController, :register
+ get "/auth/google/callback", GoogleAuthController, :index
+ end
+
+ scope "/", AppWeb do
+ pipe_through [:browser, :person]
+
+ # person information
+ get "/people/info", PersonController, :info
# generic resources for schemas:
resources "/items", ItemController
@@ -26,6 +41,7 @@ defmodule AppWeb.Router do
resources "/tags", TagController
resources "/timers", TimerController
+
# capture
resources "/capture", CaptureController, only: [:new, :create]
diff --git a/lib/app_web/templates/layout/app.html.eex b/lib/app_web/templates/layout/app.html.eex
index 738eb70d..0516576c 100644
--- a/lib/app_web/templates/layout/app.html.eex
+++ b/lib/app_web/templates/layout/app.html.eex
@@ -6,11 +6,27 @@
dwyl app
"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
diff --git a/lib/app_web/templates/page/index.html.eex b/lib/app_web/templates/page/index.html.eex
index a399c35f..e996400b 100644
--- a/lib/app_web/templates/page/index.html.eex
+++ b/lib/app_web/templates/page/index.html.eex
@@ -1,9 +1,40 @@
- Empower people to maximise effectiveness, creativity and happiness
+
+ dwyl
+ Unlock a new level of personal effectiveness .
- <%=link("Capture", to: Routes.capture_path(@conn, :new), class: "f6 b link dim br2 ph3 pv2 db white bg-dark-blue center w4 ma4") %>
+
+
+
+
+
+
+
+OR
+
+ <%= form_for @changeset, Routes.page_path(@conn, :register), fn f -> %>
+
+<%= email_input f, :email, placeholder: "email address" %>
+
+ <%= error_tag f, :email %>
+
+
+
+ <%= password_input f, :password, placeholder: "password" %>
+
+ <%= error_tag f, :password%>
+
+
+
+ <%= submit "Login / Register", class: "pointer f6 link br1 ph3 pv2 mb2 dib white dwyl-bg-teal" %>
+
+ <% end %>
+
diff --git a/lib/app_web/templates/person/form.html.eex b/lib/app_web/templates/person/form.html.eex
index 98ac10b6..d9b68067 100644
--- a/lib/app_web/templates/person/form.html.eex
+++ b/lib/app_web/templates/person/form.html.eex
@@ -17,10 +17,6 @@
<%= text_input f, :email %>
<%= error_tag f, :email %>
- <%= label f, :email_hash %>
- <%= text_input f, :email_hash %>
- <%= error_tag f, :email_hash %>
-
<%= label f, :givenName %>
<%= text_input f, :givenName %>
<%= error_tag f, :givenName %>
diff --git a/lib/app_web/templates/person/info.html.eex b/lib/app_web/templates/person/info.html.eex
new file mode 100644
index 00000000..551414cd
--- /dev/null
+++ b/lib/app_web/templates/person/info.html.eex
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Hello <%= @person.givenName %>!
+
+ You are signed in
+ with
+
+ <%= @person.email %>
+
+
+
+
+<%= link "Capture", to: Routes.capture_path(@conn, :new) %>
\ No newline at end of file
diff --git a/lib/app_web/views/google_auth_view.ex b/lib/app_web/views/google_auth_view.ex
new file mode 100644
index 00000000..c966fc02
--- /dev/null
+++ b/lib/app_web/views/google_auth_view.ex
@@ -0,0 +1,3 @@
+defmodule AppWeb.GoogleAuthView do
+ use AppWeb, :view
+end
diff --git a/lib/app_web/views/page_view.ex b/lib/app_web/views/page_view.ex
index 8ba34d2e..53d7bb7f 100644
--- a/lib/app_web/views/page_view.ex
+++ b/lib/app_web/views/page_view.ex
@@ -1,3 +1,7 @@
defmodule AppWeb.PageView do
use AppWeb, :view
+
+ def authenticated?(person) do
+ Map.has_key?(person, :email) && String.length( person["email"] ) > 0
+ end
end
diff --git a/lib/elixir_auth_google/mock.ex b/lib/elixir_auth_google/mock.ex
new file mode 100644
index 00000000..f61f6024
--- /dev/null
+++ b/lib/elixir_auth_google/mock.ex
@@ -0,0 +1,20 @@
+defmodule App.ElixirAuthGoogle.Mock do
+ def get_token(_code, _conn) do
+ {:ok, %{:access_token => "token"}}
+ end
+
+ def get_user_profile(_token) do
+ {:ok,
+ %{
+ email: "nelson@gmail.com",
+ email_verified: true,
+ family_name: "Correia",
+ given_name: "Nelson",
+ locale: "en",
+ name: "Nelson Correia",
+ picture: "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7a",
+ sub: "940732358705212133793"
+ }
+ }
+ end
+end
diff --git a/mix.exs b/mix.exs
index a62d2440..3cc2d0de 100644
--- a/mix.exs
+++ b/mix.exs
@@ -5,7 +5,7 @@ defmodule App.MixProject do
[
app: :app,
version: "0.1.0",
- elixir: "~> 1.7",
+ elixir: "~> 1.9",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
@@ -50,7 +50,14 @@ defmodule App.MixProject do
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"},
+ {:elixir_auth_google, "~> 1.0.2" },
+ {:fields, "~> 2.1.0"},
+
+ # create docs on localhost by running "mix docs"
+ {:ex_doc, "~> 0.21", only: :dev, runtime: false},
+ # track test coverage
{:excoveralls, "~> 0.12.1", only: [:test, :dev]},
+ # git pre-commit hook runs tests before allowing commits
{:pre_commit, "~> 0.3.4"},
{:credo, "~> 1.1.0", only: [:dev, :test], runtime: false}
]
@@ -66,7 +73,7 @@ defmodule App.MixProject do
[
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
- test: ["ecto.create --quiet", "ecto.migrate", "test"]
+ test: ["ecto.create --quiet", "ecto.migrate", "run priv/repo/seeds.exs", "test"]
]
end
end
diff --git a/mix.lock b/mix.lock
index ad21b97d..09cefbb3 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,36 +1,50 @@
%{
+ "argon2_elixir": {:hex, :argon2_elixir, "2.1.2", "c276b960f0b550a7613a9bebf8e14645ca5eb71a34a1bf0f896fe3511966b051", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
+ "comeonin": {:hex, :comeonin, "5.1.3", "4c9880ed348cc0330c74086b4383ffb0b5a599aa603416497b7374c168cae340", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
- "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
- "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
+ "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
+ "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"},
"credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"db_connection": {:hex, :db_connection, "2.1.1", "a51e8a2ee54ef2ae6ec41a668c85787ed40cb8944928c191280fe34c15b76ae5", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
- "ecto": {:hex, :ecto, "3.2.1", "a0f9af0fb50b19d3bb6237e512ac0ba56ea222c2bbea92e7c6c94897932c76ba", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
- "ecto_sql": {:hex, :ecto_sql, "3.2.0", "751cea597e8deb616084894dd75cbabfdbe7255ff01e8c058ca13f0353a3921b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
+ "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
+ "ecto": {:hex, :ecto, "3.2.5", "76c864b77948a479e18e69cc1d0f0f4ee7cced1148ffe6a093ff91eba644f0b5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
+ "ecto_sql": {:hex, :ecto_sql, "3.2.2", "d10845bc147b9f61ef485cbf0973c0a337237199bd9bd30dd9542db00aadc26b", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.2.0 or ~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
+ "elixir_auth_google": {:hex, :elixir_auth_google, "1.0.2", "46a1884d14ba2eb2ab92c33c24bf6366e4c610757c5bea8f95e674ff3ae2bd6c", [:mix], [{:httpoison, "~> 1.6", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 4.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
+ "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
+ "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.12.1", "a553c59f6850d0aff3770e4729515762ba7c8e41eedde03208182a8dc9d0ce07", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
+ "fields": {:hex, :fields, "2.1.0", "1dc42be9c7b518fde38e37c0f2ce7ea97f9b23c21fd661a11fc92da99e8d7f01", [:mix], [{:argon2_elixir, "~> 2.1.2", [hex: :argon2_elixir, repo: "hexpm", optional: false]}, {:ecto, "~> 3.2.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:html_sanitize_ex, "~> 1.3", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}], "hexpm"},
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
- "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
+ "gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
+ "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.0", "0310d27d7bafb662f30bff22ec732a72414799c83eaf44239781fd23b96216c0", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
+ "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
+ "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
+ "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
+ "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
+ "nimble_parsec": {:hex, :nimble_parsec, "0.5.2", "1d71150d5293d703a9c38d4329da57d3935faed2031d64bc19e77b654ef2d177", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
- "phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
- "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [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": {:hex, :phoenix, "1.4.11", "d112c862f6959f98e6e915c3b76c7a87ca3efd075850c8daa7c3c7a609014b0d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
+ "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [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.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.1", "274a4b07c4adbdd7785d45a8b0bb57634d0b4f45b18d2c508b26c0344bd59b8f", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.8.3", "12d5f9796dc72e8ac9614e94bda5e51c4c028d0d428e9297650d09e15a684478", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
- "postgrex": {:hex, :postgrex, "0.15.1", "23ce3417de70f4c0e9e7419ad85bdabcc6860a6925fe2c6f3b1b5b1e8e47bf2f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
+ "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm"},
+ "postgrex": {:hex, :postgrex, "0.15.2", "052dad08d934863d1a4dcbd48ae7fc2af21a8535f556121e91b13b2884b0965a", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"pre_commit": {:hex, :pre_commit, "0.3.4", "e2850f80be8090d50ad8019ef2426039307ff5dfbe70c736ad0d4d401facf304", [:mix], [], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
- "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
+ "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
}
diff --git a/priv/repo/migrations/20191126144556_create_session_table.exs b/priv/repo/migrations/20191126144556_create_session_table.exs
new file mode 100644
index 00000000..7705c9d3
--- /dev/null
+++ b/priv/repo/migrations/20191126144556_create_session_table.exs
@@ -0,0 +1,15 @@
+defmodule App.Repo.Migrations.CreateSessionTable do
+ use Ecto.Migration
+
+ def change do
+ create table(:sessions) do
+ add :auth_token, :binary
+ add :refresh_token, :binary
+ add :key_id, :integer
+
+ # keep sessions when user is deleted
+ add :person_id, references(:people, on_delete: :nothing)
+ timestamps()
+ end
+ end
+end
diff --git a/priv/repo/migrations/20191130210036_add_picture_locale_to_people.exs b/priv/repo/migrations/20191130210036_add_picture_locale_to_people.exs
new file mode 100644
index 00000000..e0cddd6a
--- /dev/null
+++ b/priv/repo/migrations/20191130210036_add_picture_locale_to_people.exs
@@ -0,0 +1,10 @@
+defmodule App.Repo.Migrations.AddPictureLocaleToPeople do
+ use Ecto.Migration
+
+ def change do
+ alter table(:people) do
+ add :picture, :binary
+ add :locale, :string, default: "en"
+ end
+ end
+end
diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs
index fe3037bf..d448b9d6 100644
--- a/priv/repo/seeds.exs
+++ b/priv/repo/seeds.exs
@@ -1,11 +1,2 @@
-# Script for populating the database. You can run it as:
-#
-# mix run priv/repo/seeds.exs
-#
-# Inside the script, you can read and write to any of your
-# repositories directly:
-#
-# App.Repo.insert!(%App.SomeSchema{})
-#
-# We recommend using the bang functions (`insert!`, `update!`
-# and so on) as they will fail if something goes wrong.
+App.Ctx.create_status(%{text: "unverified"})
+App.Ctx.create_status(%{text: "verified"})
diff --git a/test/app/ctx_test.exs b/test/app/ctx_test.exs
index 54064617..10f3b0ce 100644
--- a/test/app/ctx_test.exs
+++ b/test/app/ctx_test.exs
@@ -80,7 +80,7 @@ defmodule App.CtxTest do
test "list_status/0 returns all status" do
status = status_fixture()
- assert Ctx.list_status() == [status]
+ assert Enum.count(Ctx.list_status()) > 1
end
test "get_status!/1 returns the status with given id" do
@@ -123,9 +123,8 @@ defmodule App.CtxTest do
describe "people" do
alias App.Ctx.Person
-
- @valid_attrs %{email: "some email", email_hash: "some email_hash", familyName: "some familyName", givenName: "some givenName", key_id: 42, password_hash: "some password_hash", username: "some username", username_hash: "some username_hash"}
- @update_attrs %{email: "some updated email", email_hash: "some updated email_hash", familyName: "some updated familyName", givenName: "some updated givenName", key_id: 43, password_hash: "some updated password_hash", username: "some updated username", username_hash: "some updated username_hash"}
+ @valid_attrs %{email: "a@b.com", email_hash: "some email_hash", familyName: "some familyName", givenName: "some givenName", key_id: 42, password_hash: "some password_hash", username: "some username", username_hash: "some username_hash", locale: "en", picture: "https://imgur.com/a/DFXNawx"}
+ @update_attrs %{email: "c@d.net", email_hash: "some updated email_hash", familyName: "some updated familyName", givenName: "some updated givenName", key_id: 43, password_hash: "some updated password_hash", username: "updated username", username_hash: "updated username_hash"}
@invalid_attrs %{email: nil, email_hash: nil, familyName: nil, givenName: nil, key_id: nil, password_hash: nil, username: nil, username_hash: nil}
def person_fixture(attrs \\ %{}) do
@@ -133,30 +132,31 @@ defmodule App.CtxTest do
attrs
|> Enum.into(@valid_attrs)
|> Ctx.create_person()
-
person
end
test "list_people/0 returns all people" do
- person = person_fixture()
- assert Ctx.list_people() == [person]
+ person_fixture()
+ assert Enum.count(Ctx.list_people()) >= 1
end
test "get_person!/1 returns the person with given id" do
- person = person_fixture()
- assert Ctx.get_person!(person.id) == person
+ person_data = person_fixture()
+ person = Ctx.get_person!(person_data.id)
+
+ assert person_data.email == person.email
end
test "create_person/1 with valid data creates a person" do
assert {:ok, %Person{} = person} = Ctx.create_person(@valid_attrs)
- assert person.email == "some email"
- assert person.email_hash == "some email_hash"
+ assert person.email == "a@b.com"
+ # <<116, 223, 252, 249, 57, 13, 89, 186, 199, 10, 177, 236, 117, 117, 76, 147,
+ # 109, 87, 187, 126, 168, 1, 63, 236, 134, 67, 92, 136, 136, 224, 45, 65>>
assert person.familyName == "some familyName"
assert person.givenName == "some givenName"
assert person.key_id == 42
assert person.password_hash == "some password_hash"
assert person.username == "some username"
- assert person.username_hash == "some username_hash"
end
test "create_person/1 with invalid data returns error changeset" do
@@ -166,20 +166,19 @@ defmodule App.CtxTest do
test "update_person/2 with valid data updates the person" do
person = person_fixture()
assert {:ok, %Person{} = person} = Ctx.update_person(person, @update_attrs)
- assert person.email == "some updated email"
- assert person.email_hash == "some updated email_hash"
+ assert person.email == "c@d.net"
assert person.familyName == "some updated familyName"
assert person.givenName == "some updated givenName"
assert person.key_id == 43
assert person.password_hash == "some updated password_hash"
- assert person.username == "some updated username"
- assert person.username_hash == "some updated username_hash"
end
test "update_person/2 with invalid data returns error changeset" do
person = person_fixture()
assert {:error, %Ecto.Changeset{}} = Ctx.update_person(person, @invalid_attrs)
- assert person == Ctx.get_person!(person.id)
+ person_data = Ctx.get_person!(person.id)
+
+ assert person.id == person_data.id
end
test "delete_person/1 deletes the person" do
diff --git a/test/app_web/controllers/capture_controller_test.exs b/test/app_web/controllers/capture_controller_test.exs
index aab07184..a18670d7 100644
--- a/test/app_web/controllers/capture_controller_test.exs
+++ b/test/app_web/controllers/capture_controller_test.exs
@@ -1,10 +1,12 @@
defmodule AppWeb.CaptureControllerTest do
use AppWeb.ConnCase
+ import App.SetupHelpers
@create_attrs %{text: "some text"}
@invalid_attrs %{text: nil}
describe "new capture" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.capture_path(conn, :new))
assert html_response(conn, 200) =~ "Capture"
@@ -12,6 +14,7 @@ defmodule AppWeb.CaptureControllerTest do
end
describe "create capture" do
+ setup [:person_login]
test "redirects to categorise page when data is valid", %{conn: conn} do
conn = post(conn, Routes.capture_path(conn, :create), item: @create_attrs)
assert redirected_to(conn) == Routes.categorise_path(conn, :index)
diff --git a/test/app_web/controllers/categorise_controller_test.exs b/test/app_web/controllers/categorise_controller_test.exs
index 44514a14..24215821 100644
--- a/test/app_web/controllers/categorise_controller_test.exs
+++ b/test/app_web/controllers/categorise_controller_test.exs
@@ -1,7 +1,9 @@
defmodule AppWeb.CategoriseControllerTest do
use AppWeb.ConnCase
+ import App.SetupHelpers
describe "return captured text" do
+ setup [:person_login]
test "index page for categorise", %{conn: conn} do
conn = get(conn, Routes.categorise_path(conn, :index))
assert html_response(conn, 200) =~ "Captures"
diff --git a/test/app_web/controllers/google_auth_controller_test.exs b/test/app_web/controllers/google_auth_controller_test.exs
new file mode 100644
index 00000000..9c54bd1b
--- /dev/null
+++ b/test/app_web/controllers/google_auth_controller_test.exs
@@ -0,0 +1,41 @@
+defmodule AppWeb.GoogleAuthControllerTest do
+ use AppWeb.ConnCase
+
+ test "transform_profile_data_to_person/1 transforms profile to person" do
+
+ profile = %{
+ email: "nelson@gmail.com",
+ email_verified: true,
+ family_name: "Correia",
+ given_name: "Nelson",
+ locale: "en",
+ name: "Nelson Correia",
+ picture: "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7a",
+ sub: "940732358705212133793"
+ }
+ expected = %{
+ email: "nelson@gmail.com",
+ email_verified: true,
+ familyName: "Correia",
+ family_name: "Correia",
+ givenName: "Nelson",
+ given_name: "Nelson",
+ locale: "en",
+ name: "Nelson Correia",
+ picture: "https://lh3.googleusercontent.com/a-/AAuE7mApnYb260YC1JY7a",
+ sub: "940732358705212133793"
+ }
+ # invoke our transformer function using the sample data:
+ person = App.Ctx.Person.transform_profile_data_to_person(profile)
+
+ assert Map.equal?(expected, person)
+ end
+
+
+ test "GET /", %{conn: conn} do
+ conn = get(conn, Routes.google_auth_path(conn, :index, code: "code"))
+ assert html_response(conn, 302)
+ end
+
+
+end
diff --git a/test/app_web/controllers/item_controller_test.exs b/test/app_web/controllers/item_controller_test.exs
index 92b83968..0b8dd6df 100644
--- a/test/app_web/controllers/item_controller_test.exs
+++ b/test/app_web/controllers/item_controller_test.exs
@@ -1,6 +1,6 @@
defmodule AppWeb.ItemControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
@create_attrs %{text: "some text"}
@@ -13,6 +13,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all items", %{conn: conn} do
conn = get(conn, Routes.item_path(conn, :index))
assert html_response(conn, 200) =~ "Listing Items"
@@ -20,6 +21,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "new item" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.item_path(conn, :new))
assert html_response(conn, 200) =~ "New Item"
@@ -27,6 +29,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "create item" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.item_path(conn, :create), item: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "edit item" do
- setup [:create_item]
+ setup [:person_login, :create_item]
test "renders form for editing chosen item", %{conn: conn, item: item} do
conn = get(conn, Routes.item_path(conn, :edit, item))
@@ -53,7 +56,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "update item" do
- setup [:create_item]
+ setup [:person_login, :create_item]
test "redirects when data is valid", %{conn: conn, item: item} do
conn = put(conn, Routes.item_path(conn, :update, item), item: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.ItemControllerTest do
end
describe "delete item" do
- setup [:create_item]
+ setup [:create_item, :person_login]
test "deletes chosen item", %{conn: conn, item: item} do
conn = delete(conn, Routes.item_path(conn, :delete, item))
diff --git a/test/app_web/controllers/list_controller_test.exs b/test/app_web/controllers/list_controller_test.exs
index 6a9bf0c3..3dda6eaf 100644
--- a/test/app_web/controllers/list_controller_test.exs
+++ b/test/app_web/controllers/list_controller_test.exs
@@ -1,6 +1,6 @@
defmodule AppWeb.ListControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
@create_attrs %{title: "some title"}
@@ -13,6 +13,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all lists", %{conn: conn} do
conn = get(conn, Routes.list_path(conn, :index))
assert html_response(conn, 200) =~ "Listing Lists"
@@ -20,6 +21,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "new list" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.list_path(conn, :new))
assert html_response(conn, 200) =~ "New List"
@@ -27,6 +29,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "create list" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.list_path(conn, :create), list: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "edit list" do
- setup [:create_list]
+ setup [:create_list, :person_login]
test "renders form for editing chosen list", %{conn: conn, list: list} do
conn = get(conn, Routes.list_path(conn, :edit, list))
@@ -53,7 +56,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "update list" do
- setup [:create_list]
+ setup [:create_list, :person_login]
test "redirects when data is valid", %{conn: conn, list: list} do
conn = put(conn, Routes.list_path(conn, :update, list), list: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.ListControllerTest do
end
describe "delete list" do
- setup [:create_list]
+ setup [:create_list, :person_login]
test "deletes chosen list", %{conn: conn, list: list} do
conn = delete(conn, Routes.list_path(conn, :delete, list))
diff --git a/test/app_web/controllers/page_controller_test.exs b/test/app_web/controllers/page_controller_test.exs
index 67cc2e2d..be2fb57d 100644
--- a/test/app_web/controllers/page_controller_test.exs
+++ b/test/app_web/controllers/page_controller_test.exs
@@ -3,6 +3,24 @@ defmodule AppWeb.PageControllerTest do
test "GET /", %{conn: conn} do
conn = get(conn, "/")
- assert html_response(conn, 200) =~ "Empower people to maximise effectiveness, creativity and happiness"
+ assert html_response(conn, 200) =~ "effectiveness"
end
+
+ describe "login/register" do
+ test "display error when password invalid", %{conn: conn} do
+ params = %{"person" => %{"email" => "test@email.com", "password" => "p"}}
+ conn = post(conn, Routes.page_path(conn, :register), params)
+
+ assert html_response(conn, 200) =~ "should be at least 6 character(s)"
+ end
+
+ test "redirects to home", %{conn: conn} do
+ params = %{"person" => %{"email" => "test@email.com", "password" => "password"}}
+ conn = post(conn, Routes.page_path(conn, :register), params)
+
+ assert redirected_to(conn, 302) =~ "/people/info"
+ end
+
+ end
+
end
diff --git a/test/app_web/controllers/person_controller_test.exs b/test/app_web/controllers/person_controller_test.exs
index b6ad7e98..c711f7f5 100644
--- a/test/app_web/controllers/person_controller_test.exs
+++ b/test/app_web/controllers/person_controller_test.exs
@@ -1,10 +1,10 @@
defmodule AppWeb.PersonControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
- @create_attrs %{email: "some email", email_hash: "some email_hash", familyName: "some familyName", givenName: "some givenName", key_id: 42, password_hash: "some password_hash", username: "some username", username_hash: "some username_hash"}
- @update_attrs %{email: "some updated email", email_hash: "some updated email_hash", familyName: "some updated familyName", givenName: "some updated givenName", key_id: 43, password_hash: "some updated password_hash", username: "some updated username", username_hash: "some updated username_hash"}
+ @create_attrs %{email: "a@b.com", email_hash: "some email_hash", familyName: "some familyName", givenName: "some givenName", key_id: 42, password_hash: "some password_hash", username: "some username", username_hash: "some username_hash"}
+ @update_attrs %{email: "c@d.net", email_hash: "some updated email_hash", familyName: "some updated familyName", givenName: "some updated givenName", key_id: 43, password_hash: "some updated password_hash", username: "some updated username", username_hash: "some updated username_hash"}
@invalid_attrs %{email: nil, email_hash: nil, familyName: nil, givenName: nil, key_id: nil, password_hash: nil, username: nil, username_hash: nil}
def fixture(:person) do
@@ -13,6 +13,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all people", %{conn: conn} do
conn = get(conn, Routes.person_path(conn, :index))
assert html_response(conn, 200) =~ "Listing People"
@@ -20,6 +21,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "new person" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.person_path(conn, :new))
assert html_response(conn, 200) =~ "New Person"
@@ -27,6 +29,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "create person" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.person_path(conn, :create), person: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "edit person" do
- setup [:create_person]
+ setup [:person_login, :create_person]
test "renders form for editing chosen person", %{conn: conn, person: person} do
conn = get(conn, Routes.person_path(conn, :edit, person))
@@ -53,7 +56,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "update person" do
- setup [:create_person]
+ setup [:person_login, :create_person]
test "redirects when data is valid", %{conn: conn, person: person} do
conn = put(conn, Routes.person_path(conn, :update, person), person: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.PersonControllerTest do
end
describe "delete person" do
- setup [:create_person]
+ setup [:person_login, :create_person]
test "deletes chosen person", %{conn: conn, person: person} do
conn = delete(conn, Routes.person_path(conn, :delete, person))
@@ -81,6 +84,15 @@ defmodule AppWeb.PersonControllerTest do
end
end
+ describe "info person" do
+ setup [:person_login, :create_person]
+
+ test "display info person", %{conn: conn} do
+ conn = get(conn, Routes.person_path(conn, :info))
+ assert html_response(conn, 200)
+ end
+ end
+
defp create_person(_) do
person = fixture(:person)
{:ok, person: person}
diff --git a/test/app_web/controllers/status_controller_test.exs b/test/app_web/controllers/status_controller_test.exs
index 62b3ac56..986fcdbf 100644
--- a/test/app_web/controllers/status_controller_test.exs
+++ b/test/app_web/controllers/status_controller_test.exs
@@ -1,6 +1,6 @@
defmodule AppWeb.StatusControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
@create_attrs %{text: "some text"}
@@ -13,6 +13,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all status", %{conn: conn} do
conn = get(conn, Routes.status_path(conn, :index))
assert html_response(conn, 200) =~ "Listing Status"
@@ -20,6 +21,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "new status" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.status_path(conn, :new))
assert html_response(conn, 200) =~ "New Status"
@@ -27,6 +29,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "create status" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.status_path(conn, :create), status: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "edit status" do
- setup [:create_status]
+ setup [:person_login, :create_status]
test "renders form for editing chosen status", %{conn: conn, status: status} do
conn = get(conn, Routes.status_path(conn, :edit, status))
@@ -53,7 +56,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "update status" do
- setup [:create_status]
+ setup [:person_login, :create_status]
test "redirects when data is valid", %{conn: conn, status: status} do
conn = put(conn, Routes.status_path(conn, :update, status), status: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.StatusControllerTest do
end
describe "delete status" do
- setup [:create_status]
+ setup [:person_login, :create_status]
test "deletes chosen status", %{conn: conn, status: status} do
conn = delete(conn, Routes.status_path(conn, :delete, status))
diff --git a/test/app_web/controllers/tag_controller_test.exs b/test/app_web/controllers/tag_controller_test.exs
index 0abb6e20..42db7232 100644
--- a/test/app_web/controllers/tag_controller_test.exs
+++ b/test/app_web/controllers/tag_controller_test.exs
@@ -1,6 +1,6 @@
defmodule AppWeb.TagControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
@create_attrs %{text: "some text"}
@@ -13,6 +13,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all tags", %{conn: conn} do
conn = get(conn, Routes.tag_path(conn, :index))
assert html_response(conn, 200) =~ "Listing Tags"
@@ -20,6 +21,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "new tag" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.tag_path(conn, :new))
assert html_response(conn, 200) =~ "New Tag"
@@ -27,6 +29,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "create tag" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.tag_path(conn, :create), tag: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "edit tag" do
- setup [:create_tag]
+ setup [:person_login, :create_tag]
test "renders form for editing chosen tag", %{conn: conn, tag: tag} do
conn = get(conn, Routes.tag_path(conn, :edit, tag))
@@ -53,7 +56,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "update tag" do
- setup [:create_tag]
+ setup [:person_login, :create_tag]
test "redirects when data is valid", %{conn: conn, tag: tag} do
conn = put(conn, Routes.tag_path(conn, :update, tag), tag: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.TagControllerTest do
end
describe "delete tag" do
- setup [:create_tag]
+ setup [:person_login, :create_tag]
test "deletes chosen tag", %{conn: conn, tag: tag} do
conn = delete(conn, Routes.tag_path(conn, :delete, tag))
diff --git a/test/app_web/controllers/timer_controller_test.exs b/test/app_web/controllers/timer_controller_test.exs
index b64d147b..7df05f28 100644
--- a/test/app_web/controllers/timer_controller_test.exs
+++ b/test/app_web/controllers/timer_controller_test.exs
@@ -1,6 +1,6 @@
defmodule AppWeb.TimerControllerTest do
use AppWeb.ConnCase
-
+ import App.SetupHelpers
alias App.Ctx
@create_attrs %{end: ~N[2010-04-17 14:00:00], start: ~N[2010-04-17 14:00:00]}
@@ -13,6 +13,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "index" do
+ setup [:person_login]
test "lists all timers", %{conn: conn} do
conn = get(conn, Routes.timer_path(conn, :index))
assert html_response(conn, 200) =~ "Listing Timers"
@@ -20,6 +21,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "new timer" do
+ setup [:person_login]
test "renders form", %{conn: conn} do
conn = get(conn, Routes.timer_path(conn, :new))
assert html_response(conn, 200) =~ "New Timer"
@@ -27,6 +29,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "create timer" do
+ setup [:person_login]
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.timer_path(conn, :create), timer: @create_attrs)
@@ -44,7 +47,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "edit timer" do
- setup [:create_timer]
+ setup [:person_login, :create_timer]
test "renders form for editing chosen timer", %{conn: conn, timer: timer} do
conn = get(conn, Routes.timer_path(conn, :edit, timer))
@@ -53,7 +56,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "update timer" do
- setup [:create_timer]
+ setup [:person_login, :create_timer]
test "redirects when data is valid", %{conn: conn, timer: timer} do
conn = put(conn, Routes.timer_path(conn, :update, timer), timer: @update_attrs)
@@ -70,7 +73,7 @@ defmodule AppWeb.TimerControllerTest do
end
describe "delete timer" do
- setup [:create_timer]
+ setup [:person_login, :create_timer]
test "deletes chosen timer", %{conn: conn, timer: timer} do
conn = delete(conn, Routes.timer_path(conn, :delete, timer))
diff --git a/test/support/setup_helpers.ex b/test/support/setup_helpers.ex
new file mode 100644
index 00000000..afe6f2d1
--- /dev/null
+++ b/test/support/setup_helpers.ex
@@ -0,0 +1,17 @@
+defmodule App.SetupHelpers do
+ use Phoenix.ConnTest
+ import AppWeb.Router.Helpers
+
+ @endpoint AppWeb.Endpoint
+
+ def person_login(_) do
+ {:ok,
+ conn:
+ build_conn()
+ |> (fn c ->
+ get(c, google_auth_path(c, :index, code: "code"))
+ end).()
+ }
+ end
+
+end