implemented optional 'allow_registration' config, with first registered user being pre-confirmed Admin, registration unavailable after that point if allow_registration: :false
This commit is contained in:
parent
ea74a89078
commit
f27df8d676
22 changed files with 395 additions and 244 deletions
|
@ -1,12 +1,14 @@
|
||||||
const togglerBtn = document.getElementById('navbarSupportedContentToggler');
|
const togglerBtn = document.getElementById('navbarSupportedContentToggler');
|
||||||
const navbarContent = document.getElementById('navbarSupportedContent');
|
const navbarContent = document.getElementById('navbarSupportedContent');
|
||||||
|
|
||||||
navbarContent.addEventListener('show.bs.collapse', () => {
|
if (navbarContent != null) {
|
||||||
|
navbarContent.addEventListener('show.bs.collapse', () => {
|
||||||
console.log('opening navbar content');
|
console.log('opening navbar content');
|
||||||
togglerBtn.classList.toggle('is-active');
|
togglerBtn.classList.toggle('is-active');
|
||||||
});
|
});
|
||||||
|
|
||||||
navbarContent.addEventListener('hide.bs.collapse', () => {
|
navbarContent.addEventListener('hide.bs.collapse', () => {
|
||||||
console.log('closing navbar content');
|
console.log('closing navbar content');
|
||||||
togglerBtn.classList.toggle('is-active');
|
togglerBtn.classList.toggle('is-active');
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ config :shift73k,
|
||||||
config :shift73k, :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",
|
||||||
|
allow_registration: :true
|
||||||
|
|
||||||
# Configures the endpoint
|
# Configures the endpoint
|
||||||
config :shift73k, Shift73kWeb.Endpoint,
|
config :shift73k, Shift73kWeb.Endpoint,
|
||||||
|
|
|
@ -108,6 +108,13 @@ defmodule Shift73k.Accounts do
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def register_user(attrs) do
|
def register_user(attrs) do
|
||||||
|
# If attrs has atom keys, convert to string
|
||||||
|
# If attrs don't include role, put default role
|
||||||
|
attrs =
|
||||||
|
attrs
|
||||||
|
|> Map.new(fn {k, v} -> {to_string(k), v} end)
|
||||||
|
|> Map.put_new("role", registration_role())
|
||||||
|
|
||||||
%User{}
|
%User{}
|
||||||
|> User.registration_changeset(attrs)
|
|> User.registration_changeset(attrs)
|
||||||
|> Repo.insert()
|
|> Repo.insert()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule Shift73kWeb.UserLive.Registration do
|
defmodule Shift73kWeb.UserLive.Registration do
|
||||||
use Shift73kWeb, :live_view
|
use Shift73kWeb, :live_view
|
||||||
|
alias Shift73k.Repo
|
||||||
alias Shift73k.Accounts
|
alias Shift73k.Accounts
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@ -20,9 +20,7 @@ defmodule Shift73kWeb.UserLive.Registration do
|
||||||
user_id: nil,
|
user_id: nil,
|
||||||
user_return_to: Map.get(session, "user_return_to", "/"),
|
user_return_to: Map.get(session, "user_return_to", "/"),
|
||||||
messages: [
|
messages: [
|
||||||
success: "Welcome! Your new account has been created, and you've been logged in.",
|
success: "Welcome! Your new account has been created, and you've been logged in."
|
||||||
info:
|
|
||||||
"Some features may be unavailable until you confirm your email address. Check your inbox for instructions."
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -35,19 +33,33 @@ defmodule Shift73kWeb.UserLive.Registration do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("save", %{"user" => user_params}, socket) do
|
def handle_event("save", %{"user" => user_params}, socket) do
|
||||||
|
is_first_user = !Repo.exists?(User)
|
||||||
user_params
|
user_params
|
||||||
|> Map.put("role", Accounts.registration_role())
|
|
||||||
|> Accounts.register_user()
|
|> Accounts.register_user()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, user} ->
|
{:ok, user} ->
|
||||||
|
# If this is the first user, we just confirm them
|
||||||
|
if is_first_user do
|
||||||
|
user |> User.confirm_changeset() |> Repo.update()
|
||||||
|
else
|
||||||
|
# Otherwise, all new users require email confirmation so we wend instructions
|
||||||
{:ok, _, %Swoosh.Email{} = _captured_email} =
|
{:ok, _, %Swoosh.Email{} = _captured_email} =
|
||||||
Accounts.deliver_user_confirmation_instructions(
|
Accounts.deliver_user_confirmation_instructions(
|
||||||
user,
|
user,
|
||||||
&Routes.user_confirmation_url(socket, :confirm, &1)
|
&Routes.user_confirmation_url(socket, :confirm, &1)
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
login_params =
|
||||||
|
if is_first_user do
|
||||||
|
socket.assigns.login_params
|
||||||
|
else
|
||||||
|
put_in(socket.assigns.login_params, [:messages, :info], "Some features may be unavailable until you confirm your email address. Check your inbox for instructions.")
|
||||||
|
end
|
||||||
|
|> put_in([:user_id], user.id)
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> assign(login_params: %{socket.assigns.login_params | user_id: user.id})
|
|> assign(login_params: login_params)
|
||||||
|> assign(trigger_submit: true)
|
|> assign(trigger_submit: true)
|
||||||
|> live_noreply()
|
|> live_noreply()
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
<p class="lead">Create an account to manage your work shifts with us.</p>
|
<p class="lead">Create an account to manage your work shifts with us.</p>
|
||||||
|
|
||||||
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, novalidate: true, id: "reg_form"], fn f -> %>
|
<.form let={f} for={@changeset} phx-change="validate" phx-submit="save" novalidate id="reg_form">
|
||||||
|
|
||||||
<%= label f, :email, class: "form-label" %>
|
<%= label f, :email, class: "form-label" %>
|
||||||
<div class="inner-addon left-addon mb-3" phx-feedback-for={input_id(f, :email)}>
|
<div class="inner-addon left-addon mb-3" phx-feedback-for={input_id(f, :email)}>
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
%>
|
%>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% end %>
|
</.form>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<%= link "Log in", to: Routes.user_session_path(@socket, :new) %> |
|
<%= link "Log in", to: Routes.user_session_path(@socket, :new) %> |
|
||||||
|
|
|
@ -4,6 +4,9 @@ defmodule Shift73kWeb.UserLive.ResetPassword do
|
||||||
alias Shift73k.Accounts
|
alias Shift73k.Accounts
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, session, socket) do
|
def mount(_params, session, socket) do
|
||||||
user = Accounts.get_user!(session["user_id"])
|
user = Accounts.get_user!(session["user_id"])
|
||||||
|
@ -37,4 +40,6 @@ defmodule Shift73kWeb.UserLive.ResetPassword do
|
||||||
|> assign(changeset: changeset)}
|
|> assign(changeset: changeset)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allow_registration, do: @app_allow_registration
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,7 +45,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p class="mt-3 is-pulled-right">
|
<p class="mt-3 is-pulled-right">
|
||||||
|
<%= if allow_registration() do %>
|
||||||
<%= link "Register", to: Routes.user_registration_path(@socket, :new) %> |
|
<%= link "Register", to: Routes.user_registration_path(@socket, :new) %> |
|
||||||
|
<% end %>
|
||||||
<%= link "Log in", to: Routes.user_session_path(@socket, :new) %>
|
<%= link "Log in", to: Routes.user_session_path(@socket, :new) %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
35
lib/shift73k_web/plugs/ensure_allow_registration_plug.ex
Normal file
35
lib/shift73k_web/plugs/ensure_allow_registration_plug.ex
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
defmodule Shift73kWeb.EnsureAllowRegistrationPlug do
|
||||||
|
@moduledoc """
|
||||||
|
This plug ensures that there is at least one known User.
|
||||||
|
"""
|
||||||
|
import Plug.Conn
|
||||||
|
import Phoenix.Controller
|
||||||
|
|
||||||
|
alias Shift73k.Repo
|
||||||
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec init(any()) :: any()
|
||||||
|
def init(config), do: config
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec call(Conn.t(), atom() | [atom()]) :: Conn.t()
|
||||||
|
def call(conn, _opts) do
|
||||||
|
# If there aren't even any users, or registration is allowed
|
||||||
|
if !Repo.exists?(User) || @app_allow_registration do
|
||||||
|
# We will allow registration
|
||||||
|
conn
|
||||||
|
else
|
||||||
|
# Otherwise,
|
||||||
|
# if app is configured to not allow registration,
|
||||||
|
# and there is a user,
|
||||||
|
# then we redirect to root URL
|
||||||
|
conn
|
||||||
|
|> redirect(to: "/")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -27,8 +27,7 @@ defmodule Shift73kWeb.EnsureRolePlug do
|
||||||
def call(conn, roles) do
|
def call(conn, roles) do
|
||||||
user_token = get_session(conn, :user_token)
|
user_token = get_session(conn, :user_token)
|
||||||
|
|
||||||
(user_token &&
|
(user_token && Accounts.get_user_by_session_token(user_token))
|
||||||
Accounts.get_user_by_session_token(user_token))
|
|
||||||
|> has_role?(roles)
|
|> has_role?(roles)
|
||||||
|> maybe_halt(conn)
|
|> maybe_halt(conn)
|
||||||
end
|
end
|
||||||
|
|
30
lib/shift73k_web/plugs/ensure_user_exist_plug.ex
Normal file
30
lib/shift73k_web/plugs/ensure_user_exist_plug.ex
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
defmodule Shift73kWeb.EnsureUserExistPlug do
|
||||||
|
@moduledoc """
|
||||||
|
This plug ensures that there is at least one known User.
|
||||||
|
"""
|
||||||
|
import Plug.Conn
|
||||||
|
import Phoenix.Controller
|
||||||
|
|
||||||
|
alias Shift73k.Repo
|
||||||
|
alias Shift73k.Accounts.User
|
||||||
|
alias Shift73kWeb.Router.Helpers, as: Routes
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec init(any()) :: any()
|
||||||
|
def init(config), do: config
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec call(Conn.t(), atom() | [atom()]) :: Conn.t()
|
||||||
|
def call(conn, _opts) do
|
||||||
|
# If there aren't even any users,
|
||||||
|
if !Repo.exists?(User) do
|
||||||
|
# We're just going to redirect to registration
|
||||||
|
conn
|
||||||
|
|> redirect(to: Routes.user_registration_path(conn, :new))
|
||||||
|
|> halt()
|
||||||
|
else
|
||||||
|
# Otherwise we proceed as normal
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,27 +2,37 @@ defmodule Shift73kWeb.Router do
|
||||||
use Shift73kWeb, :router
|
use Shift73kWeb, :router
|
||||||
import Shift73kWeb.UserAuth
|
import Shift73kWeb.UserAuth
|
||||||
alias Shift73kWeb.EnsureRolePlug
|
alias Shift73kWeb.EnsureRolePlug
|
||||||
|
alias Shift73kWeb.EnsureUserExistPlug
|
||||||
|
alias Shift73kWeb.EnsureAllowRegistrationPlug
|
||||||
|
|
||||||
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, {Shift73kWeb.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
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :user do
|
pipeline :ensure_role_user do
|
||||||
plug(EnsureRolePlug, [:admin, :manager, :user])
|
plug EnsureRolePlug, [:admin, :manager, :user]
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :manager do
|
pipeline :ensure_user_exist do
|
||||||
plug(EnsureRolePlug, [:admin, :manager])
|
plug EnsureUserExistPlug
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :admin do
|
pipeline :ensure_allow_registration do
|
||||||
plug(EnsureRolePlug, :admin)
|
plug EnsureAllowRegistrationPlug
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline :ensure_role_manager do
|
||||||
|
plug EnsureRolePlug, [:admin, :manager]
|
||||||
|
end
|
||||||
|
|
||||||
|
pipeline :ensure_role_admin do
|
||||||
|
plug EnsureRolePlug, :admin
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables the Swoosh mailbox preview in development.
|
# Enables the Swoosh mailbox preview in development.
|
||||||
|
@ -38,49 +48,54 @@ defmodule Shift73kWeb.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Shift73kWeb do
|
scope "/", Shift73kWeb do
|
||||||
pipe_through([:browser])
|
pipe_through([:browser, :ensure_user_exist])
|
||||||
|
|
||||||
get("/", Redirector, to: "/assign")
|
get "/", Redirector, to: "/assign"
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Shift73kWeb do
|
scope "/", Shift73kWeb do
|
||||||
pipe_through([:browser, :redirect_if_user_is_authenticated])
|
pipe_through [:browser, :redirect_if_user_is_authenticated, :ensure_allow_registration]
|
||||||
|
|
||||||
|
get "/users/register", UserRegistrationController, :new
|
||||||
|
end
|
||||||
|
|
||||||
|
scope "/", Shift73kWeb do
|
||||||
|
pipe_through [:browser, :redirect_if_user_is_authenticated, :ensure_user_exist]
|
||||||
|
|
||||||
# session routes, irrelevant if user is authenticated
|
# session routes, irrelevant if user is authenticated
|
||||||
get("/users/register", UserRegistrationController, :new)
|
get "/users/log_in", UserSessionController, :new
|
||||||
get("/users/log_in", UserSessionController, :new)
|
post "/users/log_in", UserSessionController, :create
|
||||||
post("/users/log_in", UserSessionController, :create)
|
get "/users/reset_password", UserResetPasswordController, :new
|
||||||
get("/users/reset_password", UserResetPasswordController, :new)
|
post "/users/reset_password", UserResetPasswordController, :create
|
||||||
post("/users/reset_password", UserResetPasswordController, :create)
|
get "/users/reset_password/:token", UserResetPasswordController, :edit
|
||||||
get("/users/reset_password/:token", UserResetPasswordController, :edit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Shift73kWeb do
|
scope "/", Shift73kWeb do
|
||||||
pipe_through([:browser, :require_authenticated_user])
|
pipe_through [:browser, :require_authenticated_user]
|
||||||
|
|
||||||
# user settings (change email, password, calendar week start, etc)
|
# user settings (change email, password, calendar week start, etc)
|
||||||
live("/users/settings", UserLive.Settings, :edit)
|
live "/users/settings", UserLive.Settings, :edit
|
||||||
|
|
||||||
# confirm email by token
|
# confirm email by token
|
||||||
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
|
get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Shift73kWeb do
|
scope "/", Shift73kWeb do
|
||||||
pipe_through([:browser])
|
pipe_through [:browser, :ensure_user_exist]
|
||||||
|
|
||||||
# session paths
|
# session paths
|
||||||
delete("/users/log_out", UserSessionController, :delete)
|
delete "/users/log_out", UserSessionController, :delete
|
||||||
get("/users/force_logout", UserSessionController, :force_logout)
|
get "/users/force_logout", UserSessionController, :force_logout
|
||||||
get("/users/confirm", UserConfirmationController, :new)
|
get "/users/confirm", UserConfirmationController, :new
|
||||||
post("/users/confirm", UserConfirmationController, :create)
|
post "/users/confirm", UserConfirmationController, :create
|
||||||
get("/users/confirm/:token", UserConfirmationController, :confirm)
|
get "/users/confirm/:token", UserConfirmationController, :confirm
|
||||||
|
|
||||||
# ics/ical route for user's shifts
|
# ics/ical route for user's shifts
|
||||||
get("/ics/:slug", UserShiftsIcsController, :index)
|
get "/ics/:slug", UserShiftsIcsController, :index
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Shift73kWeb do
|
scope "/", Shift73kWeb do
|
||||||
pipe_through([:browser, :require_authenticated_user, :user])
|
pipe_through [:browser, :require_authenticated_user, :ensure_role_user]
|
||||||
|
|
||||||
live "/templates", ShiftTemplateLive.Index, :index
|
live "/templates", ShiftTemplateLive.Index, :index
|
||||||
live "/templates/new", ShiftTemplateLive.Index, :new
|
live "/templates/new", ShiftTemplateLive.Index, :new
|
||||||
|
@ -98,16 +113,16 @@ defmodule Shift73kWeb.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
# scope "/", Shift73kWeb do
|
# scope "/", Shift73kWeb do
|
||||||
# pipe_through([:browser, :require_authenticated_user, :admin])
|
# pipe_through([:browser, :require_authenticated_user, :ensure_role_admin])
|
||||||
# end
|
# end
|
||||||
|
|
||||||
# Users Management
|
# Users Management
|
||||||
scope "/users", Shift73kWeb do
|
scope "/users", Shift73kWeb do
|
||||||
pipe_through([:browser, :require_authenticated_user, :manager, :require_email_confirmed])
|
pipe_through [:browser, :require_authenticated_user, :ensure_role_manager, :require_email_confirmed]
|
||||||
|
|
||||||
live("/", UserManagementLive.Index, :index)
|
live "/", UserManagementLive.Index, :index
|
||||||
live("/new", UserManagementLive.Index, :new)
|
live "/new", UserManagementLive.Index, :new
|
||||||
live("/edit/:id", UserManagementLive.Index, :edit)
|
live "/edit/:id", UserManagementLive.Index, :edit
|
||||||
# resources "/", UserManagementController, only: [:new, :create, :edit, :update]
|
# resources "/", UserManagementController, only: [:new, :create, :edit, :update]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,59 +8,26 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<%= if @current_user do %>
|
<%# If there's a current user,
|
||||||
|
OR if there are users & we allow registration,
|
||||||
|
THEN we will show a full menu configuration %>
|
||||||
|
|
||||||
|
<%= if @current_user || (Repo.exists?(User) && allow_registration()) do %>
|
||||||
|
|
||||||
<button class="hamburger hamburger--squeeze collapsed navbar-toggler" id="navbarSupportedContentToggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
<button class="hamburger hamburger--squeeze collapsed navbar-toggler" id="navbarSupportedContentToggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="hamburger-box d-flex">
|
<span class="hamburger-box d-flex">
|
||||||
<span class="hamburger-inner"></span>
|
<span class="hamburger-inner"></span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<% else %>
|
|
||||||
<%= link nav_link_opts(@conn, to: Routes.user_session_path(@conn, :new), class: "btn btn-outline-light d-block d-lg-none") do %>
|
|
||||||
<i class="bi bi-door-open me-1"></i> Log in
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
|
||||||
<%# nav LEFT items %>
|
<%# nav LEFT items %>
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
|
||||||
<%#= if @current_user do %>
|
|
||||||
<%# <li class="nav-item"> %>
|
|
||||||
<%#= link nav_link_opts(@conn, to: Routes.shift_template_index_path(@conn, :index), class: "nav-link") do %>
|
|
||||||
<%#= icon_div @conn, "bi-clock-history", [class: "icon baseline me-1"] %>
|
|
||||||
<%# Templates %>
|
|
||||||
<%# end %>
|
|
||||||
<%# </li> %>
|
|
||||||
<%# end %>
|
|
||||||
|
|
||||||
<%# normal navbar link example %>
|
|
||||||
<%# <li class="nav-item"> %>
|
|
||||||
<%#= link "Properties", nav_link_opts(@conn, to: Routes.property_index_path(@conn, :index), class: "nav-link") %>
|
|
||||||
<%# </li> %>
|
|
||||||
|
|
||||||
<%# ACTIVE page link example %>
|
|
||||||
<%# <li class="nav-item">
|
|
||||||
<a class="nav-link active" aria-current="page" href="#">Home</a>
|
|
||||||
</li> %>
|
|
||||||
|
|
||||||
<%# DISABLED page link example %>
|
|
||||||
<%# <li class="nav-item">
|
|
||||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
|
|
||||||
</li> %>
|
|
||||||
|
|
||||||
<%# normal dropdown menu example %>
|
|
||||||
<%# <li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownExample" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdownExample">
|
|
||||||
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Another action</a></li>
|
|
||||||
<li><hr class="dropdown-divider"></li>
|
|
||||||
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li> %>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<%# nav RIGHT items %>
|
<%# nav RIGHT items %>
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
|
@ -73,14 +40,31 @@
|
||||||
|
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|
||||||
<%= link nav_link_opts(@conn, to: Routes.user_session_path(@conn, :new), class: "btn btn-outline-light d-none d-lg-block") do %>
|
<%= render "navbar/_nouser_menu.html", assigns %>
|
||||||
<i class="bi bi-door-open me-1"></i> Log in
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<%# If there's no current user,
|
||||||
|
AND:
|
||||||
|
There are no users -- [REGISTER]
|
||||||
|
OR no registration allowed -- [LOG IN] %>
|
||||||
|
<%= else %>
|
||||||
|
|
||||||
|
<%= if !Repo.exists?(User) || allow_registration() do %>
|
||||||
|
<%= link nav_link_opts(@conn, to: Routes.user_registration_path(@conn, :new), class: "btn btn-outline-light") do %>
|
||||||
|
<i class="bi bi-journal-plus"></i> Register
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<%= link nav_link_opts(@conn, to: Routes.user_session_path(@conn, :new), class: "btn btn-outline-light") do %>
|
||||||
|
<i class="bi bi-door-open"></i> Log in
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
|
||||||
|
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-person-circle me-1"></i> Hello?
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownUserMenu">
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<%= link nav_link_opts(@conn, to: Routes.user_registration_path(@conn, :new), class: "dropdown-item") do %>
|
||||||
|
<i class="bi bi-journal-plus me-1"></i> Register
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<%= link nav_link_opts(@conn, to: Routes.user_session_path(@conn, :new), class: "dropdown-item") do %>
|
||||||
|
<i class="bi bi-door-open me-1"></i> Log in
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</li>
|
|
@ -1,7 +1,7 @@
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
|
|
||||||
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
<a href="#" class="nav-link dropdown-toggle" id="navbarDropdownUserMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
<i class="bi bi-person-circle me-1"></i> <%= @current_user && "Hello!" || "Hello?" %>
|
<i class="bi bi-person-circle me-1"></i> Hello!
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownUserMenu">
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownUserMenu">
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
<%= if allow_registration() do %>
|
||||||
|
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
||||||
|
<% end %>
|
||||||
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
||||||
<%= link "Log in", to: Routes.user_session_path(@conn, :new) %>
|
<%= link "Log in", to: Routes.user_session_path(@conn, :new) %>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
<%= if allow_registration() do %>
|
||||||
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
||||||
|
<% end %>
|
||||||
<%= link "Log in", to: Routes.user_session_path(@conn, :new) %>
|
<%= link "Log in", to: Routes.user_session_path(@conn, :new) %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
<%= if allow_registration() do %>
|
||||||
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
<%= link "Register", to: Routes.user_registration_path(@conn, :new) %> |
|
||||||
|
<% end %>
|
||||||
<%= link "Forgot your password?", to: Routes.user_reset_password_path(@conn, :new) %>
|
<%= link "Forgot your password?", to: Routes.user_reset_password_path(@conn, :new) %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
defmodule Shift73kWeb.LayoutView do
|
defmodule Shift73kWeb.LayoutView do
|
||||||
use Shift73kWeb, :view
|
use Shift73kWeb, :view
|
||||||
|
alias Shift73k.Repo
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
alias Shift73kWeb.Roles
|
alias Shift73kWeb.Roles
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
# With a Vite.js-based workflow, we will import different asset files in development
|
# With a Vite.js-based workflow, we will import different asset files in development
|
||||||
# and in production builds. Therefore, we will need a way to conditionally render
|
# and in production builds. Therefore, we will need a way to conditionally render
|
||||||
# <script> tags based on Mix environment. However, since Mix is not available in
|
# <script> tags based on Mix environment. However, since Mix is not available in
|
||||||
|
@ -11,6 +14,8 @@ defmodule Shift73kWeb.LayoutView do
|
||||||
@env Mix.env() # remember value at compile time
|
@env Mix.env() # remember value at compile time
|
||||||
def dev_env?, do: @env == :dev
|
def dev_env?, do: @env == :dev
|
||||||
|
|
||||||
|
def allow_registration, do: @app_allow_registration
|
||||||
|
|
||||||
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
|
||||||
false -> opts
|
false -> opts
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
defmodule Shift73kWeb.UserConfirmationView do
|
defmodule Shift73kWeb.UserConfirmationView do
|
||||||
use Shift73kWeb, :view
|
use Shift73kWeb, :view
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
|
def allow_registration, do: @app_allow_registration
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
defmodule Shift73kWeb.UserResetPasswordView do
|
defmodule Shift73kWeb.UserResetPasswordView do
|
||||||
use Shift73kWeb, :view
|
use Shift73kWeb, :view
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
|
def allow_registration, do: @app_allow_registration
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
defmodule Shift73kWeb.UserSessionView do
|
defmodule Shift73kWeb.UserSessionView do
|
||||||
use Shift73kWeb, :view
|
use Shift73kWeb, :view
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
|
@app_vars Application.compile_env(:shift73k, :app_global_vars, allow_registration: :true)
|
||||||
|
@app_allow_registration @app_vars[:allow_registration]
|
||||||
|
|
||||||
|
def allow_registration, do: @app_allow_registration
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,10 +14,15 @@ alias Shift73k.Repo
|
||||||
alias Shift73k.Accounts
|
alias Shift73k.Accounts
|
||||||
alias Shift73k.Accounts.User
|
alias Shift73k.Accounts.User
|
||||||
|
|
||||||
############################################################################
|
|
||||||
## INSERTING MOCK USER DATA
|
|
||||||
|
|
||||||
{:ok, _admin} =
|
if Mix.env() == :dev do
|
||||||
|
|
||||||
|
if System.get_env("ECTO_SEED_DB") do
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
## INSERTING MOCK USER DATA
|
||||||
|
|
||||||
|
{:ok, _admin} =
|
||||||
Accounts.register_user(%{
|
Accounts.register_user(%{
|
||||||
email: "admin@company.com",
|
email: "admin@company.com",
|
||||||
password: "123456789abC",
|
password: "123456789abC",
|
||||||
|
@ -25,7 +30,7 @@ alias Shift73k.Accounts.User
|
||||||
role: Accounts.registration_role()
|
role: Accounts.registration_role()
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, _user_1} =
|
{:ok, _user_1} =
|
||||||
Accounts.register_user(%{
|
Accounts.register_user(%{
|
||||||
email: "user1@company.com",
|
email: "user1@company.com",
|
||||||
password: "123456789abC",
|
password: "123456789abC",
|
||||||
|
@ -33,7 +38,7 @@ alias Shift73k.Accounts.User
|
||||||
role: Accounts.registration_role()
|
role: Accounts.registration_role()
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, _user_2} =
|
{:ok, _user_2} =
|
||||||
Accounts.register_user(%{
|
Accounts.register_user(%{
|
||||||
email: "user2@company.com",
|
email: "user2@company.com",
|
||||||
password: "123456789abC",
|
password: "123456789abC",
|
||||||
|
@ -41,27 +46,27 @@ alias Shift73k.Accounts.User
|
||||||
role: Accounts.registration_role()
|
role: Accounts.registration_role()
|
||||||
})
|
})
|
||||||
|
|
||||||
# if Mix.env() == :dev do
|
# if Mix.env() == :dev do
|
||||||
this_path = Path.dirname(__ENV__.file)
|
this_path = Path.dirname(__ENV__.file)
|
||||||
users_json = Path.join(this_path, "MOCK_DATA_users.json")
|
users_json = Path.join(this_path, "MOCK_DATA_users.json")
|
||||||
|
|
||||||
count_to_take = 15
|
count_to_take = 15
|
||||||
|
|
||||||
mock_users = users_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take)
|
mock_users = users_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take)
|
||||||
|
|
||||||
extra_mock_users = ~s([
|
extra_mock_users = ~s([
|
||||||
{"email":"adam@73k.us","password":"adamadamA1","role":"admin","inserted_at":"2018-12-14T01:01:01Z","confirmed_at":true},
|
{"email":"adam@73k.us","password":"adamadamA1","role":"admin","inserted_at":"2018-12-14T01:01:01Z","confirmed_at":true},
|
||||||
{"email":"kat@73k.us","password":"katkatA1","role":"manager","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":true},
|
{"email":"kat@73k.us","password":"katkatA1","role":"manager","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":true},
|
||||||
{"email":"babka@73k.us","password":"Babka2020","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false},
|
{"email":"babka@73k.us","password":"Babka2020","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false},
|
||||||
{"email":"malcolm@73k.us","password":"Malc2018","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false},
|
{"email":"malcolm@73k.us","password":"Malc2018","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false},
|
||||||
{"email":"casio@73k.us","password":"Casio2011","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false}
|
{"email":"casio@73k.us","password":"Casio2011","role":"user","inserted_at":"2018-12-14T01:06:01Z","confirmed_at":false}
|
||||||
])
|
])
|
||||||
|
|
||||||
# for random week_start_at values
|
# for random week_start_at values
|
||||||
[head | tail] = Shift73k.weekdays()
|
[head | tail] = Shift73k.weekdays()
|
||||||
week_starts = [head | Enum.drop(tail, 4)]
|
week_starts = [head | Enum.drop(tail, 4)]
|
||||||
|
|
||||||
mock_users =
|
mock_users =
|
||||||
extra_mock_users
|
extra_mock_users
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|> Stream.concat(mock_users)
|
|> Stream.concat(mock_users)
|
||||||
|
@ -80,28 +85,28 @@ mock_users =
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Repo.insert_all(User, mock_users)
|
Repo.insert_all(User, mock_users)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
#####
|
#####
|
||||||
# shift tepmlates
|
# shift tepmlates
|
||||||
alias Shift73k.Shifts.Templates.ShiftTemplate
|
alias Shift73k.Shifts.Templates.ShiftTemplate
|
||||||
|
|
||||||
shifts_json = Path.join(this_path, "MOCK_DATA_shift-templates.json")
|
shifts_json = Path.join(this_path, "MOCK_DATA_shift-templates.json")
|
||||||
mock_shifts = shifts_json |> File.read!() |> Jason.decode!()
|
mock_shifts = shifts_json |> File.read!() |> Jason.decode!()
|
||||||
|
|
||||||
time_from_mock = fn mock_time ->
|
time_from_mock = fn mock_time ->
|
||||||
case String.length(mock_time) do
|
case String.length(mock_time) do
|
||||||
4 -> Time.from_iso8601!("T0#{mock_time}:00")
|
4 -> Time.from_iso8601!("T0#{mock_time}:00")
|
||||||
5 -> Time.from_iso8601!("T#{mock_time}:00")
|
5 -> Time.from_iso8601!("T#{mock_time}:00")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
seconds_day = 86_400
|
seconds_day = 86_400
|
||||||
seconds_days_14 = seconds_day * 14
|
seconds_days_14 = seconds_day * 14
|
||||||
seconds_half_day = Integer.floor_div(seconds_day, 2)
|
seconds_half_day = Integer.floor_div(seconds_day, 2)
|
||||||
|
|
||||||
for user <- Accounts.list_users() do
|
for user <- Accounts.list_users() do
|
||||||
user_shifts =
|
user_shifts =
|
||||||
mock_shifts
|
mock_shifts
|
||||||
|> Enum.take_random(:rand.uniform(15) + 5)
|
|> Enum.take_random(:rand.uniform(15) + 5)
|
||||||
|
@ -127,14 +132,14 @@ for user <- Accounts.list_users() do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Repo.insert_all(ShiftTemplate, user_shifts)
|
Repo.insert_all(ShiftTemplate, user_shifts)
|
||||||
end
|
end
|
||||||
|
|
||||||
#####
|
#####
|
||||||
# insert shifts for each user?
|
# insert shifts for each user?
|
||||||
alias Shift73k.Shifts
|
alias Shift73k.Shifts
|
||||||
alias Shift73k.Shifts.Templates
|
alias Shift73k.Shifts.Templates
|
||||||
|
|
||||||
for user <- Accounts.list_users() do
|
for user <- Accounts.list_users() do
|
||||||
# build a date range for the time from 120 days ago to 120 days from now
|
# build a date range for the time from 120 days ago to 120 days from now
|
||||||
today = Date.utc_today()
|
today = Date.utc_today()
|
||||||
date_range = Date.range(Date.add(today, -120), Date.add(today, 120))
|
date_range = Date.range(Date.add(today, -120), Date.add(today, 120))
|
||||||
|
@ -151,4 +156,8 @@ for user <- Accounts.list_users() do
|
||||||
|> Enum.map(&Repo.timestamp/1)
|
|> Enum.map(&Repo.timestamp/1)
|
||||||
|> Shifts.create_multiple()
|
|> Shifts.create_multiple()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue