initial shift template migration & schema working with user field/assoc for default shift template

This commit is contained in:
Adam Piontek 2021-03-06 13:48:13 -05:00
parent 61db634c36
commit a151bfcee7
16 changed files with 665 additions and 4 deletions

View file

@ -3,3 +3,5 @@ import Ecto.Query
alias Shift73k.Repo
alias Shift73k.Accounts
alias Shift73k.Accounts.User
alias Shift73k.ShiftTemplates, as: STemplates
alias Shift73k.ShiftTemplates.ShiftTemplate, as: STemplate

View file

@ -3,6 +3,8 @@ defmodule Shift73k.Accounts.User do
import Ecto.Changeset
import EctoEnum
alias Shift73k.ShiftTemplates.ShiftTemplate
@roles [
user: "Basic user level",
manager: "Can create users, update user emails & passwords",
@ -25,6 +27,11 @@ defmodule Shift73k.Accounts.User do
field(:confirmed_at, :naive_datetime)
field(:role, RolesEnum, default: :user)
has_many(:shift_templates, ShiftTemplate)
# has_one(:default_shift_template, ShiftTemplate, references: :default_shift_template_id)
belongs_to(:default_shift_template, ShiftTemplate)
timestamps()
end

View file

@ -0,0 +1,104 @@
defmodule Shift73k.ShiftTemplates do
@moduledoc """
The ShiftTemplates context.
"""
import Ecto.Query, warn: false
alias Shift73k.Repo
alias Shift73k.ShiftTemplates.ShiftTemplate
@doc """
Returns the list of shift_templates.
## Examples
iex> list_shift_templates()
[%ShiftTemplate{}, ...]
"""
def list_shift_templates do
Repo.all(ShiftTemplate)
end
@doc """
Gets a single shift_template.
Raises `Ecto.NoResultsError` if the Shift template does not exist.
## Examples
iex> get_shift_template!(123)
%ShiftTemplate{}
iex> get_shift_template!(456)
** (Ecto.NoResultsError)
"""
def get_shift_template!(id), do: Repo.get!(ShiftTemplate, id)
@doc """
Creates a shift_template.
## Examples
iex> create_shift_template(%{field: value})
{:ok, %ShiftTemplate{}}
iex> create_shift_template(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_shift_template(attrs \\ %{}) do
%ShiftTemplate{}
|> ShiftTemplate.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a shift_template.
## Examples
iex> update_shift_template(shift_template, %{field: new_value})
{:ok, %ShiftTemplate{}}
iex> update_shift_template(shift_template, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_shift_template(%ShiftTemplate{} = shift_template, attrs) do
shift_template
|> ShiftTemplate.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a shift_template.
## Examples
iex> delete_shift_template(shift_template)
{:ok, %ShiftTemplate{}}
iex> delete_shift_template(shift_template)
{:error, %Ecto.Changeset{}}
"""
def delete_shift_template(%ShiftTemplate{} = shift_template) do
Repo.delete(shift_template)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking shift_template changes.
## Examples
iex> change_shift_template(shift_template)
%Ecto.Changeset{data: %ShiftTemplate{}}
"""
def change_shift_template(%ShiftTemplate{} = shift_template, attrs \\ %{}) do
ShiftTemplate.changeset(shift_template, attrs)
end
end

View file

@ -0,0 +1,46 @@
defmodule Shift73k.ShiftTemplates.ShiftTemplate do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "shift_templates" do
field :label, :string
field :subject, :string
field :description, :string
field :location, :string
field :timezone, :string
field :start_time, :time
field :length_hours, :integer
field :length_minutes, :integer
belongs_to(:user, Shift73k.Accounts.User)
timestamps()
end
@doc false
def changeset(shift_template, attrs) do
shift_template
|> cast(attrs, [
:label,
:subject,
:description,
:location,
:timezone,
:start_time,
:length_hours,
:length_minutes,
:user_id
])
|> validate_required([
:subject,
:timezone,
:start_time,
:length_hours
])
|> validate_number(:length_hours, greater_than_or_equal_to: 0, less_than_or_equal_to: 24)
|> validate_number(:length_minutes, greater_than_or_equal_to: 0, less_than: 60)
|> validate_inclusion(:timezone, Tzdata.zone_list())
end
end

View file

@ -0,0 +1,55 @@
defmodule Shift73kWeb.ShiftTemplateLive.FormComponent do
use Shift73kWeb, :live_component
alias Shift73k.ShiftTemplates
@impl true
def update(%{shift_template: shift_template} = assigns, socket) do
changeset = ShiftTemplates.change_shift_template(shift_template)
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
end
@impl true
def handle_event("validate", %{"shift_template" => shift_template_params}, socket) do
changeset =
socket.assigns.shift_template
|> ShiftTemplates.change_shift_template(shift_template_params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
def handle_event("save", %{"shift_template" => shift_template_params}, socket) do
save_shift_template(socket, socket.assigns.action, shift_template_params)
end
defp save_shift_template(socket, :edit, shift_template_params) do
case ShiftTemplates.update_shift_template(socket.assigns.shift_template, shift_template_params) do
{:ok, _shift_template} ->
{:noreply,
socket
|> put_flash(:info, "Shift template updated successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_shift_template(socket, :new, shift_template_params) do
case ShiftTemplates.create_shift_template(shift_template_params) do
{:ok, _shift_template} ->
{:noreply,
socket
|> put_flash(:info, "Shift template created successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
end

View file

@ -0,0 +1,42 @@
<h2><%= @title %></h2>
<%= f = form_for @changeset, "#",
id: "shift_template-form",
phx_target: @myself,
phx_change: "validate",
phx_submit: "save" %>
<%= label f, :label %>
<%= text_input f, :label %>
<%= error_tag f, :label %>
<%= label f, :subject %>
<%= text_input f, :subject %>
<%= error_tag f, :subject %>
<%= label f, :description %>
<%= text_input f, :description %>
<%= error_tag f, :description %>
<%= label f, :location %>
<%= text_input f, :location %>
<%= error_tag f, :location %>
<%= label f, :timezone %>
<%= text_input f, :timezone %>
<%= error_tag f, :timezone %>
<%= label f, :start_time %>
<%= time_select f, :start_time %>
<%= error_tag f, :start_time %>
<%= label f, :length_hours %>
<%= number_input f, :length_hours %>
<%= error_tag f, :length_hours %>
<%= label f, :length_minutes %>
<%= number_input f, :length_minutes %>
<%= error_tag f, :length_minutes %>
<%= submit "Save", phx_disable_with: "Saving..." %>
</form>

View file

@ -0,0 +1,46 @@
defmodule Shift73kWeb.ShiftTemplateLive.Index do
use Shift73kWeb, :live_view
alias Shift73k.ShiftTemplates
alias Shift73k.ShiftTemplates.ShiftTemplate
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :shift_templates, list_shift_templates())}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Shift template")
|> assign(:shift_template, ShiftTemplates.get_shift_template!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Shift template")
|> assign(:shift_template, %ShiftTemplate{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Shift templates")
|> assign(:shift_template, nil)
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
shift_template = ShiftTemplates.get_shift_template!(id)
{:ok, _} = ShiftTemplates.delete_shift_template(shift_template)
{:noreply, assign(socket, :shift_templates, list_shift_templates())}
end
defp list_shift_templates do
ShiftTemplates.list_shift_templates()
end
end

View file

@ -0,0 +1,49 @@
<h1>Listing Shift templates</h1>
<%= if @live_action in [:new, :edit] do %>
<%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.FormComponent,
id: @shift_template.id || :new,
title: @page_title,
action: @live_action,
shift_template: @shift_template,
return_to: Routes.shift_template_index_path(@socket, :index) %>
<% end %>
<table>
<thead>
<tr>
<th>Label</th>
<th>Subject</th>
<th>Description</th>
<th>Location</th>
<th>Timezone</th>
<th>Start time</th>
<th>Length hours</th>
<th>Length minutes</th>
<th></th>
</tr>
</thead>
<tbody id="shift_templates">
<%= for shift_template <- @shift_templates do %>
<tr id="shift_template-<%= shift_template.id %>">
<td><%= shift_template.label %></td>
<td><%= shift_template.subject %></td>
<td><%= shift_template.description %></td>
<td><%= shift_template.location %></td>
<td><%= shift_template.timezone %></td>
<td><%= shift_template.start_time %></td>
<td><%= shift_template.length_hours %></td>
<td><%= shift_template.length_minutes %></td>
<td>
<span><%= live_redirect "Show", to: Routes.shift_template_show_path(@socket, :show, shift_template) %></span>
<span><%= live_patch "Edit", to: Routes.shift_template_index_path(@socket, :edit, shift_template) %></span>
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: shift_template.id, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<span><%= live_patch "New Shift template", to: Routes.shift_template_index_path(@socket, :new) %></span>

View file

@ -0,0 +1,21 @@
defmodule Shift73kWeb.ShiftTemplateLive.Show do
use Shift73kWeb, :live_view
alias Shift73k.ShiftTemplates
@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:shift_template, ShiftTemplates.get_shift_template!(id))}
end
defp page_title(:show), do: "Show Shift template"
defp page_title(:edit), do: "Edit Shift template"
end

View file

@ -0,0 +1,57 @@
<h1>Show Shift template</h1>
<%= if @live_action in [:edit] do %>
<%= live_modal @socket, Shift73kWeb.ShiftTemplateLive.FormComponent,
id: @shift_template.id,
title: @page_title,
action: @live_action,
shift_template: @shift_template,
return_to: Routes.shift_template_show_path(@socket, :show, @shift_template) %>
<% end %>
<ul>
<li>
<strong>Label:</strong>
<%= @shift_template.label %>
</li>
<li>
<strong>Subject:</strong>
<%= @shift_template.subject %>
</li>
<li>
<strong>Description:</strong>
<%= @shift_template.description %>
</li>
<li>
<strong>Location:</strong>
<%= @shift_template.location %>
</li>
<li>
<strong>Timezone:</strong>
<%= @shift_template.timezone %>
</li>
<li>
<strong>Start time:</strong>
<%= @shift_template.start_time %>
</li>
<li>
<strong>Length hours:</strong>
<%= @shift_template.length_hours %>
</li>
<li>
<strong>Length minutes:</strong>
<%= @shift_template.length_minutes %>
</li>
</ul>
<span><%= live_patch "Edit", to: Routes.shift_template_show_path(@socket, :edit, @shift_template), class: "button" %></span>
<span><%= live_redirect "Back", to: Routes.shift_template_index_path(@socket, :index) %></span>

View file

@ -88,9 +88,16 @@ defmodule Shift73kWeb.Router do
get("/users/confirm/:token", UserConfirmationController, :confirm)
end
# scope "/", Shift73kWeb do
# pipe_through([:browser, :require_authenticated_user, :user])
# end
scope "/", Shift73kWeb do
pipe_through([:browser, :require_authenticated_user, :user])
live "/shift_templates", ShiftTemplateLive.Index, :index
live "/shift_templates/new", ShiftTemplateLive.Index, :new
live "/shift_templates/:id/edit", ShiftTemplateLive.Index, :edit
live "/shift_templates/:id", ShiftTemplateLive.Show, :show
live "/shift_templates/:id/show/edit", ShiftTemplateLive.Show, :edit
end
# scope "/", Shift73kWeb do
# pipe_through([:browser, :require_authenticated_user, :admin])

View file

@ -0,0 +1,22 @@
defmodule Shift73k.Repo.Migrations.CreateShiftTemplates do
use Ecto.Migration
def change do
create table(:shift_templates, primary_key: false) do
add :id, :binary_id, primary_key: true
add :label, :string
add :subject, :string, null: false
add :description, :string
add :location, :string
add :timezone, :string, null: false
add :start_time, :time, null: false
add :length_hours, :integer, null: false
add :length_minutes, :integer
add :user_id, references(:users, on_delete: :nothing, type: :binary_id)
timestamps()
end
create index(:shift_templates, [:user_id])
end
end

View file

@ -0,0 +1,9 @@
defmodule Shift73k.Repo.Migrations.AddUserDefaultShiftColumn do
use Ecto.Migration
def change do
alter table(:users) do
add(:default_shift_template_id, references(:shift_templates, type: :binary_id, on_delete: :delete_all))
end
end
end

View file

@ -46,7 +46,7 @@ this_path = Path.dirname(__ENV__.file)
users_json = Path.join(this_path, "MOCK_DATA_users.json")
count_to_take = 65
count_to_take = 15
mock_users = users_json |> File.read!() |> Jason.decode!() |> Enum.take_random(count_to_take)

View file

@ -0,0 +1,78 @@
defmodule Shift73k.ShiftTemplatesTest do
use Shift73k.DataCase
alias Shift73k.ShiftTemplates
describe "shift_templates" do
alias Shift73k.ShiftTemplates.ShiftTemplate
@valid_attrs %{description: "some description", label: "some label", length_hours: 42, length_minutes: 42, location: "some location", start_time: ~T[14:00:00], subject: "some subject", timezone: "some timezone"}
@update_attrs %{description: "some updated description", label: "some updated label", length_hours: 43, length_minutes: 43, location: "some updated location", start_time: ~T[15:01:01], subject: "some updated subject", timezone: "some updated timezone"}
@invalid_attrs %{description: nil, label: nil, length_hours: nil, length_minutes: nil, location: nil, start_time: nil, subject: nil, timezone: nil}
def shift_template_fixture(attrs \\ %{}) do
{:ok, shift_template} =
attrs
|> Enum.into(@valid_attrs)
|> ShiftTemplates.create_shift_template()
shift_template
end
test "list_shift_templates/0 returns all shift_templates" do
shift_template = shift_template_fixture()
assert ShiftTemplates.list_shift_templates() == [shift_template]
end
test "get_shift_template!/1 returns the shift_template with given id" do
shift_template = shift_template_fixture()
assert ShiftTemplates.get_shift_template!(shift_template.id) == shift_template
end
test "create_shift_template/1 with valid data creates a shift_template" do
assert {:ok, %ShiftTemplate{} = shift_template} = ShiftTemplates.create_shift_template(@valid_attrs)
assert shift_template.description == "some description"
assert shift_template.label == "some label"
assert shift_template.length_hours == 42
assert shift_template.length_minutes == 42
assert shift_template.location == "some location"
assert shift_template.start_time == ~T[14:00:00]
assert shift_template.subject == "some subject"
assert shift_template.timezone == "some timezone"
end
test "create_shift_template/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = ShiftTemplates.create_shift_template(@invalid_attrs)
end
test "update_shift_template/2 with valid data updates the shift_template" do
shift_template = shift_template_fixture()
assert {:ok, %ShiftTemplate{} = shift_template} = ShiftTemplates.update_shift_template(shift_template, @update_attrs)
assert shift_template.description == "some updated description"
assert shift_template.label == "some updated label"
assert shift_template.length_hours == 43
assert shift_template.length_minutes == 43
assert shift_template.location == "some updated location"
assert shift_template.start_time == ~T[15:01:01]
assert shift_template.subject == "some updated subject"
assert shift_template.timezone == "some updated timezone"
end
test "update_shift_template/2 with invalid data returns error changeset" do
shift_template = shift_template_fixture()
assert {:error, %Ecto.Changeset{}} = ShiftTemplates.update_shift_template(shift_template, @invalid_attrs)
assert shift_template == ShiftTemplates.get_shift_template!(shift_template.id)
end
test "delete_shift_template/1 deletes the shift_template" do
shift_template = shift_template_fixture()
assert {:ok, %ShiftTemplate{}} = ShiftTemplates.delete_shift_template(shift_template)
assert_raise Ecto.NoResultsError, fn -> ShiftTemplates.get_shift_template!(shift_template.id) end
end
test "change_shift_template/1 returns a shift_template changeset" do
shift_template = shift_template_fixture()
assert %Ecto.Changeset{} = ShiftTemplates.change_shift_template(shift_template)
end
end
end

View file

@ -0,0 +1,116 @@
defmodule Shift73kWeb.ShiftTemplateLiveTest do
use Shift73kWeb.ConnCase
import Phoenix.LiveViewTest
alias Shift73k.ShiftTemplates
@create_attrs %{description: "some description", label: "some label", length_hours: 42, length_minutes: 42, location: "some location", start_time: ~T[14:00:00], subject: "some subject", timezone: "some timezone"}
@update_attrs %{description: "some updated description", label: "some updated label", length_hours: 43, length_minutes: 43, location: "some updated location", start_time: ~T[15:01:01], subject: "some updated subject", timezone: "some updated timezone"}
@invalid_attrs %{description: nil, label: nil, length_hours: nil, length_minutes: nil, location: nil, start_time: nil, subject: nil, timezone: nil}
defp fixture(:shift_template) do
{:ok, shift_template} = ShiftTemplates.create_shift_template(@create_attrs)
shift_template
end
defp create_shift_template(_) do
shift_template = fixture(:shift_template)
%{shift_template: shift_template}
end
describe "Index" do
setup [:create_shift_template]
test "lists all shift_templates", %{conn: conn, shift_template: shift_template} do
{:ok, _index_live, html} = live(conn, Routes.shift_template_index_path(conn, :index))
assert html =~ "Listing Shift templates"
assert html =~ shift_template.description
end
test "saves new shift_template", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
assert index_live |> element("a", "New Shift template") |> render_click() =~
"New Shift template"
assert_patch(index_live, Routes.shift_template_index_path(conn, :new))
assert index_live
|> form("#shift_template-form", shift_template: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#shift_template-form", shift_template: @create_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.shift_template_index_path(conn, :index))
assert html =~ "Shift template created successfully"
assert html =~ "some description"
end
test "updates shift_template in listing", %{conn: conn, shift_template: shift_template} do
{:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
assert index_live |> element("#shift_template-#{shift_template.id} a", "Edit") |> render_click() =~
"Edit Shift template"
assert_patch(index_live, Routes.shift_template_index_path(conn, :edit, shift_template))
assert index_live
|> form("#shift_template-form", shift_template: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
index_live
|> form("#shift_template-form", shift_template: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.shift_template_index_path(conn, :index))
assert html =~ "Shift template updated successfully"
assert html =~ "some updated description"
end
test "deletes shift_template in listing", %{conn: conn, shift_template: shift_template} do
{:ok, index_live, _html} = live(conn, Routes.shift_template_index_path(conn, :index))
assert index_live |> element("#shift_template-#{shift_template.id} a", "Delete") |> render_click()
refute has_element?(index_live, "#shift_template-#{shift_template.id}")
end
end
describe "Show" do
setup [:create_shift_template]
test "displays shift_template", %{conn: conn, shift_template: shift_template} do
{:ok, _show_live, html} = live(conn, Routes.shift_template_show_path(conn, :show, shift_template))
assert html =~ "Show Shift template"
assert html =~ shift_template.description
end
test "updates shift_template within modal", %{conn: conn, shift_template: shift_template} do
{:ok, show_live, _html} = live(conn, Routes.shift_template_show_path(conn, :show, shift_template))
assert show_live |> element("a", "Edit") |> render_click() =~
"Edit Shift template"
assert_patch(show_live, Routes.shift_template_show_path(conn, :edit, shift_template))
assert show_live
|> form("#shift_template-form", shift_template: @invalid_attrs)
|> render_change() =~ "can&apos;t be blank"
{:ok, _, html} =
show_live
|> form("#shift_template-form", shift_template: @update_attrs)
|> render_submit()
|> follow_redirect(conn, Routes.shift_template_show_path(conn, :show, shift_template))
assert html =~ "Shift template updated successfully"
assert html =~ "some updated description"
end
end
end