Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions lib/atlas/university/degrees/courses/shifts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule Atlas.University.Degrees.Courses.Shifts do
use Atlas.Context

alias Atlas.University.Degrees.Courses.Shifts.Shift
alias Ecto.Multi

@doc """
Returns the list of shifts.
Expand All @@ -21,6 +22,13 @@ defmodule Atlas.University.Degrees.Courses.Shifts do
|> Repo.all()
end

def list_shifts_with_timeslots(opts \\ []) do
Shift
|> apply_filters(opts)
|> Repo.all()
|> Repo.preload([:timeslots])
end

@doc """
Gets a single shift.

Expand All @@ -41,6 +49,13 @@ defmodule Atlas.University.Degrees.Courses.Shifts do
|> Repo.get!(id)
end

def get_shift_with_timeslots(id, opts \\ []) do
Shift
|> apply_filters(opts)
|> Repo.get(id)
|> Repo.preload([:timeslots])
end

@doc """
Creates a shift.

Expand Down Expand Up @@ -208,4 +223,50 @@ defmodule Atlas.University.Degrees.Courses.Shifts do
def change_timeslot(%Timeslot{} = timeslot, attrs \\ %{}) do
Timeslot.changeset(timeslot, attrs)
end

@doc """
Updates a shift that contains
"""

def update_shift_with_timeslots(shift, shift_attrs, timeslot_attrs) do
Multi.new()
|> Multi.update(:shift, change_shift(shift, shift_attrs))
|> process_timeslots(shift, timeslot_attrs)
|> Repo.transact()
end

defp process_timeslots(multi, shift, timeslot_attrs) do
multi
|> then(fn multi ->
timeslot_attrs
|> Enum.with_index()
|> Enum.reduce(multi, fn {timeslot_attr, index}, acc_multi ->
process_timeslot(acc_multi, timeslot_attr, shift.id, index)
end)
end)
end

defp process_timeslot(multi, timeslot_attr, shift_id, index) do
if timeslot_attr["id"] && timeslot_exists?(timeslot_attr["id"]) do
timeslot = get_timeslot!(timeslot_attr["id"])
changeset = change_timeslot(timeslot, Map.delete(timeslot_attr, "id"))
Multi.update(multi, {:timeslot, index}, changeset)
else
clean_attrs =
timeslot_attr
|> Map.delete("id")
|> Map.put("shift_id", shift_id)
|> Map.replace("weekday", timeslot_attr["weekday"] |> String.to_atom())

changeset = change_timeslot(%Timeslot{}, clean_attrs)
Multi.insert(multi, {:timeslot, index}, changeset)
end
end

defp timeslot_exists?(id) do
case Repo.get(Timeslot, id) do
nil -> false
_ -> true
end
end
end
38 changes: 38 additions & 0 deletions lib/atlas/university/degrees/courses/timeslots.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule Atlas.University.Degrees.Courses.Timeslots do
@moduledoc """
The Timeslots context.
"""
use Atlas.Context
alias Atlas.University.Degrees.Courses.Shifts.Timeslot

@doc """
Gets a single timeslot.

## Examples

iex> get_timeslot!(123)
%Timeslot{}

iex> get_timeslot!(456)
** (Ecto.NoResultsError)
"""
def get_timeslot!(id, opts \\ []) do
Timeslot
|> apply_filters(opts)
|> Repo.get!(id)
end

@doc """
Deletes a timeslot.
## Examples

iex> delete_timeslot(timeslot)
{:ok, %Timeslot{}}

iex> delete_timeslot(timeslot)
{:error, %Ecto.Changeset{}}
"""
def delete_timeslot(%Timeslot{} = timeslot) do
Repo.delete(timeslot)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ defmodule AtlasWeb.ShiftExchangeRequestJSON do
@moduledoc """
A module for rendering shift exchange request data in JSON format.
"""
alias AtlasWeb.University.{CourseJSON, ShiftJSON}
alias AtlasWeb.ShiftsJSON
alias AtlasWeb.University.CourseJSON

@doc """
Renders a list of shift exchange requests as JSON.
Expand All @@ -28,8 +29,8 @@ defmodule AtlasWeb.ShiftExchangeRequestJSON do
%{
id: shift_exchange_request.id,
status: shift_exchange_request.status,
from: ShiftJSON.data(shift_exchange_request.from),
to: ShiftJSON.data(shift_exchange_request.to),
from: ShiftsJSON.data(shift_exchange_request.from),
to: ShiftsJSON.data(shift_exchange_request.to),
course: CourseJSON.data(shift_exchange_request.from.course),
inserted_at: shift_exchange_request.inserted_at
}
Expand Down
53 changes: 53 additions & 0 deletions lib/atlas_web/controllers/shifts/shifts_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule AtlasWeb.ShiftsController do
use AtlasWeb, :controller

alias Atlas.Repo
alias Atlas.University.Degrees.Courses.Shifts

action_fallback AtlasWeb.FallbackController

def index(conn, attrs) do
{user, _} = Guardian.Plug.current_resource(conn)

if user_has_elevated_privileges?(user) do
shifts = Shifts.list_shifts_with_timeslots(attrs)

conn
|> render(:index, shifts: shifts)
else
conn
|> put_status(:forbidden)
|> json(%{error: "Unauthorized"})
end
end

def update(conn, %{"id" => id} = attrs) do
{user, _} = Guardian.Plug.current_resource(conn)

if user_has_elevated_privileges?(user) do
shift = Shifts.get_shift_with_timeslots(id)
timeslot_attrs = Map.get(attrs, "timeslots", [])
shift_attrs = Map.delete(attrs, "timeslots")

case Shifts.update_shift_with_timeslots(shift, shift_attrs, timeslot_attrs) do
{:ok, %{shift: updated_shift} = _results} ->
conn
|> render(:show, shift: updated_shift |> Repo.preload([:timeslots]))

{:error, _operation, changeset, _changeset} ->
conn
|> put_status(:unprocessable_entity)
|> put_view(json: AtlasWeb.ChangesetJSON)
|> render(:error, changeset: changeset)
end
else
conn
|> put_status(:forbidden)
|> json(%{error: "Unauthorized"})
end
end

defp user_has_elevated_privileges?(user) do
(user && user.type == :admin) || user.type == :professor
end
end
14 changes: 14 additions & 0 deletions lib/atlas_web/controllers/timeslots_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule AtlasWeb.TimeslotsController do
use AtlasWeb, :controller

alias Atlas.University.Degrees.Courses.Shifts.Timeslot
alias Atlas.University.Degrees.Courses.Timeslots

def delete(conn, %{"id" => id}) do
timeslot = Timeslots.get_timeslot!(id)

with {:ok, %Timeslot{}} <- Timeslots.delete_timeslot(timeslot) do
send_resp(conn, :no_content, "")
end
end
end
5 changes: 3 additions & 2 deletions lib/atlas_web/controllers/university/course_json.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule AtlasWeb.University.CourseJSON do
alias Atlas.University.Degrees.Courses.Course
alias AtlasWeb.University.{CourseJSON, ShiftJSON}
alias AtlasWeb.ShiftsJSON
alias AtlasWeb.University.CourseJSON

def index(%{courses: courses}) do
%{courses: for(course <- courses, do: data(course))}
Expand All @@ -22,7 +23,7 @@ defmodule AtlasWeb.University.CourseJSON do
end,
shifts:
if Ecto.assoc_loaded?(course.shifts) do
for(shift <- course.shifts, do: ShiftJSON.data(shift))
for(shift <- course.shifts, do: ShiftsJSON.data(shift))
else
[]
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
defmodule AtlasWeb.University.ShiftJSON do
defmodule AtlasWeb.ShiftsJSON do
alias Atlas.University.Degrees.Courses.Shifts.Shift
alias AtlasWeb.University.TimeslotJSON

def index(%{shifts: shifts}) do
%{data: for(shift <- shifts, do: data(shift))}
end

def show(%{shift: shift}) do
%{data: data(shift)}
end

def data(%Shift{} = shift) do
%{
id: shift.id,
number: shift.number,
type: shift.type,
professor: shift.professor,
timeslots: for(timeslot <- shift.timeslots, do: TimeslotJSON.data(timeslot)),
timeslots:
if Ecto.assoc_loaded?(shift.timeslots) do
for timeslot <- shift.timeslots, do: TimeslotJSON.data(timeslot)
else
[]
end,
enrollment_status:
if Ecto.assoc_loaded?(shift.enrollments) && shift.enrollments != [] do
hd(shift.enrollments).status
else
nil
end
}
end
Expand Down
9 changes: 9 additions & 0 deletions lib/atlas_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ defmodule AtlasWeb.Router do

get "/students", University.StudentsController, :index

scope "/shifts" do
get "/", ShiftsController, :index
put "/:id", ShiftsController, :update
end

scope "/timeslots" do
delete "/:id", TimeslotsController, :delete
end

scope "/jobs" do
get "/", JobController, :index
get "/:id", JobController, :show
Expand Down