diff --git a/lib/skate/detours/detours.ex b/lib/skate/detours/detours.ex index 159527859..1c18893d9 100644 --- a/lib/skate/detours/detours.ex +++ b/lib/skate/detours/detours.ex @@ -193,36 +193,33 @@ defmodule Skate.Detours.Detours do end @doc """ - Update or create a detour given a user id & detour id. + Update or insert a detour given a user id and a XState Snapshot. """ - def update_or_create_detour_for_user(user_id, uuid, attrs \\ %{}) do - user = User.get_by_id!(user_id) - - previous_record = uuid != nil && Skate.Repo.get(Detour, uuid) - - detour = - case uuid do - nil -> - create_detour_for_user(user_id, attrs) - - _ -> - Repo.insert( - Detour.changeset(%Detour{author: user, id: uuid}, attrs), - returning: true, - conflict_target: [:id], - on_conflict: {:replace, [:state, :updated_at]} - ) + def upsert_from_snapshot(author_id, %{} = snapshot) do + previous_record = + case Skate.Detours.SnapshotSerde.id_from_snapshot(snapshot) do + nil -> nil + id -> Skate.Repo.get(Detour, id) end - case detour do + detour_db_result = + author_id + |> Skate.Detours.SnapshotSerde.deserialize(snapshot) + |> Skate.Repo.insert( + returning: true, + conflict_target: [:id], + on_conflict: {:replace, [:state, :updated_at]} + ) + + case detour_db_result do {:ok, %Detour{} = new_record} -> - send_notification(new_record, previous_record, user_id) + send_notification(new_record, previous_record, author_id) _ -> nil end - detour + detour_db_result end @doc """ diff --git a/lib/skate/detours/snapshot_serde.ex b/lib/skate/detours/snapshot_serde.ex index 95ff55ae4..cbf61fd88 100644 --- a/lib/skate/detours/snapshot_serde.ex +++ b/lib/skate/detours/snapshot_serde.ex @@ -3,4 +3,28 @@ defmodule Skate.Detours.SnapshotSerde do Deserializes XState JSON Snapshots to Ecto Database Changesets Serializes Ecto Database Structs into XState JSON Snapshots """ + + @doc """ + Converts a XState JSON Snapshot to Detours Database Changeset + """ + def deserialize(user_id, %{} = snapshot) do + Skate.Detours.Db.Detour.changeset( + %Skate.Detours.Db.Detour{ + # `id` is `nil` by default, so a `nil` `id` should be fine + id: id_from_snapshot(snapshot), + author_id: user_id + }, + %{ + # Save Snapshot to DB until we've fully transitioned to serializing + # snapshots from DB data + state: snapshot + } + ) + end + + @doc """ + Extracts the Detour ID from a XState Snapshot + """ + def id_from_snapshot(%{"context" => %{"uuid" => id}}), do: id + def id_from_snapshot(%{"context" => %{}}), do: nil end diff --git a/lib/skate_web/controllers/detours_controller.ex b/lib/skate_web/controllers/detours_controller.ex index 2ee170fb6..76b06ddcd 100644 --- a/lib/skate_web/controllers/detours_controller.ex +++ b/lib/skate_web/controllers/detours_controller.ex @@ -11,15 +11,11 @@ defmodule SkateWeb.DetoursController do alias Util.Location @spec update_snapshot(Plug.Conn.t(), map()) :: Plug.Conn.t() - def update_snapshot(conn, %{"snapshot" => %{"context" => context} = snapshot}) do - uuid = Map.get(context, "uuid") - + def update_snapshot(conn, %{"snapshot" => snapshot}) do %{id: user_id} = AuthManager.Plug.current_resource(conn) {:ok, %Skate.Detours.Db.Detour{id: returned_uuid}} = - Detours.update_or_create_detour_for_user(user_id, uuid, %{ - state: snapshot - }) + Detours.upsert_from_snapshot(user_id, snapshot) json(conn, %{data: returned_uuid}) end diff --git a/test/skate_web/controllers/detours_controller_test.exs b/test/skate_web/controllers/detours_controller_test.exs index 8437dcab2..cd5ad1a86 100644 --- a/test/skate_web/controllers/detours_controller_test.exs +++ b/test/skate_web/controllers/detours_controller_test.exs @@ -280,23 +280,21 @@ defmodule SkateWeb.DetoursControllerTest do other_user = Skate.Settings.User.get_by_email("other_user@gmail.com") # Manually insert a detour by another user - Detours.update_or_create_detour_for_user(other_user.id, 10, %{ - state: %{ - "context" => %{ - "route" => %{ - "name" => "23", - "directionNames" => %{ - "0" => "Outbound", - "1" => "Inbound" - } - }, - "routePattern" => %{ - "headsign" => "Headsign", - "directionId" => 0 - }, - "nearestIntersection" => "Street A & Avenue B", - "uuid" => 10 - } + Detours.upsert_from_snapshot(other_user.id, %{ + "context" => %{ + "route" => %{ + "name" => "23", + "directionNames" => %{ + "0" => "Outbound", + "1" => "Inbound" + } + }, + "routePattern" => %{ + "headsign" => "Headsign", + "directionId" => 0 + }, + "nearestIntersection" => "Street A & Avenue B", + "uuid" => 10 } })