diff --git a/lib/atlas/university/degrees/courses/shifts.ex b/lib/atlas/university/degrees/courses/shifts.ex index c7e2205..0d72428 100644 --- a/lib/atlas/university/degrees/courses/shifts.ex +++ b/lib/atlas/university/degrees/courses/shifts.ex @@ -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. @@ -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. @@ -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. @@ -208,4 +223,24 @@ 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)) + |> then(fn multi -> + timeslot_attrs + |> Enum.with_index() + |> Enum.reduce(multi, fn {timeslot_attr, index}, acc_multi -> + timeslot = get_timeslot!(timeslot_attr["id"]) + changeset = change_timeslot(timeslot, Map.delete(timeslot_attr, "id")) + + Multi.update(acc_multi, {:timeslot, index}, changeset) + end) + end) + |> Repo.transaction() + end end diff --git a/lib/atlas_web/controllers/exchanges/shift_exchange_request_json.ex b/lib/atlas_web/controllers/exchanges/shift_exchange_request_json.ex index ef0c8f4..7acdf4a 100644 --- a/lib/atlas_web/controllers/exchanges/shift_exchange_request_json.ex +++ b/lib/atlas_web/controllers/exchanges/shift_exchange_request_json.ex @@ -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. @@ -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 } diff --git a/lib/atlas_web/controllers/shifts/shifts_controller.ex b/lib/atlas_web/controllers/shifts/shifts_controller.ex new file mode 100644 index 0000000..249e5fd --- /dev/null +++ b/lib/atlas_web/controllers/shifts/shifts_controller.ex @@ -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 diff --git a/lib/atlas_web/controllers/university/course_json.ex b/lib/atlas_web/controllers/university/course_json.ex index fa7d66e..44db3d5 100644 --- a/lib/atlas_web/controllers/university/course_json.ex +++ b/lib/atlas_web/controllers/university/course_json.ex @@ -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))} @@ -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 diff --git a/lib/atlas_web/controllers/university/shift_json.ex b/lib/atlas_web/controllers/university/shifts_json.ex similarity index 50% rename from lib/atlas_web/controllers/university/shift_json.ex rename to lib/atlas_web/controllers/university/shifts_json.ex index 082e404..829b11e 100644 --- a/lib/atlas_web/controllers/university/shift_json.ex +++ b/lib/atlas_web/controllers/university/shifts_json.ex @@ -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 diff --git a/lib/atlas_web/router.ex b/lib/atlas_web/router.ex index a5309ef..0922e7b 100644 --- a/lib/atlas_web/router.ex +++ b/lib/atlas_web/router.ex @@ -93,6 +93,11 @@ defmodule AtlasWeb.Router do get "/students", University.StudentsController, :index + scope "/shifts" do + get "/", ShiftsController, :index + put "/:id", ShiftsController, :update + end + scope "/jobs" do get "/", JobController, :index get "/:id", JobController, :show