refactored for new project name

This commit is contained in:
Adam Piontek 2021-03-05 19:23:32 -05:00
parent 0039146cd4
commit 82ab1d1ea5
113 changed files with 417 additions and 412 deletions

2
.gitignore vendored
View file

@ -24,7 +24,7 @@ erl_crash.dump
*.ez *.ez
# Ignore package tarball (built via "mix hex.build"). # Ignore package tarball (built via "mix hex.build").
bones73k-*.tar shift73k-*.tar
# If NPM crashes, it generates a log, let's ignore it too. # If NPM crashes, it generates a log, let's ignore it too.
npm-debug.log npm-debug.log

View file

@ -1,5 +1,5 @@
import Ecto.Query import Ecto.Query
# alias Bones73kWeb.Router.Helpers, as: Routes # alias Shift73kWeb.Router.Helpers, as: Routes
alias Bones73k.Repo alias Shift73k.Repo
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User

View file

@ -1,4 +1,4 @@
# Bones73k # Shift73k
See full article [here](https://www.leanpanda.com/blog/authentication-and-authorisation-in-phoenix-liveview/). See full article [here](https://www.leanpanda.com/blog/authentication-and-authorisation-in-phoenix-liveview/).

View file

@ -7,21 +7,21 @@
# General application configuration # General application configuration
use Mix.Config use Mix.Config
config :bones73k, config :shift73k,
ecto_repos: [Bones73k.Repo] ecto_repos: [Shift73k.Repo]
# Custom application global variables # Custom application global variables
config :bones73k, :app_global_vars, config :shift73k, :app_global_vars,
time_zone: "America/New_York", time_zone: "America/New_York",
mailer_reply_to: "reply_to@example.com", mailer_reply_to: "reply_to@example.com",
mailer_from: "app_name@example.com" mailer_from: "app_name@example.com"
# Configures the endpoint # Configures the endpoint
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
url: [host: "localhost"], url: [host: "localhost"],
secret_key_base: "LdIQmzV5UCWSbB2SdiWFHLgxYNObKq9Za/VyguoILxfOAMDb5IsptKCKtXTRn+Tf", secret_key_base: "LdIQmzV5UCWSbB2SdiWFHLgxYNObKq9Za/VyguoILxfOAMDb5IsptKCKtXTRn+Tf",
render_errors: [view: Bones73kWeb.ErrorView, accepts: ~w(html json), layout: false], render_errors: [view: Shift73kWeb.ErrorView, accepts: ~w(html json), layout: false],
pubsub_server: Bones73k.PubSub, pubsub_server: Shift73k.PubSub,
live_view: [signing_salt: "2D4GC4ac"] live_view: [signing_salt: "2D4GC4ac"]
# Configures Elixir's Logger # Configures Elixir's Logger

View file

@ -1,10 +1,10 @@
use Mix.Config use Mix.Config
# Configure your database # Configure your database
config :bones73k, Bones73k.Repo, config :shift73k, Shift73k.Repo,
username: "postgres", username: "postgres",
password: "postgres", password: "postgres",
database: "bones73k_dev", database: "shift73k_dev",
hostname: "localhost", hostname: "localhost",
show_sensitive_data_on_connection_error: true, show_sensitive_data_on_connection_error: true,
pool_size: 10 pool_size: 10
@ -15,7 +15,7 @@ config :bones73k, Bones73k.Repo,
# The watchers configuration can be used to run external # The watchers configuration can be used to run external
# watchers to your application. For example, we use it # watchers to your application. For example, we use it
# with webpack to recompile .js and .css sources. # with webpack to recompile .js and .css sources.
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
http: [port: 4000], http: [port: 4000],
debug_errors: true, debug_errors: true,
code_reloader: true, code_reloader: true,
@ -56,13 +56,13 @@ config :bones73k, Bones73kWeb.Endpoint,
# different ports. # different ports.
# Watch static and templates for browser reloading. # Watch static and templates for browser reloading.
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
live_reload: [ live_reload: [
patterns: [ patterns: [
~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
~r"priv/gettext/.*(po)$", ~r"priv/gettext/.*(po)$",
~r"lib/bones73k_web/(live|views)/.*(ex)$", ~r"lib/shift73k_web/(live|views)/.*(ex)$",
~r"lib/bones73k_web/templates/.*(eex)$" ~r"lib/shift73k_web/templates/.*(eex)$"
] ]
] ]

View file

@ -9,7 +9,7 @@ use Mix.Config
# manifest is generated by the `mix phx.digest` task, # manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and # which you should run after static files are built and
# before starting your production server. # before starting your production server.
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
url: [host: "example.com", port: 80], url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json" cache_static_manifest: "priv/static/cache_manifest.json"
@ -21,7 +21,7 @@ config :logger, level: :info
# To get SSL working, you will need to add the `https` key # To get SSL working, you will need to add the `https` key
# to the previous section and set your `:url` port to 443: # to the previous section and set your `:url` port to 443:
# #
# config :bones73k, Bones73kWeb.Endpoint, # config :shift73k, Shift73kWeb.Endpoint,
# ... # ...
# url: [host: "example.com", port: 443], # url: [host: "example.com", port: 443],
# https: [ # https: [
@ -45,7 +45,7 @@ config :logger, level: :info
# We also recommend setting `force_ssl` in your endpoint, ensuring # We also recommend setting `force_ssl` in your endpoint, ensuring
# no data is ever sent via http, always redirecting to https: # no data is ever sent via http, always redirecting to https:
# #
# config :bones73k, Bones73kWeb.Endpoint, # config :shift73k, Shift73kWeb.Endpoint,
# force_ssl: [hsts: true] # force_ssl: [hsts: true]
# #
# Check `Plug.SSL` for all available options in `force_ssl`. # Check `Plug.SSL` for all available options in `force_ssl`.

View file

@ -11,7 +11,7 @@ database_url =
For example: ecto://USER:PASS@HOST/DATABASE For example: ecto://USER:PASS@HOST/DATABASE
""" """
config :bones73k, Bones73k.Repo, config :shift73k, Shift73k.Repo,
# ssl: true, # ssl: true,
url: database_url, url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
@ -23,7 +23,7 @@ secret_key_base =
You can generate one by calling: mix phx.gen.secret You can generate one by calling: mix phx.gen.secret
""" """
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
http: [ http: [
port: String.to_integer(System.get_env("PORT") || "4000"), port: String.to_integer(System.get_env("PORT") || "4000"),
transport_options: [socket_opts: [:inet6]] transport_options: [socket_opts: [:inet6]]
@ -35,7 +35,7 @@ config :bones73k, Bones73kWeb.Endpoint,
# If you are doing OTP releases, you need to instruct Phoenix # If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint: # to start each relevant endpoint:
# #
# config :bones73k, Bones73kWeb.Endpoint, server: true # config :shift73k, Shift73kWeb.Endpoint, server: true
# #
# Then you can assemble a release by calling `mix release`. # Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information. # See `mix help release` for more information.

View file

@ -8,16 +8,16 @@ config :bcrypt_elixir, :log_rounds, 1
# The MIX_TEST_PARTITION environment variable can be used # The MIX_TEST_PARTITION environment variable can be used
# to provide built-in test partitioning in CI environment. # to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information. # Run `mix help test` for more information.
config :bones73k, Bones73k.Repo, config :shift73k, Shift73k.Repo,
username: "postgres", username: "postgres",
password: "postgres", password: "postgres",
database: "bones73k_test#{System.get_env("MIX_TEST_PARTITION")}", database: "shift73k_test#{System.get_env("MIX_TEST_PARTITION")}",
hostname: "localhost", hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox pool: Ecto.Adapters.SQL.Sandbox
# We don't run a server during test. If one is required, # We don't run a server during test. If one is required,
# you can enable the server option below. # you can enable the server option below.
config :bones73k, Bones73kWeb.Endpoint, config :shift73k, Shift73kWeb.Endpoint,
http: [port: 4002], http: [port: 4002],
server: false server: false
@ -25,7 +25,7 @@ config :bones73k, Bones73kWeb.Endpoint,
config :logger, level: :warn config :logger, level: :warn
# Bamboo test mailer config # Bamboo test mailer config
config :bones73k, Bones73k.Mailer, adapter: Bamboo.TestAdapter config :shift73k, Shift73k.Mailer, adapter: Bamboo.TestAdapter
# Import secret config # Import secret config
import_config "test.secret.exs" import_config "test.secret.exs"

View file

@ -1,3 +0,0 @@
defmodule Bones73k.Mailer do
use Bamboo.Mailer, otp_app: :bones73k
end

View file

@ -1,8 +0,0 @@
defmodule Bones73kWeb.UserRegistrationController do
use Bones73kWeb, :controller
import Phoenix.LiveView.Controller
def new(conn, _params) do
live_render(conn, Bones73kWeb.UserLive.Registration)
end
end

View file

@ -1,3 +0,0 @@
defmodule Bones73kWeb.OtherView do
use Bones73kWeb, :view
end

View file

@ -1,4 +0,0 @@
defmodule Bones73kWeb.UserConfirmationView do
use Bones73kWeb, :view
alias Bones73k.Accounts.User
end

View file

@ -1,4 +0,0 @@
defmodule Bones73kWeb.UserResetPasswordView do
use Bones73kWeb, :view
alias Bones73k.Accounts.User
end

View file

@ -1,4 +0,0 @@
defmodule Bones73kWeb.UserSessionView do
use Bones73kWeb, :view
alias Bones73k.Accounts.User
end

View file

@ -1,6 +1,6 @@
defmodule Bones73k do defmodule Shift73k do
@moduledoc """ @moduledoc """
Bones73k keeps the contexts that define your domain Shift73k keeps the contexts that define your domain
and business logic. and business logic.
Contexts are also responsible for managing your data, regardless Contexts are also responsible for managing your data, regardless

View file

@ -1,12 +1,12 @@
defmodule Bones73k.Accounts do defmodule Shift73k.Accounts do
@moduledoc """ @moduledoc """
The Accounts context. The Accounts context.
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Bones73k.Repo alias Shift73k.Repo
alias Bones73k.Accounts.{User, UserToken, UserNotifier} alias Shift73k.Accounts.{User, UserToken, UserNotifier}
alias Bones73kWeb.UserAuth alias Shift73kWeb.UserAuth
## Database getters ## Database getters
@ -121,7 +121,7 @@ defmodule Bones73k.Accounts do
Repo.delete_all(UserToken.user_and_contexts_query(user, :all)) Repo.delete_all(UserToken.user_and_contexts_query(user, :all))
# Broadcast to all liveviews to immediately disconnect the user # Broadcast to all liveviews to immediately disconnect the user
Bones73kWeb.Endpoint.broadcast_from( Shift73kWeb.Endpoint.broadcast_from(
self(), self(),
UserAuth.pubsub_topic(), UserAuth.pubsub_topic(),
"logout_user", "logout_user",

View file

@ -1,4 +1,4 @@
defmodule Bones73k.Accounts.User do defmodule Shift73k.Accounts.User do
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
import EctoEnum import EctoEnum
@ -19,12 +19,12 @@ defmodule Bones73k.Accounts.User do
@primary_key {:id, :binary_id, autogenerate: true} @primary_key {:id, :binary_id, autogenerate: true}
# @foreign_key_type :binary_id # @foreign_key_type :binary_id
schema "users" do schema "users" do
field :email, :string field(:email, :string)
field :password, :string, virtual: true field(:password, :string, virtual: true)
field :hashed_password, :string field(:hashed_password, :string)
field :confirmed_at, :naive_datetime field(:confirmed_at, :naive_datetime)
field :role, RolesEnum, default: :user field(:role, RolesEnum, default: :user)
timestamps() timestamps()
end end
@ -102,7 +102,7 @@ defmodule Bones73k.Accounts.User do
defp validate_email(changeset) do defp validate_email(changeset) do
changeset changeset
|> validate_email_format() |> validate_email_format()
|> unsafe_validate_unique(:email, Bones73k.Repo) |> unsafe_validate_unique(:email, Shift73k.Repo)
|> unique_constraint(:email) |> unique_constraint(:email)
end end
@ -173,7 +173,7 @@ defmodule Bones73k.Accounts.User do
If there is no user or the user doesn't have a password, we call If there is no user or the user doesn't have a password, we call
`Bcrypt.no_user_verify/0` to avoid timing attacks. `Bcrypt.no_user_verify/0` to avoid timing attacks.
""" """
def valid_password?(%Bones73k.Accounts.User{hashed_password: hashed_password}, password) def valid_password?(%Shift73k.Accounts.User{hashed_password: hashed_password}, password)
when is_binary(hashed_password) and byte_size(password) > 0 do when is_binary(hashed_password) and byte_size(password) > 0 do
Bcrypt.verify_pass(password, hashed_password) Bcrypt.verify_pass(password, hashed_password)
end end

View file

@ -1,6 +1,6 @@
defmodule Bones73k.Accounts.UserNotifier do defmodule Shift73k.Accounts.UserNotifier do
alias Bones73k.Mailer alias Shift73k.Mailer
alias Bones73k.Mailer.UserEmail alias Shift73k.Mailer.UserEmail
@doc """ @doc """
Deliver instructions to confirm account. Deliver instructions to confirm account.

View file

@ -1,4 +1,4 @@
defmodule Bones73k.Accounts.UserToken do defmodule Shift73k.Accounts.UserToken do
use Ecto.Schema use Ecto.Schema
import Ecto.Query import Ecto.Query
@ -15,10 +15,10 @@ defmodule Bones73k.Accounts.UserToken do
@primary_key {:id, :binary_id, autogenerate: true} @primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id @foreign_key_type :binary_id
schema "users_tokens" do schema "users_tokens" do
field :token, :binary field(:token, :binary)
field :context, :string field(:context, :string)
field :sent_to, :string field(:sent_to, :string)
belongs_to :user, Bones73k.Accounts.User belongs_to(:user, Shift73k.Accounts.User)
timestamps(updated_at: false) timestamps(updated_at: false)
end end
@ -30,7 +30,7 @@ defmodule Bones73k.Accounts.UserToken do
""" """
def build_session_token(user) do def build_session_token(user) do
token = :crypto.strong_rand_bytes(@rand_size) token = :crypto.strong_rand_bytes(@rand_size)
{token, %Bones73k.Accounts.UserToken{token: token, context: "session", user_id: user.id}} {token, %Shift73k.Accounts.UserToken{token: token, context: "session", user_id: user.id}}
end end
@doc """ @doc """
@ -40,10 +40,11 @@ defmodule Bones73k.Accounts.UserToken do
""" """
def verify_session_token_query(token) do def verify_session_token_query(token) do
query = query =
from token in token_and_context_query(token, "session"), from(token in token_and_context_query(token, "session"),
join: user in assoc(token, :user), join: user in assoc(token, :user),
where: token.inserted_at > ago(@session_validity_in_days, "day"), where: token.inserted_at > ago(@session_validity_in_days, "day"),
select: user select: user
)
{:ok, query} {:ok, query}
end end
@ -65,7 +66,7 @@ defmodule Bones73k.Accounts.UserToken do
hashed_token = :crypto.hash(@hash_algorithm, token) hashed_token = :crypto.hash(@hash_algorithm, token)
{Base.url_encode64(token, padding: false), {Base.url_encode64(token, padding: false),
%Bones73k.Accounts.UserToken{ %Shift73k.Accounts.UserToken{
token: hashed_token, token: hashed_token,
context: context, context: context,
sent_to: sent_to, sent_to: sent_to,
@ -85,10 +86,11 @@ defmodule Bones73k.Accounts.UserToken do
days = days_for_context(context) days = days_for_context(context)
query = query =
from token in token_and_context_query(hashed_token, context), from(token in token_and_context_query(hashed_token, context),
join: user in assoc(token, :user), join: user in assoc(token, :user),
where: token.inserted_at > ago(^days, "day") and token.sent_to == user.email, where: token.inserted_at > ago(^days, "day") and token.sent_to == user.email,
select: user select: user
)
{:ok, query} {:ok, query}
@ -111,8 +113,9 @@ defmodule Bones73k.Accounts.UserToken do
hashed_token = :crypto.hash(@hash_algorithm, decoded_token) hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query = query =
from token in token_and_context_query(hashed_token, context), from(token in token_and_context_query(hashed_token, context),
where: token.inserted_at > ago(@change_email_validity_in_days, "day") where: token.inserted_at > ago(@change_email_validity_in_days, "day")
)
{:ok, query} {:ok, query}
@ -125,17 +128,17 @@ defmodule Bones73k.Accounts.UserToken do
Returns the given token with the given context. Returns the given token with the given context.
""" """
def token_and_context_query(token, context) do def token_and_context_query(token, context) do
from Bones73k.Accounts.UserToken, where: [token: ^token, context: ^context] from(Shift73k.Accounts.UserToken, where: [token: ^token, context: ^context])
end end
@doc """ @doc """
Gets all tokens for the given user for the given contexts. Gets all tokens for the given user for the given contexts.
""" """
def user_and_contexts_query(user, :all) do def user_and_contexts_query(user, :all) do
from t in Bones73k.Accounts.UserToken, where: t.user_id == ^user.id from(t in Shift73k.Accounts.UserToken, where: t.user_id == ^user.id)
end end
def user_and_contexts_query(user, [_ | _] = contexts) do def user_and_contexts_query(user, [_ | _] = contexts) do
from t in Bones73k.Accounts.UserToken, where: t.user_id == ^user.id and t.context in ^contexts from(t in Shift73k.Accounts.UserToken, where: t.user_id == ^user.id and t.context in ^contexts)
end end
end end

View file

@ -1,4 +1,4 @@
defmodule Bones73k.Application do defmodule Shift73k.Application do
# See https://hexdocs.pm/elixir/Application.html # See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications # for more information on OTP Applications
@moduledoc false @moduledoc false
@ -8,27 +8,27 @@ defmodule Bones73k.Application do
def start(_type, _args) do def start(_type, _args) do
children = [ children = [
# Start the Ecto repository # Start the Ecto repository
Bones73k.Repo, Shift73k.Repo,
# Start the Telemetry supervisor # Start the Telemetry supervisor
Bones73kWeb.Telemetry, Shift73kWeb.Telemetry,
# Start the PubSub system # Start the PubSub system
{Phoenix.PubSub, name: Bones73k.PubSub}, {Phoenix.PubSub, name: Shift73k.PubSub},
# Start the Endpoint (http/https) # Start the Endpoint (http/https)
Bones73kWeb.Endpoint Shift73kWeb.Endpoint
# Start a worker by calling: Bones73k.Worker.start_link(arg) # Start a worker by calling: Shift73k.Worker.start_link(arg)
# {Bones73k.Worker, arg} # {Shift73k.Worker, arg}
] ]
# See https://hexdocs.pm/elixir/Supervisor.html # See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options # for other strategies and supported options
opts = [strategy: :one_for_one, name: Bones73k.Supervisor] opts = [strategy: :one_for_one, name: Shift73k.Supervisor]
Supervisor.start_link(children, opts) Supervisor.start_link(children, opts)
end end
# Tell Phoenix to update the endpoint configuration # Tell Phoenix to update the endpoint configuration
# whenever the application is updated. # whenever the application is updated.
def config_change(changed, _new, removed) do def config_change(changed, _new, removed) do
Bones73kWeb.Endpoint.config_change(changed, removed) Shift73kWeb.Endpoint.config_change(changed, removed)
:ok :ok
end end
end end

3
lib/shift73k/mailer.ex Normal file
View file

@ -0,0 +1,3 @@
defmodule Shift73k.Mailer do
use Bamboo.Mailer, otp_app: :shift73k
end

View file

@ -1,9 +1,9 @@
defmodule Bones73k.Mailer.UserEmail do defmodule Shift73k.Mailer.UserEmail do
import Bamboo.Email import Bamboo.Email
@mailer_vars Application.get_env(:bones73k, :app_global_vars, @mailer_vars Application.get_env(:shift73k, :app_global_vars,
mailer_reply_to: "admin@example.com", mailer_reply_to: "admin@example.com",
mailer_from: {"Bones73k", "bones73k@example.com"} mailer_from: {"Shift73k", "shift73k@example.com"}
) )
def compose(user, subject, body_text) do def compose(user, subject, body_text) do

View file

@ -1,12 +1,12 @@
defmodule Bones73k.Properties do defmodule Shift73k.Properties do
@moduledoc """ @moduledoc """
The Properties context. The Properties context.
""" """
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Bones73k.Repo alias Shift73k.Repo
alias Bones73k.Properties.Property alias Shift73k.Properties.Property
@doc """ @doc """
Returns the list of properties. Returns the list of properties.

View file

@ -1,14 +1,14 @@
defmodule Bones73k.Properties.Property do defmodule Shift73k.Properties.Property do
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true} @primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id @foreign_key_type :binary_id
schema "properties" do schema "properties" do
field :description, :string field(:description, :string)
field :name, :string field(:name, :string)
field :price, :decimal field(:price, :decimal)
field :user_id, :binary_id field(:user_id, :binary_id)
timestamps() timestamps()
end end

View file

@ -1,6 +1,6 @@
defmodule Bones73k.Repo do defmodule Shift73k.Repo do
use Ecto.Repo, use Ecto.Repo,
otp_app: :bones73k, otp_app: :shift73k,
adapter: Ecto.Adapters.Postgres adapter: Ecto.Adapters.Postgres
use Scrivener, page_size: 10 use Scrivener, page_size: 10

View file

@ -1,5 +1,5 @@
defmodule Bones73k.Util.Dt do defmodule Shift73k.Util.Dt do
@app_vars Application.get_env(:bones73k, :app_global_vars, time_zone: "America/New_York") @app_vars Application.get_env(:shift73k, :app_global_vars, time_zone: "America/New_York")
@time_zone @app_vars[:time_zone] @time_zone @app_vars[:time_zone]
def ndt_to_local(%NaiveDateTime{} = ndt), do: Timex.to_datetime(ndt, @time_zone) def ndt_to_local(%NaiveDateTime{} = ndt), do: Timex.to_datetime(ndt, @time_zone)

View file

@ -1,12 +1,12 @@
defmodule Bones73kWeb do defmodule Shift73kWeb do
@moduledoc """ @moduledoc """
The entrypoint for defining your web interface, such The entrypoint for defining your web interface, such
as controllers, views, channels and so on. as controllers, views, channels and so on.
This can be used in your application as: This can be used in your application as:
use Bones73kWeb, :controller use Shift73kWeb, :controller
use Bones73kWeb, :view use Shift73kWeb, :view
The definitions below will be executed for every view, The definitions below will be executed for every view,
controller, etc, so keep them short and clean, focused controller, etc, so keep them short and clean, focused
@ -19,19 +19,19 @@ defmodule Bones73kWeb do
def controller do def controller do
quote do quote do
use Phoenix.Controller, namespace: Bones73kWeb use Phoenix.Controller, namespace: Shift73kWeb
import Plug.Conn import Plug.Conn
import Bones73kWeb.Gettext import Shift73kWeb.Gettext
alias Bones73kWeb.Router.Helpers, as: Routes alias Shift73kWeb.Router.Helpers, as: Routes
end end
end end
def view do def view do
quote do quote do
use Phoenix.View, use Phoenix.View,
root: "lib/bones73k_web/templates", root: "lib/shift73k_web/templates",
namespace: Bones73kWeb, namespace: Shift73kWeb,
pattern: "**/*" pattern: "**/*"
# Import convenience functions from controllers # Import convenience functions from controllers
@ -46,12 +46,12 @@ defmodule Bones73kWeb do
def live_view do def live_view do
quote do quote do
use Phoenix.LiveView, use Phoenix.LiveView,
layout: {Bones73kWeb.LayoutView, "live.html"} layout: {Shift73kWeb.LayoutView, "live.html"}
unquote(view_helpers()) unquote(view_helpers())
import Bones73kWeb.LiveHelpers import Shift73kWeb.LiveHelpers
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def handle_info(%{event: "logout_user", payload: %{user: %User{id: id}}}, socket) do def handle_info(%{event: "logout_user", payload: %{user: %User{id: id}}}, socket) do
@ -71,7 +71,7 @@ defmodule Bones73kWeb do
use Phoenix.LiveComponent use Phoenix.LiveComponent
# Import General Custom Live Helpers # Import General Custom Live Helpers
import Bones73kWeb.LiveHelpers import Shift73kWeb.LiveHelpers
unquote(view_helpers()) unquote(view_helpers())
end end
@ -90,7 +90,7 @@ defmodule Bones73kWeb do
def channel do def channel do
quote do quote do
use Phoenix.Channel use Phoenix.Channel
import Bones73kWeb.Gettext import Shift73kWeb.Gettext
end end
end end
@ -106,11 +106,11 @@ defmodule Bones73kWeb do
import Phoenix.View import Phoenix.View
# Import SVG Icon helper # Import SVG Icon helper
import Bones73kWeb.IconHelpers import Shift73kWeb.IconHelpers
import Bones73kWeb.ErrorHelpers import Shift73kWeb.ErrorHelpers
import Bones73kWeb.Gettext import Shift73kWeb.Gettext
alias Bones73kWeb.Router.Helpers, as: Routes alias Shift73kWeb.Router.Helpers, as: Routes
end end
end end

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserSocket do defmodule Shift73kWeb.UserSocket do
use Phoenix.Socket use Phoenix.Socket
## Channels ## Channels
# channel "room:*", Bones73kWeb.RoomChannel # channel "room:*", Shift73kWeb.RoomChannel
# Socket params are passed from the client and can # Socket params are passed from the client and can
# be used to verify and authenticate a user. After # be used to verify and authenticate a user. After
@ -27,7 +27,7 @@ defmodule Bones73kWeb.UserSocket do
# Would allow you to broadcast a "disconnect" event and terminate # Would allow you to broadcast a "disconnect" event and terminate
# all active sockets and channels for a given user: # all active sockets and channels for a given user:
# #
# Bones73kWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) # Shift73kWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
# #
# Returning `nil` makes this socket anonymous. # Returning `nil` makes this socket anonymous.
@impl true @impl true

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.OtherController do defmodule Shift73kWeb.OtherController do
use Bones73kWeb, :controller use Shift73kWeb, :controller
def index(conn, _params) do def index(conn, _params) do
conn conn

View file

@ -1,9 +1,9 @@
defmodule Bones73kWeb.UserAuth do defmodule Shift73kWeb.UserAuth do
import Plug.Conn import Plug.Conn
import Phoenix.Controller import Phoenix.Controller
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73kWeb.Router.Helpers, as: Routes alias Shift73kWeb.Router.Helpers, as: Routes
@pubsub_topic "user_updates" @pubsub_topic "user_updates"
@ -76,7 +76,7 @@ defmodule Bones73kWeb.UserAuth do
user_token && Accounts.delete_session_token(user_token) user_token && Accounts.delete_session_token(user_token)
if live_socket_id = get_session(conn, :live_socket_id) do if live_socket_id = get_session(conn, :live_socket_id) do
Bones73kWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{}) Shift73kWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
end end
conn conn

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserConfirmationController do defmodule Shift73kWeb.UserConfirmationController do
use Bones73kWeb, :controller use Shift73kWeb, :controller
alias Bones73k.Accounts alias Shift73k.Accounts
def new(conn, _params) do def new(conn, _params) do
render(conn, "new.html") render(conn, "new.html")

View file

@ -0,0 +1,8 @@
defmodule Shift73kWeb.UserRegistrationController do
use Shift73kWeb, :controller
import Phoenix.LiveView.Controller
def new(conn, _params) do
live_render(conn, Shift73kWeb.UserLive.Registration)
end
end

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserResetPasswordController do defmodule Shift73kWeb.UserResetPasswordController do
use Bones73kWeb, :controller use Shift73kWeb, :controller
import Phoenix.LiveView.Controller import Phoenix.LiveView.Controller
alias Bones73k.Accounts alias Shift73k.Accounts
plug(:get_user_by_reset_password_token when action in [:edit]) plug(:get_user_by_reset_password_token when action in [:edit])
@ -28,7 +28,7 @@ defmodule Bones73kWeb.UserResetPasswordController do
end end
def edit(conn, _params) do def edit(conn, _params) do
live_render(conn, Bones73kWeb.UserLive.ResetPassword) live_render(conn, Shift73kWeb.UserLive.ResetPassword)
end end
defp get_user_by_reset_password_token(conn, _opts) do defp get_user_by_reset_password_token(conn, _opts) do

View file

@ -1,10 +1,10 @@
defmodule Bones73kWeb.UserSessionController do defmodule Shift73kWeb.UserSessionController do
use Bones73kWeb, :controller use Shift73kWeb, :controller
alias Phoenix.HTML alias Phoenix.HTML
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73kWeb.UserAuth alias Shift73kWeb.UserAuth
def new(conn, _params) do def new(conn, _params) do
render(conn, "new.html", error_message: nil) render(conn, "new.html", error_message: nil)
@ -24,7 +24,7 @@ defmodule Bones73kWeb.UserSessionController do
end end
def create(conn, %{"user" => %{"params_token" => token} = user_params}) do def create(conn, %{"user" => %{"params_token" => token} = user_params}) do
with {:ok, params} <- Phoenix.Token.decrypt(Bones73kWeb.Endpoint, "login_params", token), with {:ok, params} <- Phoenix.Token.decrypt(Shift73kWeb.Endpoint, "login_params", token),
%User{} = user <- Accounts.get_user(params.user_id) do %User{} = user <- Accounts.get_user(params.user_id) do
conn conn
|> collect_messages(params.messages) |> collect_messages(params.messages)

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserSettingsController do defmodule Shift73kWeb.UserSettingsController do
use Bones73kWeb, :controller use Shift73kWeb, :controller
alias Bones73k.Accounts alias Shift73k.Accounts
def confirm_email(conn, %{"token" => token}) do def confirm_email(conn, %{"token" => token}) do
case Accounts.update_user_email(conn.assigns.current_user, token) do case Accounts.update_user_email(conn.assigns.current_user, token) do

View file

@ -1,16 +1,16 @@
defmodule Bones73kWeb.Endpoint do defmodule Shift73kWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :bones73k use Phoenix.Endpoint, otp_app: :shift73k
# The session will be stored in the cookie and signed, # The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with. # this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it. # Set :encryption_salt if you would also like to encrypt it.
@session_options [ @session_options [
store: :cookie, store: :cookie,
key: "_bones73k_key", key: "_shift73k_key",
signing_salt: "9CKxo0VJ" signing_salt: "9CKxo0VJ"
] ]
socket("/socket", Bones73kWeb.UserSocket, socket("/socket", Shift73kWeb.UserSocket,
websocket: true, websocket: true,
longpoll: false longpoll: false
) )
@ -23,7 +23,7 @@ defmodule Bones73kWeb.Endpoint do
# when deploying your static files in production. # when deploying your static files in production.
plug(Plug.Static, plug(Plug.Static,
at: "/", at: "/",
from: :bones73k, from: :shift73k,
gzip: false, gzip: false,
only: ~w(css fonts images js favicon.ico robots.txt) only: ~w(css fonts images js favicon.ico robots.txt)
) )
@ -34,7 +34,7 @@ defmodule Bones73kWeb.Endpoint do
socket("/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket) socket("/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket)
plug(Phoenix.LiveReloader) plug(Phoenix.LiveReloader)
plug(Phoenix.CodeReloader) plug(Phoenix.CodeReloader)
plug(Phoenix.Ecto.CheckRepoStatus, otp_app: :bones73k) plug(Phoenix.Ecto.CheckRepoStatus, otp_app: :shift73k)
end end
plug(Phoenix.LiveDashboard.RequestLogger, plug(Phoenix.LiveDashboard.RequestLogger,
@ -54,5 +54,5 @@ defmodule Bones73kWeb.Endpoint do
plug(Plug.MethodOverride) plug(Plug.MethodOverride)
plug(Plug.Head) plug(Plug.Head)
plug(Plug.Session, @session_options) plug(Plug.Session, @session_options)
plug(Bones73kWeb.Router) plug(Shift73kWeb.Router)
end end

View file

@ -1,11 +1,11 @@
defmodule Bones73kWeb.Gettext do defmodule Shift73kWeb.Gettext do
@moduledoc """ @moduledoc """
A module providing Internationalization with a gettext-based API. A module providing Internationalization with a gettext-based API.
By using [Gettext](https://hexdocs.pm/gettext), By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example: your module gains a set of macros for translations, for example:
import Bones73kWeb.Gettext import Shift73kWeb.Gettext
# Simple translation # Simple translation
gettext("Here is the string to translate") gettext("Here is the string to translate")
@ -20,5 +20,5 @@ defmodule Bones73kWeb.Gettext do
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
""" """
use Gettext, otp_app: :bones73k use Gettext, otp_app: :shift73k
end end

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.AdminDashboardLive do defmodule Shift73kWeb.AdminDashboardLive do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -1,10 +1,10 @@
defmodule Bones73kWeb.LiveHelpers do defmodule Shift73kWeb.LiveHelpers do
import Phoenix.LiveView import Phoenix.LiveView
import Phoenix.LiveView.Helpers import Phoenix.LiveView.Helpers
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73kWeb.UserAuth alias Shift73kWeb.UserAuth
@doc """ @doc """
Performs the {:noreply, socket} for a given socket. Performs the {:noreply, socket} for a given socket.
@ -19,14 +19,14 @@ defmodule Bones73kWeb.LiveHelpers do
def live_okreply(socket), do: {:ok, socket} def live_okreply(socket), do: {:ok, socket}
@doc """ @doc """
Renders a component inside the `Bones73kWeb.ModalComponent` component. Renders a component inside the `Shift73kWeb.ModalComponent` component.
The rendered modal receives a `:return_to` option to properly update The rendered modal receives a `:return_to` option to properly update
the URL when the modal is closed. the URL when the modal is closed.
## Examples ## Examples
<%= live_modal @socket, Bones73kWeb.PropertyLive.FormComponent, <%= live_modal @socket, Shift73kWeb.PropertyLive.FormComponent,
id: @property.id || :new, id: @property.id || :new,
action: @live_action, action: @live_action,
property: @property, property: @property,
@ -36,14 +36,14 @@ defmodule Bones73kWeb.LiveHelpers do
modal_opts = [id: :modal, component: component, opts: opts] modal_opts = [id: :modal, component: component, opts: opts]
# dirty little workaround for elixir complaining about socket being unused # dirty little workaround for elixir complaining about socket being unused
_socket = socket _socket = socket
live_component(socket, Bones73kWeb.ModalComponent, modal_opts) live_component(socket, Shift73kWeb.ModalComponent, modal_opts)
end end
@doc """ @doc """
Loads default assigns for liveviews Loads default assigns for liveviews
""" """
def assign_defaults(socket, session) do def assign_defaults(socket, session) do
Bones73kWeb.Endpoint.subscribe(UserAuth.pubsub_topic()) Shift73kWeb.Endpoint.subscribe(UserAuth.pubsub_topic())
assign_current_user(socket, session) assign_current_user(socket, session)
end end

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.ModalComponent do defmodule Shift73kWeb.ModalComponent do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
@impl true @impl true
def render(assigns) do def render(assigns) do

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.PageLive do defmodule Shift73kWeb.PageLive do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do
@ -27,7 +27,7 @@ defmodule Bones73kWeb.PageLive do
end end
defp search(query) do defp search(query) do
if not Bones73kWeb.Endpoint.config(:code_reloader) do if not Shift73kWeb.Endpoint.config(:code_reloader) do
raise "action disabled when not in development" raise "action disabled when not in development"
end end

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.PropertyLive.FormComponent do defmodule Shift73kWeb.PropertyLive.FormComponent do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
alias Bones73k.Properties alias Shift73k.Properties
@impl true @impl true
def update(%{property: property} = assigns, socket) do def update(%{property: property} = assigns, socket) do

View file

@ -1,9 +1,9 @@
defmodule Bones73kWeb.PropertyLive.Index do defmodule Shift73kWeb.PropertyLive.Index do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
alias Bones73k.Properties alias Shift73k.Properties
alias Bones73k.Properties.Property alias Shift73k.Properties.Property
alias Bones73kWeb.Roles alias Shift73kWeb.Roles
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do
@ -54,7 +54,7 @@ defmodule Bones73kWeb.PropertyLive.Index do
current_user = socket.assigns.current_user current_user = socket.assigns.current_user
property = Properties.get_property!(id) property = Properties.get_property!(id)
if Bones73kWeb.Roles.can?(current_user, property, :delete) do if Shift73kWeb.Roles.can?(current_user, property, :delete) do
property = Properties.get_property!(id) property = Properties.get_property!(id)
{:ok, _} = Properties.delete_property(property) {:ok, _} = Properties.delete_property(property)

View file

@ -1,5 +1,5 @@
<%= if @live_action in [:new, :edit] do %> <%= if @live_action in [:new, :edit] do %>
<%= live_modal @socket, Bones73kWeb.PropertyLive.FormComponent, <%= live_modal @socket, Shift73kWeb.PropertyLive.FormComponent,
id: @property.id || :new, id: @property.id || :new,
title: @page_title, title: @page_title,
action: @live_action, action: @live_action,

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.PropertyLive.Show do defmodule Shift73kWeb.PropertyLive.Show do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
alias Bones73k.Properties alias Shift73k.Properties
alias Bones73kWeb.Roles alias Shift73kWeb.Roles
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -1,7 +1,7 @@
<h2>Show Property</h2> <h2>Show Property</h2>
<%= if @live_action in [:edit] do %> <%= if @live_action in [:edit] do %>
<%= live_modal @socket, Bones73kWeb.PropertyLive.FormComponent, <%= live_modal @socket, Shift73kWeb.PropertyLive.FormComponent,
id: @property.id, id: @property.id,
title: @page_title, title: @page_title,
action: @live_action, action: @live_action,

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserLive.Registration do defmodule Shift73kWeb.UserLive.Registration do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -63,7 +63,7 @@
<%# hidden form for initial login after registration %> <%# hidden form for initial login after registration %>
<%= form_for :user, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit, id: "reg_trigger"], fn f -> %> <%= form_for :user, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit, id: "reg_trigger"], fn f -> %>
<%= hidden_input f, :params_token, value: Phoenix.Token.encrypt(Bones73kWeb.Endpoint, "login_params", @login_params) %> <%= hidden_input f, :params_token, value: Phoenix.Token.encrypt(Shift73kWeb.Endpoint, "login_params", @login_params) %>
<% end %> <% end %>
</div> </div>

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserLive.ResetPassword do defmodule Shift73kWeb.UserLive.ResetPassword do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserLive.Settings do defmodule Shift73kWeb.UserLive.Settings do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -4,6 +4,6 @@
</h2> </h2>
<div class="row"> <div class="row">
<%= live_component @socket, Bones73kWeb.UserLive.Settings.Email, id: "email-#{@current_user.id}", current_user: @current_user %> <%= live_component @socket, Shift73kWeb.UserLive.Settings.Email, id: "email-#{@current_user.id}", current_user: @current_user %>
<%= live_component @socket, Bones73kWeb.UserLive.Settings.Password, id: "password-#{@current_user.id}", current_user: @current_user %> <%= live_component @socket, Shift73kWeb.UserLive.Settings.Password, id: "password-#{@current_user.id}", current_user: @current_user %>
</div> </div>

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserLive.Settings.Email do defmodule Shift73kWeb.UserLive.Settings.Email do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def update(%{current_user: user} = assigns, socket) do def update(%{current_user: user} = assigns, socket) do
@ -23,7 +23,7 @@ defmodule Bones73kWeb.UserLive.Settings.Email do
{:noreply, assign(socket, changeset: %{cs | action: :validate})} {:noreply, assign(socket, changeset: %{cs | action: :validate})}
end end
# user_settings_path GET /users/settings/confirm_email/:token Bones73kWeb.UserSettingsController :confirm_email # user_settings_path GET /users/settings/confirm_email/:token Shift73kWeb.UserSettingsController :confirm_email
@impl true @impl true
def handle_event("save", %{"user" => user_params}, socket) do def handle_event("save", %{"user" => user_params}, socket) do

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserLive.Settings.Password do defmodule Shift73kWeb.UserLive.Settings.Password do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
@impl true @impl true
def update(%{current_user: user} = assigns, socket) do def update(%{current_user: user} = assigns, socket) do

View file

@ -65,12 +65,12 @@
<%# hidden form for initial login after registration %> <%# hidden form for initial login after registration %>
<%= form_for :user, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit, id: "settings_pw_change_trigger"], fn f -> %> <%= form_for :user, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit, id: "settings_pw_change_trigger"], fn f -> %>
<%= hidden_input f, :params_token, value: Phoenix.Token.encrypt(Bones73kWeb.Endpoint, "login_params", @login_params) %> <%= hidden_input f, :params_token, value: Phoenix.Token.encrypt(Shift73kWeb.Endpoint, "login_params", @login_params) %>
<% end %> <% end %>
<%# hidden form to submit user for relogin after password change %> <%# hidden form to submit user for relogin after password change %>
<%#= form_for :user_login, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit], fn f -> %> <%#= form_for :user_login, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit], fn f -> %>
<%#= hidden_input f, :login_params_token, value: Phoenix.Token.encrypt(Bones73kWeb.Endpoint, "login_params", @login_params) %> <%#= hidden_input f, :login_params_token, value: Phoenix.Token.encrypt(Shift73kWeb.Endpoint, "login_params", @login_params) %>
<%#= hidden_input f, :remember_me, value: false %> <%#= hidden_input f, :remember_me, value: false %>
<%# end %> <%# end %>

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.UserDashboardLive do defmodule Shift73kWeb.UserDashboardLive do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserManagement.DeleteComponent do defmodule Shift73kWeb.UserManagement.DeleteComponent do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
alias Bones73k.Accounts alias Shift73k.Accounts
@impl true @impl true
def update(assigns, socket) do def update(assigns, socket) do

View file

@ -1,9 +1,9 @@
defmodule Bones73kWeb.UserManagement.FormComponent do defmodule Shift73kWeb.UserManagement.FormComponent do
use Bones73kWeb, :live_component use Shift73kWeb, :live_component
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73kWeb.Roles alias Shift73kWeb.Roles
@impl true @impl true
def update(assigns, socket) do def update(assigns, socket) do

View file

@ -1,14 +1,14 @@
defmodule Bones73kWeb.UserManagementLive.Index do defmodule Shift73kWeb.UserManagementLive.Index do
use Bones73kWeb, :live_view use Shift73kWeb, :live_view
import Ecto.Query import Ecto.Query
import Bones73kWeb.Pagination import Shift73kWeb.Pagination
import Bones73k.Util.Dt import Shift73k.Util.Dt
alias Bones73k.Repo alias Shift73k.Repo
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73kWeb.Roles alias Shift73kWeb.Roles
@impl true @impl true
def mount(_params, session, socket) do def mount(_params, session, socket) do

View file

@ -1,5 +1,5 @@
<%= if @live_action in [:new, :edit] do %> <%= if @live_action in [:new, :edit] do %>
<%= live_modal @socket, Bones73kWeb.UserManagement.FormComponent, <%= live_modal @socket, Shift73kWeb.UserManagement.FormComponent,
id: @user.id || :new, id: @user.id || :new,
title: @page_title, title: @page_title,
action: @live_action, action: @live_action,
@ -8,7 +8,7 @@
<% end %> <% end %>
<%= if @delete_user do %> <%= if @delete_user do %>
<%= live_modal @socket, Bones73kWeb.UserManagement.DeleteComponent, <%= live_modal @socket, Shift73kWeb.UserManagement.DeleteComponent,
id: @delete_user.id, id: @delete_user.id,
title: "Delete User", title: "Delete User",
delete_user: @delete_user, delete_user: @delete_user,

View file

@ -1,4 +1,4 @@
defmodule Bones73kWeb.EnsureRolePlug do defmodule Shift73kWeb.EnsureRolePlug do
@moduledoc """ @moduledoc """
This plug ensures that a user has a particular role before accessing a given route. This plug ensures that a user has a particular role before accessing a given route.
@ -6,15 +6,15 @@ defmodule Bones73kWeb.EnsureRolePlug do
Let's suppose we have three roles: :admin, :manager and :user. Let's suppose we have three roles: :admin, :manager and :user.
If you want a user to have at least manager role, so admins and managers are authorised to access a given route If you want a user to have at least manager role, so admins and managers are authorised to access a given route
plug Bones73kWeb.EnsureRolePlug, [:admin, :manager] plug Shift73kWeb.EnsureRolePlug, [:admin, :manager]
If you want to give access only to an admin: If you want to give access only to an admin:
plug Bones73kWeb.EnsureRolePlug, :admin plug Shift73kWeb.EnsureRolePlug, :admin
""" """
import Plug.Conn import Plug.Conn
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Phoenix.Controller alias Phoenix.Controller
alias Plug.Conn alias Plug.Conn

View file

@ -1,10 +1,10 @@
defmodule Bones73kWeb.Roles do defmodule Shift73kWeb.Roles do
@moduledoc """ @moduledoc """
Defines roles related functions. Defines roles related functions.
""" """
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73k.Properties.Property alias Shift73k.Properties.Property
@type entity :: struct() @type entity :: struct()
@type action :: :new | :index | :edit | :show | :delete | :edit_role @type action :: :new | :index | :edit | :show | :delete | :edit_role

View file

@ -1,13 +1,13 @@
defmodule Bones73kWeb.Router do defmodule Shift73kWeb.Router do
use Bones73kWeb, :router use Shift73kWeb, :router
import Bones73kWeb.UserAuth import Shift73kWeb.UserAuth
alias Bones73kWeb.EnsureRolePlug alias Shift73kWeb.EnsureRolePlug
pipeline :browser do pipeline :browser do
plug(:accepts, ["html"]) plug(:accepts, ["html"])
plug(:fetch_session) plug(:fetch_session)
plug(:fetch_live_flash) plug(:fetch_live_flash)
plug(:put_root_layout, {Bones73kWeb.LayoutView, :root}) plug(:put_root_layout, {Shift73kWeb.LayoutView, :root})
plug(:protect_from_forgery) plug(:protect_from_forgery)
plug(:put_secure_browser_headers) plug(:put_secure_browser_headers)
plug(:fetch_current_user) plug(:fetch_current_user)
@ -29,15 +29,15 @@ defmodule Bones73kWeb.Router do
plug(EnsureRolePlug, :admin) plug(EnsureRolePlug, :admin)
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through [:browser] pipe_through([:browser])
live "/", PageLive, :index live("/", PageLive, :index)
get "/other", OtherController, :index get("/other", OtherController, :index)
end end
# Other scopes may use custom stacks. # Other scopes may use custom stacks.
# scope "/api", Bones73kWeb do # scope "/api", Shift73kWeb do
# pipe_through :api # pipe_through :api
# end # end
@ -53,11 +53,11 @@ defmodule Bones73kWeb.Router do
scope "/" do scope "/" do
pipe_through(:browser) pipe_through(:browser)
live_dashboard("/dashboard", metrics: Bones73kWeb.Telemetry) live_dashboard("/dashboard", metrics: Shift73kWeb.Telemetry)
end end
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through([:browser, :redirect_if_user_is_authenticated]) pipe_through([:browser, :redirect_if_user_is_authenticated])
get("/users/register", UserRegistrationController, :new) get("/users/register", UserRegistrationController, :new)
@ -68,17 +68,17 @@ defmodule Bones73kWeb.Router do
get("/users/reset_password/:token", UserResetPasswordController, :edit) get("/users/reset_password/:token", UserResetPasswordController, :edit)
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through([:browser, :require_authenticated_user]) pipe_through([:browser, :require_authenticated_user])
# # liveview user settings # # liveview user settings
live "/users/settings", UserLive.Settings, :edit live("/users/settings", UserLive.Settings, :edit)
# original user routes from phx.gen.auth # original user routes from phx.gen.auth
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email) get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through([:browser]) pipe_through([:browser])
delete("/users/log_out", UserSessionController, :delete) delete("/users/log_out", UserSessionController, :delete)
@ -88,7 +88,7 @@ defmodule Bones73kWeb.Router do
get("/users/confirm/:token", UserConfirmationController, :confirm) get("/users/confirm/:token", UserConfirmationController, :confirm)
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through([:browser, :require_authenticated_user, :user]) pipe_through([:browser, :require_authenticated_user, :user])
live("/user_dashboard", UserDashboardLive, :index) live("/user_dashboard", UserDashboardLive, :index)
@ -100,15 +100,15 @@ defmodule Bones73kWeb.Router do
live("/properties/:id/show/edit", PropertyLive.Show, :edit) live("/properties/:id/show/edit", PropertyLive.Show, :edit)
end end
scope "/", Bones73kWeb do scope "/", Shift73kWeb do
pipe_through([:browser, :require_authenticated_user, :admin]) pipe_through([:browser, :require_authenticated_user, :admin])
live("/admin_dashboard", AdminDashboardLive, :index) live("/admin_dashboard", AdminDashboardLive, :index)
end end
# Users Management # Users Management
scope "/users", Bones73kWeb do scope "/users", Shift73kWeb do
pipe_through [:browser, :require_authenticated_user, :manager, :require_email_confirmed] pipe_through([:browser, :require_authenticated_user, :manager, :require_email_confirmed])
live("/", UserManagementLive.Index, :index) live("/", UserManagementLive.Index, :index)
live("/new", UserManagementLive.Index, :new) live("/new", UserManagementLive.Index, :new)

View file

@ -1,4 +1,4 @@
defmodule Bones73kWeb.Telemetry do defmodule Shift73kWeb.Telemetry do
use Supervisor use Supervisor
import Telemetry.Metrics import Telemetry.Metrics
@ -31,11 +31,11 @@ defmodule Bones73kWeb.Telemetry do
), ),
# Database Metrics # Database Metrics
summary("bones73k.repo.query.total_time", unit: {:native, :millisecond}), summary("shift73k.repo.query.total_time", unit: {:native, :millisecond}),
summary("bones73k.repo.query.decode_time", unit: {:native, :millisecond}), summary("shift73k.repo.query.decode_time", unit: {:native, :millisecond}),
summary("bones73k.repo.query.query_time", unit: {:native, :millisecond}), summary("shift73k.repo.query.query_time", unit: {:native, :millisecond}),
summary("bones73k.repo.query.queue_time", unit: {:native, :millisecond}), summary("shift73k.repo.query.queue_time", unit: {:native, :millisecond}),
summary("bones73k.repo.query.idle_time", unit: {:native, :millisecond}), summary("shift73k.repo.query.idle_time", unit: {:native, :millisecond}),
# VM Metrics # VM Metrics
summary("vm.memory.total", unit: {:byte, :kilobyte}), summary("vm.memory.total", unit: {:byte, :kilobyte}),
@ -49,7 +49,7 @@ defmodule Bones73kWeb.Telemetry do
[ [
# A module, function and arguments to be invoked periodically. # A module, function and arguments to be invoked periodically.
# This function must call :telemetry.execute/3 and a metric must be added above. # This function must call :telemetry.execute/3 and a metric must be added above.
# {Bones73kWeb, :count_users, []} # {Shift73kWeb, :count_users, []}
] ]
end end
end end

View file

@ -4,7 +4,7 @@
<h1 class="fs-4 my-0 py-0 lh-base"> <h1 class="fs-4 my-0 py-0 lh-base">
<%= link to: Routes.page_path(@conn, :index), class: "navbar-brand fs-4" do %> <%= link to: Routes.page_path(@conn, :index), class: "navbar-brand fs-4" do %>
<%= icon_div @conn, "mdi-skull-crossbones", [class: "icon baseline fs-3"] %> <%= icon_div @conn, "mdi-skull-crossbones", [class: "icon baseline fs-3"] %>
<span class="fw-light">Bones73k</span> <span class="fw-light">Shift73k</span>
<% end %> <% end %>
</h1> </h1>

View file

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= csrf_meta_tag() %> <%= csrf_meta_tag() %>
<%= live_title_tag assigns[:page_title] || "Bones73k", suffix: " · Phoenix Framework" %> <%= live_title_tag assigns[:page_title] || "Shift73k", suffix: " · Phoenix Framework" %>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/> <link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script> <script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
</head> </head>

View file

@ -1,4 +1,4 @@
defmodule Bones73kWeb.ErrorHelpers do defmodule Shift73kWeb.ErrorHelpers do
@moduledoc """ @moduledoc """
Conveniences for translating and building error messages. Conveniences for translating and building error messages.
""" """
@ -31,7 +31,9 @@ defmodule Bones73kWeb.ErrorHelpers do
def input_class(form, field, classes \\ "") do def input_class(form, field, classes \\ "") do
case form.source.action do case form.source.action do
nil -> classes nil ->
classes
_ -> _ ->
case Keyword.has_key?(form.errors, field) do case Keyword.has_key?(form.errors, field) do
true -> "#{classes} is-invalid" true -> "#{classes} is-invalid"
@ -62,9 +64,9 @@ defmodule Bones73kWeb.ErrorHelpers do
# should be written to the errors.po file. The :count option is # should be written to the errors.po file. The :count option is
# set by Ecto and indicates we should also apply plural rules. # set by Ecto and indicates we should also apply plural rules.
if count = opts[:count] do if count = opts[:count] do
Gettext.dngettext(Bones73kWeb.Gettext, "errors", msg, msg, count, opts) Gettext.dngettext(Shift73kWeb.Gettext, "errors", msg, msg, count, opts)
else else
Gettext.dgettext(Bones73kWeb.Gettext, "errors", msg, opts) Gettext.dgettext(Shift73kWeb.Gettext, "errors", msg, opts)
end end
end end
end end

View file

@ -1,5 +1,5 @@
defmodule Bones73kWeb.ErrorView do defmodule Shift73kWeb.ErrorView do
use Bones73kWeb, :view use Shift73kWeb, :view
# If you want to customize a particular status code # If you want to customize a particular status code
# for a certain format, you may uncomment below. # for a certain format, you may uncomment below.

View file

@ -1,10 +1,10 @@
defmodule Bones73kWeb.IconHelpers do defmodule Shift73kWeb.IconHelpers do
@moduledoc """ @moduledoc """
Generate SVG sprite use tags for SVG icons Generate SVG sprite use tags for SVG icons
""" """
use Phoenix.HTML use Phoenix.HTML
alias Bones73kWeb.Router.Helpers, as: Routes alias Shift73kWeb.Router.Helpers, as: Routes
def icon_div(conn, name, div_opts \\ [], svg_opts \\ []) do def icon_div(conn, name, div_opts \\ [], svg_opts \\ []) do
content_tag(:div, tag_opts(name, div_opts)) do content_tag(:div, tag_opts(name, div_opts)) do

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.LayoutView do defmodule Shift73kWeb.LayoutView do
use Bones73kWeb, :view use Shift73kWeb, :view
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73kWeb.Roles alias Shift73kWeb.Roles
def nav_link_opts(conn, opts) do def nav_link_opts(conn, opts) do
case Keyword.get(opts, :to) == Phoenix.Controller.current_path(conn) do case Keyword.get(opts, :to) == Phoenix.Controller.current_path(conn) do

View file

@ -0,0 +1,3 @@
defmodule Shift73kWeb.OtherView do
use Shift73kWeb, :view
end

View file

@ -1,4 +1,4 @@
defmodule Bones73kWeb.Pagination do defmodule Shift73kWeb.Pagination do
def generate_page_list(_, total_pages) when total_pages < 5, def generate_page_list(_, total_pages) when total_pages < 5,
do: 1..total_pages |> Enum.to_list() do: 1..total_pages |> Enum.to_list()

View file

@ -0,0 +1,4 @@
defmodule Shift73kWeb.UserConfirmationView do
use Shift73kWeb, :view
alias Shift73k.Accounts.User
end

View file

@ -0,0 +1,4 @@
defmodule Shift73kWeb.UserResetPasswordView do
use Shift73kWeb, :view
alias Shift73k.Accounts.User
end

View file

@ -0,0 +1,4 @@
defmodule Shift73kWeb.UserSessionView do
use Shift73kWeb, :view
alias Shift73k.Accounts.User
end

View file

@ -1,9 +1,9 @@
defmodule Bones73k.MixProject do defmodule Shift73k.MixProject do
use Mix.Project use Mix.Project
def project do def project do
[ [
app: :bones73k, app: :shift73k,
version: "0.1.0", version: "0.1.0",
elixir: "~> 1.7", elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
@ -19,7 +19,7 @@ defmodule Bones73k.MixProject do
# Type `mix help compile.app` for more information. # Type `mix help compile.app` for more information.
def application do def application do
[ [
mod: {Bones73k.Application, []}, mod: {Shift73k.Application, []},
extra_applications: [:logger, :runtime_tools] extra_applications: [:logger, :runtime_tools]
] ]
end end

View file

@ -1,4 +1,4 @@
defmodule Bones73k.Repo.Migrations.CreateUsersAuthTables do defmodule Shift73k.Repo.Migrations.CreateUsersAuthTables do
use Ecto.Migration use Ecto.Migration
def change do def change do

View file

@ -1,7 +1,7 @@
defmodule Bones73k.Repo.Migrations.AddRoleToUsers do defmodule Shift73k.Repo.Migrations.AddRoleToUsers do
use Ecto.Migration use Ecto.Migration
alias Bones73k.Accounts.User.RolesEnum alias Shift73k.Accounts.User.RolesEnum
def up do def up do
RolesEnum.create_type() RolesEnum.create_type()

View file

@ -1,4 +1,4 @@
defmodule Bones73k.Repo.Migrations.CreateProperties do defmodule Shift73k.Repo.Migrations.CreateProperties do
use Ecto.Migration use Ecto.Migration
def change do def change do

View file

@ -5,16 +5,16 @@
# Inside the script, you can read and write to any of your # Inside the script, you can read and write to any of your
# repositories directly: # repositories directly:
# #
# Bones73k.Repo.insert!(%Bones73k.SomeSchema{}) # Shift73k.Repo.insert!(%Shift73k.SomeSchema{})
# #
# We recommend using the bang functions (`insert!`, `update!` # We recommend using the bang functions (`insert!`, `update!`
# and so on) as they will fail if something goes wrong. # and so on) as they will fail if something goes wrong.
import Ecto.Query import Ecto.Query
alias Bones73k.Repo alias Shift73k.Repo
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Accounts.User alias Shift73k.Accounts.User
alias Bones73k.Properties.Property alias Shift73k.Properties.Property
############################################################################ ############################################################################
## INSERTING MOCK USER DATA ## INSERTING MOCK USER DATA
@ -86,7 +86,7 @@ Enum.each(1..10, fn i ->
description: "Property that belongs to user 1", description: "Property that belongs to user 1",
user_id: user_1.id user_id: user_1.id
} }
|> Bones73k.Properties.create_property() |> Shift73k.Properties.create_property()
%{ %{
name: "Property #{i} - User 2", name: "Property #{i} - User 2",
@ -94,7 +94,7 @@ Enum.each(1..10, fn i ->
description: "Property that belongs to user 2", description: "Property that belongs to user 2",
user_id: user_2.id user_id: user_2.id
} }
|> Bones73k.Properties.create_property() |> Shift73k.Properties.create_property()
%{ %{
name: "Property #{i} - Admin", name: "Property #{i} - Admin",
@ -102,7 +102,7 @@ Enum.each(1..10, fn i ->
description: "Property that belongs to admin", description: "Property that belongs to admin",
user_id: admin.id user_id: admin.id
} }
|> Bones73k.Properties.create_property() |> Shift73k.Properties.create_property()
end) end)
# if Mix.env() == :dev do # if Mix.env() == :dev do
@ -114,7 +114,7 @@ count_to_take = 123
mock_props = props_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take) mock_props = props_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take)
random_user_query = from User, order_by: fragment("RANDOM()"), limit: 1 random_user_query = from(User, order_by: fragment("RANDOM()"), limit: 1)
mock_props = mock_props =
Enum.map(mock_props, fn e -> Enum.map(mock_props, fn e ->

View file

@ -1,9 +1,9 @@
defmodule Bones73k.AccountsTest do defmodule Shift73k.AccountsTest do
use Bones73k.DataCase use Shift73k.DataCase
alias Bones73k.Accounts alias Shift73k.Accounts
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
alias Bones73k.Accounts.{User, UserToken} alias Shift73k.Accounts.{User, UserToken}
describe "get_user_by_email/1" do describe "get_user_by_email/1" do
test "does not return the user if the email does not exist" do test "does not return the user if the email does not exist" do

View file

@ -1,11 +1,11 @@
defmodule Bones73k.PropertiesTest do defmodule Shift73k.PropertiesTest do
use Bones73k.DataCase use Shift73k.DataCase
alias Bones73k.Properties alias Shift73k.Properties
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
describe "properties" do describe "properties" do
alias Bones73k.Properties.Property alias Shift73k.Properties.Property
@valid_attrs %{description: "some description", name: "some name", price: "120.5"} @valid_attrs %{description: "some description", name: "some name", price: "120.5"}
@update_attrs %{ @update_attrs %{

View file

@ -1,14 +1,14 @@
defmodule Bones73kWeb.UserAuthTest do defmodule Shift73kWeb.UserAuthTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73kWeb.UserAuth alias Shift73kWeb.UserAuth
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
setup %{conn: conn} do setup %{conn: conn} do
conn = conn =
conn conn
|> Map.replace!(:secret_key_base, Bones73kWeb.Endpoint.config(:secret_key_base)) |> Map.replace!(:secret_key_base, Shift73kWeb.Endpoint.config(:secret_key_base))
|> init_test_session(%{}) |> init_test_session(%{})
%{user: user_fixture(), conn: conn} %{user: user_fixture(), conn: conn}
@ -63,7 +63,7 @@ defmodule Bones73kWeb.UserAuthTest do
test "broadcasts to the given live_socket_id", %{conn: conn} do test "broadcasts to the given live_socket_id", %{conn: conn} do
live_socket_id = "users_sessions:abcdef-token" live_socket_id = "users_sessions:abcdef-token"
Bones73kWeb.Endpoint.subscribe(live_socket_id) Shift73kWeb.Endpoint.subscribe(live_socket_id)
conn conn
|> put_session(:live_socket_id, live_socket_id) |> put_session(:live_socket_id, live_socket_id)

View file

@ -1,9 +1,9 @@
defmodule Bones73kWeb.UserConfirmationControllerTest do defmodule Shift73kWeb.UserConfirmationControllerTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Repo alias Shift73k.Repo
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
setup do setup do
%{user: user_fixture()} %{user: user_fixture()}

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserRegistrationControllerTest do defmodule Shift73kWeb.UserRegistrationControllerTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
describe "GET /users/register" do describe "GET /users/register" do
test "renders registration page", %{conn: conn} do test "renders registration page", %{conn: conn} do

View file

@ -1,9 +1,9 @@
defmodule Bones73kWeb.UserResetPasswordControllerTest do defmodule Shift73kWeb.UserResetPasswordControllerTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
alias Bones73k.Accounts alias Shift73k.Accounts
alias Bones73k.Repo alias Shift73k.Repo
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
setup do setup do
%{user: user_fixture()} %{user: user_fixture()}

View file

@ -1,7 +1,7 @@
defmodule Bones73kWeb.UserSessionControllerTest do defmodule Shift73kWeb.UserSessionControllerTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
setup do setup do
%{user: user_fixture()} %{user: user_fixture()}

View file

@ -1,8 +1,8 @@
defmodule Bones73kWeb.UserSettingsControllerTest do defmodule Shift73kWeb.UserSettingsControllerTest do
use Bones73kWeb.ConnCase, async: true use Shift73kWeb.ConnCase, async: true
alias Bones73k.Accounts alias Shift73k.Accounts
import Bones73k.AccountsFixtures import Shift73k.AccountsFixtures
setup :register_and_log_in_user setup :register_and_log_in_user

Some files were not shown because too many files have changed in this diff Show more