diff --git a/config/config.exs b/config/config.exs index d1e28b42..e2677ea9 100644 --- a/config/config.exs +++ b/config/config.exs @@ -10,6 +10,12 @@ use Mix.Config config :philomena, ecto_repos: [Philomena.Repo] +config :philomena, + password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP" + +config :bcrypt_elixir, + log_rounds: 12 + # Configures the endpoint config :philomena, PhilomenaWeb.Endpoint, url: [host: "localhost"], @@ -17,6 +23,12 @@ config :philomena, PhilomenaWeb.Endpoint, render_errors: [view: PhilomenaWeb.ErrorView, accepts: ~w(html json)], pubsub: [name: Philomena.PubSub, adapter: Phoenix.PubSub.PG2] +config :phoenix, :template_engines, + slim: PhoenixSlime.Engine, + slime: PhoenixSlime.Engine, + # If you want to use LiveView + slimleex: PhoenixSlime.LiveViewEngine + # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", diff --git a/config/dev.exs b/config/dev.exs index 12987625..33bfff42 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -61,7 +61,7 @@ config :philomena, PhilomenaWeb.Endpoint, ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", ~r"priv/gettext/.*(po)$", ~r"lib/philomena_web/{live,views}/.*(ex)$", - ~r"lib/philomena_web/templates/.*(eex)$" + ~r"lib/philomena_web/templates/.*(eex|slim|slime)$" ] ] diff --git a/config/prod.secret.exs b/config/prod.secret.exs index 9f69adcf..76b24d67 100644 --- a/config/prod.secret.exs +++ b/config/prod.secret.exs @@ -11,6 +11,17 @@ database_url = For example: ecto://USER:PASS@HOST/DATABASE """ +config :bcrypt_elixir, + log_rounds: String.to_integer(System.get_env("BCRYPT_ROUNDS") || "12") + +config :philomena, + password_pepper: + System.get_env("PASSWORD_PEPPER") || + raise(""" + environment variable PASSWORD_PEPPER is missing. + You can generate one by calling: mix phx.gen.secret + """) + config :philomena, Philomena.Repo, # ssl: true, url: database_url, @@ -25,7 +36,8 @@ secret_key_base = config :philomena, PhilomenaWeb.Endpoint, http: [:inet6, port: String.to_integer(System.get_env("PORT") || "4000")], - secret_key_base: secret_key_base + secret_key_base: secret_key_base, + server: true # ## Using releases (Elixir v1.9+) # diff --git a/lib/philomena/users.ex b/lib/philomena/users.ex new file mode 100644 index 00000000..923b73bf --- /dev/null +++ b/lib/philomena/users.ex @@ -0,0 +1,104 @@ +defmodule Philomena.Users do + @moduledoc """ + The Users context. + """ + + import Ecto.Query, warn: false + alias Philomena.Repo + + alias Philomena.Users.User + + @doc """ + Returns the list of users. + + ## Examples + + iex> list_users() + [%User{}, ...] + + """ + def list_users do + Repo.all(User) + end + + @doc """ + Gets a single user. + + Raises `Ecto.NoResultsError` if the User does not exist. + + ## Examples + + iex> get_user!(123) + %User{} + + iex> get_user!(456) + ** (Ecto.NoResultsError) + + """ + def get_user!(id), do: Repo.get!(User, id) + + @doc """ + Creates a user. + + ## Examples + + iex> create_user(%{field: value}) + {:ok, %User{}} + + iex> create_user(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_user(attrs \\ %{}) do + %User{} + |> User.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a user. + + ## Examples + + iex> update_user(user, %{field: new_value}) + {:ok, %User{}} + + iex> update_user(user, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_user(%User{} = user, attrs) do + user + |> User.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a User. + + ## Examples + + iex> delete_user(user) + {:ok, %User{}} + + iex> delete_user(user) + {:error, %Ecto.Changeset{}} + + """ + def delete_user(%User{} = user) do + Repo.delete(user) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking user changes. + + ## Examples + + iex> change_user(user) + %Ecto.Changeset{source: %User{}} + + """ + def change_user(%User{} = user) do + User.changeset(user, %{}) + end +end diff --git a/lib/philomena/users/user.ex b/lib/philomena/users/user.ex new file mode 100644 index 00000000..506e8212 --- /dev/null +++ b/lib/philomena/users/user.ex @@ -0,0 +1,25 @@ +defmodule Philomena.Users.User do + use Ecto.Schema + import Ecto.Changeset + + schema "users" do + field :email, :string + field :encrypted_password, :string, default: "" + field :reset_password_token, :string + field :reset_password_sent_at, :naive_datetime + field :remember_created_at, :naive_datetime + field :sign_in_count, :integer, default: 0 + field :current_sign_in_at, :naive_datetime + field :last_sign_in_at, :naive_datetime + field :current_sign_in_ip, EctoNetwork.INET + field :last_sign_in_ip, EctoNetwork.INET + timestamps(inserted_at: :created_at) + end + + @doc false + def changeset(user, attrs) do + user + |> cast(attrs, []) + |> validate_required([]) + end +end diff --git a/lib/philomena_web/endpoint.ex b/lib/philomena_web/endpoint.ex index 3a44d128..4f7265e4 100644 --- a/lib/philomena_web/endpoint.ex +++ b/lib/philomena_web/endpoint.ex @@ -40,7 +40,9 @@ defmodule PhilomenaWeb.Endpoint do plug Plug.Session, store: :cookie, key: "_philomena_key", - signing_salt: "YoFrfZr1" + signing_salt: "signed cookie", + encryption_salt: "authenticated encrypted cookie" + plug PhilomenaWeb.Plugs.RenderTime plug PhilomenaWeb.Router end diff --git a/lib/philomena_web/plugs/render_time.ex b/lib/philomena_web/plugs/render_time.ex new file mode 100644 index 00000000..2705d73f --- /dev/null +++ b/lib/philomena_web/plugs/render_time.ex @@ -0,0 +1,11 @@ +defmodule PhilomenaWeb.Plugs.RenderTime do + import Plug.Conn + + # No options + def init([]), do: false + + # Assign current time + def call(conn, _opts) do + conn |> assign(:start_time, Time.utc_now()) + end +end diff --git a/lib/philomena_web/templates/layout/app.html.eex b/lib/philomena_web/templates/layout/app.html.eex index 5bf288f2..a580fb35 100644 --- a/lib/philomena_web/templates/layout/app.html.eex +++ b/lib/philomena_web/templates/layout/app.html.eex @@ -24,6 +24,7 @@
<%= get_flash(@conn, :info) %>
<%= get_flash(@conn, :error) %>
<%= render @view_module, @view_template, assigns %> +Rendered in <%= render_time(@conn) %> ms