Skip to content

Commit

Permalink
feat: generated timer + check DateTime
Browse files Browse the repository at this point in the history
Signed-off-by: WoodenMaiden <yann.pomie@laposte.net>
  • Loading branch information
WoodenMaiden committed Apr 14, 2024
1 parent e576bd0 commit 4524a2a
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 0 deletions.
116 changes: 116 additions & 0 deletions lib/timecopsync_projects_api/projects.ex
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,120 @@ defmodule TimecopsyncProjectsApi.Projects do
def change_project(%Project{} = project, attrs \\ %{}) do
Project.changeset(project, attrs)
end

alias TimecopsyncProjectsApi.Projects.Timer

@doc """
Returns the list of timers.
## Examples
iex> list_timers()
[%Timer{}, ...]
"""
def list_timers do
Repo.all(Timer)
end

@doc """
Gets a single timer.
Raises `Ecto.NoResultsError` if the Timer does not exist.
## Examples
iex> get_timer!(123)
%Timer{}
iex> get_timer!(456)
** (Ecto.NoResultsError)
"""
def get_timer!(id), do: Repo.get!(Timer, id)

@doc """
Gets a single timer and returns it in a ok tuple. returns an error tuple if the timer does not exist.
## Examples
iex> get_timer(123)
{:ok, %Timer{}}
iex> get_timer(456)
{:error, "Timer not found"}
"""
@spec get_timer(Ecto.UUID.t() | String.t()) :: {:error, String.t()} | {:ok, any()}
def get_timer(id) do
case Repo.get(Timer, id) do
t when t != nil -> {:ok, t}
_ -> {:error, "Timer not found"}
end
end

@doc """
Creates a timer.
## Examples
iex> create_timer(%{field: value})
{:ok, %Timer{}}
iex> create_timer(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_timer(attrs \\ %{}) do
%Timer{}
|> Timer.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a timer.
## Examples
iex> update_timer(timer, %{field: new_value})
{:ok, %Timer{}}
iex> update_timer(timer, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_timer(%Timer{} = timer, attrs) do
timer
|> Timer.changeset(attrs)
|> Repo.update()
end

@doc """
Deletes a timer.
## Examples
iex> delete_timer(timer)
{:ok, %Timer{}}
iex> delete_timer(timer)
{:error, %Ecto.Changeset{}}
"""
def delete_timer(%Timer{} = timer) do
Repo.delete(timer)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking timer changes.
## Examples
iex> change_timer(timer)
%Ecto.Changeset{data: %Timer{}}
"""
def change_timer(%Timer{} = timer, attrs \\ %{}) do
Timer.changeset(timer, attrs)
end
end
43 changes: 43 additions & 0 deletions lib/timecopsync_projects_api/projects/timer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule TimecopsyncProjectsApi.Projects.Timer do
use Ecto.Schema
import Ecto.Changeset

require Logger

@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "timers" do
field :description, :string
field :notes, :string
field :start_time, :utc_datetime
field :end_time, :utc_datetime
field :project_id, :binary_id

timestamps(type: :utc_datetime)
end


defp check_chronology(_, ended) when is_nil(ended), do: :lt

defp check_chronology(started, ended) do
DateTime.compare(started, ended)
end

def validate_datetime_chronology(changeset) do
start_time = get_field(changeset, :start_time)
end_time = get_field(changeset, :end_time)

case check_chronology(start_time, end_time) do
:gt -> add_error(changeset, :end_time, "A timer cannot end before it started!")
_ -> changeset
end
end

@doc false
def changeset(timer, attrs) do
timer
|> cast(attrs, [:description, :notes, :start_time, :end_time])
|> validate_required([:start_time])
|> validate_datetime_chronology()
end
end
43 changes: 43 additions & 0 deletions lib/timecopsync_projects_api_web/controllers/timer_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule TimecopsyncProjectsApiWeb.TimerController do
use TimecopsyncProjectsApiWeb, :controller

alias TimecopsyncProjectsApi.Projects
alias TimecopsyncProjectsApi.Projects.Timer

action_fallback TimecopsyncProjectsApiWeb.FallbackController

def index(conn, _params) do
timers = Projects.list_timers()
render(conn, :index, timers: timers)
end

def create(conn, %{"timer" => timer_params}) do
with {:ok, %Timer{} = timer} <- Projects.create_timer(timer_params) do
conn
|> put_status(:created)
|> put_resp_header("location", ~p"/api/v1/timers/#{timer}")
|> render(:show, timer: timer)
end
end

def show(conn, %{"id" => id}) do
timer = Projects.get_timer!(id)
render(conn, :show, timer: timer)
end

def update(conn, %{"id" => id, "timer" => timer_params}) do
timer = Projects.get_timer!(id)

with {:ok, %Timer{} = timer} <- Projects.update_timer(timer, timer_params) do
render(conn, :show, timer: timer)
end
end

def delete(conn, %{"id" => id}) do
timer = Projects.get_timer!(id)

with {:ok, %Timer{}} <- Projects.delete_timer(timer) do
send_resp(conn, :no_content, "")
end
end
end
32 changes: 32 additions & 0 deletions lib/timecopsync_projects_api_web/controllers/timer_json.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule TimecopsyncProjectsApiWeb.TimerJSON do
alias TimecopsyncProjectsApi.Projects.Timer

@doc """
Renders a list of timers.
"""
def index(%{timers: timers}) do
%{
metadata: %{
total: length(timers)
# page: page,
},
data: for(timer <- timers, do: data(timer))}
end

@doc """
Renders a single timer.
"""
def show(%{timer: timer}) do
%{data: data(timer)}
end

defp data(%Timer{} = timer) do
%{
id: timer.id,
description: timer.description,
notes: timer.notes,
start_time: timer.start_time,
end_time: timer.end_time
}
end
end
1 change: 1 addition & 0 deletions lib/timecopsync_projects_api_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule TimecopsyncProjectsApiWeb.Router do
pipe_through :api

resources "/projects", ProjectController, except: [:new, :edit]
resources "/timers", TimerController, except: [:new, :edit]
end

# Enable LiveDashboard in development
Expand Down
18 changes: 18 additions & 0 deletions priv/repo/migrations/20240225232829_create_timers.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule TimecopsyncProjectsApi.Repo.Migrations.CreateTimers do
use Ecto.Migration

def change do
create table(:timers, primary_key: false) do
add :id, :binary_id, primary_key: true
add :description, :string
add :notes, :string
add :start_time, :utc_datetime
add :end_time, :utc_datetime
add :project_id, references(:projects, on_delete: :nothing, type: :binary_id)

timestamps(type: :utc_datetime)
end

create index(:timers, [:project_id])
end
end
17 changes: 17 additions & 0 deletions test/support/fixtures/projects_fixtures.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,21 @@ defmodule TimecopsyncProjectsApi.ProjectsFixtures do

project
end

@doc """
Generate a timer.
"""
def timer_fixture(attrs \\ %{}) do
{:ok, timer} =
attrs
|> Enum.into(%{
description: "some description",
end_time: ~U[2024-02-24 23:28:00Z],
notes: "some notes",
start_time: ~U[2024-02-24 23:28:00Z]
})
|> TimecopsyncProjectsApi.Projects.create_timer()

timer
end
end
60 changes: 60 additions & 0 deletions test/timecopsync_projects_api/projects_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,64 @@ defmodule TimecopsyncProjectsApi.ProjectsTest do
assert %Ecto.Changeset{} = Projects.change_project(project)
end
end

describe "timers" do
alias TimecopsyncProjectsApi.Projects.Timer

import TimecopsyncProjectsApi.ProjectsFixtures

@invalid_attrs %{description: nil, notes: nil, start_time: nil, end_time: nil}

test "list_timers/0 returns all timers" do
timer = timer_fixture()
assert Projects.list_timers() == [timer]
end

test "get_timer!/1 returns the timer with given id" do
timer = timer_fixture()
assert Projects.get_timer!(timer.id) == timer
end

test "create_timer/1 with valid data creates a timer" do
valid_attrs = %{description: "some description", notes: "some notes", start_time: ~U[2024-02-24 23:28:00Z], end_time: ~U[2024-02-24 23:28:00Z]}

assert {:ok, %Timer{} = timer} = Projects.create_timer(valid_attrs)
assert timer.description == "some description"
assert timer.notes == "some notes"
assert timer.start_time == ~U[2024-02-24 23:28:00Z]
assert timer.end_time == ~U[2024-02-24 23:28:00Z]
end

test "create_timer/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Projects.create_timer(@invalid_attrs)
end

test "update_timer/2 with valid data updates the timer" do
timer = timer_fixture()
update_attrs = %{description: "some updated description", notes: "some updated notes", start_time: ~U[2024-02-25 23:28:00Z], end_time: ~U[2024-02-25 23:28:00Z]}

assert {:ok, %Timer{} = timer} = Projects.update_timer(timer, update_attrs)
assert timer.description == "some updated description"
assert timer.notes == "some updated notes"
assert timer.start_time == ~U[2024-02-25 23:28:00Z]
assert timer.end_time == ~U[2024-02-25 23:28:00Z]
end

test "update_timer/2 with invalid data returns error changeset" do
timer = timer_fixture()
assert {:error, %Ecto.Changeset{}} = Projects.update_timer(timer, @invalid_attrs)
assert timer == Projects.get_timer!(timer.id)
end

test "delete_timer/1 deletes the timer" do
timer = timer_fixture()
assert {:ok, %Timer{}} = Projects.delete_timer(timer)
assert_raise Ecto.NoResultsError, fn -> Projects.get_timer!(timer.id) end
end

test "change_timer/1 returns a timer changeset" do
timer = timer_fixture()
assert %Ecto.Changeset{} = Projects.change_timer(timer)
end
end
end
Loading

0 comments on commit 4524a2a

Please sign in to comment.