From 7597a37d0e7741f55dbd40ff8409c1ba1f401437 Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 27 May 2024 17:13:14 +0200 Subject: [PATCH] Add PATCH/POST endpoints for updating contact data --- CHANGELOG.md | 4 ++ .../api/controllers/api_contact_controller.ex | 51 +++++++++++++++++++ lib/keila_web/api/schemas/contact.ex | 15 ++++++ lib/keila_web/router.ex | 2 + .../api/api_contact_controller_test.exs | 20 ++++++++ 5 files changed, 92 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a789f582..88dabd53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## Added +- Added PATCH and POST API endpoints for updating just the data field of a + contact + ## Fixed - Liquid tags are now correctly rendered in layout blocks in the Block Editor diff --git a/lib/keila_web/api/controllers/api_contact_controller.ex b/lib/keila_web/api/controllers/api_contact_controller.ex index bbe0b03d..2d422ed9 100644 --- a/lib/keila_web/api/controllers/api_contact_controller.ex +++ b/lib/keila_web/api/controllers/api_contact_controller.ex @@ -116,6 +116,57 @@ defmodule KeilaWeb.ApiContactController do end end + operation(:update_data, + summary: "Update Contact data", + description: + "Update just the `data` field of a Contact. The existing JSON object is merged in a shallow merge with the provided data object.", + parameters: [id: [in: :path, type: :string, description: "Contact ID"]], + request_body: {"Contact data params", "application/json", Schemas.Contact.DataParams}, + responses: [ + ok: {"Contact response", "application/json", Schemas.Contact.Response} + ] + ) + + @spec update_data(Plug.Conn.t(), map()) :: Plug.Conn.t() + def update_data(conn, %{id: id}) do + contact = Contacts.get_project_contact(project_id(conn), id) + + if contact do + params = %{data: Map.merge(contact.data || %{}, conn.body_params.data)} + + case Contacts.update_contact(id, params) do + {:ok, contact} -> render(conn, "contact.json", %{contact: contact}) + {:error, changeset} -> Errors.send_changeset_error(conn, changeset) + end + else + Errors.send_404(conn) + end + end + + operation(:replace_data, + summary: "Replace Contact data", + description: "Replace just the `data` field of a Contact with the provided data object.", + parameters: [id: [in: :path, type: :string, description: "Contact ID"]], + request_body: {"Contact data params", "application/json", Schemas.Contact.DataParams}, + responses: [ + ok: {"Contact response", "application/json", Schemas.Contact.Response} + ] + ) + + @spec replace_data(Plug.Conn.t(), map()) :: Plug.Conn.t() + def replace_data(conn, %{id: id}) do + if Contacts.get_project_contact(project_id(conn), id) do + params = %{data: conn.body_params.data} + + case Contacts.update_contact(id, params) do + {:ok, contact} -> render(conn, "contact.json", %{contact: contact}) + {:error, changeset} -> Errors.send_changeset_error(conn, changeset) + end + else + Errors.send_404(conn) + end + end + operation(:delete, summary: "Delete Contact", parameters: [id: [in: :path, type: :string, description: "Contact ID"]], diff --git a/lib/keila_web/api/schemas/contact.ex b/lib/keila_web/api/schemas/contact.ex index dd82c2b6..622a7bd2 100644 --- a/lib/keila_web/api/schemas/contact.ex +++ b/lib/keila_web/api/schemas/contact.ex @@ -68,3 +68,18 @@ defmodule KeilaWeb.Api.Schemas.Contact.Params do @allowed_properties [:email, :first_name, :last_name, :data, :status] build_open_api_schema(@properties, only: @allowed_properties) end + +defmodule KeilaWeb.Api.Schemas.Contact.DataParams do + require OpenApiSpex + + %OpenApiSpex.Schema{ + type: :object, + properties: %{ + data: %OpenApiSpex.Schema{ + type: :object, + example: %{"tags" => ["rocket-scientist"]} + } + } + } + |> OpenApiSpex.schema() +end diff --git a/lib/keila_web/router.ex b/lib/keila_web/router.ex index 6c282778..c5e056ac 100644 --- a/lib/keila_web/router.ex +++ b/lib/keila_web/router.ex @@ -192,6 +192,8 @@ defmodule KeilaWeb.Router do pipe_through [:api, :open_api] resources "/contacts", ApiContactController, only: [:index, :show, :create, :update, :delete] + patch "/contacts/:id/data", ApiContactController, :update_data + post "/contacts/:id/data", ApiContactController, :replace_data resources "/campaigns", ApiCampaignController, only: [:index, :show, :create, :update, :delete] diff --git a/test/keila_web/api/api_contact_controller_test.exs b/test/keila_web/api/api_contact_controller_test.exs index 27381a37..0768c217 100644 --- a/test/keila_web/api/api_contact_controller_test.exs +++ b/test/keila_web/api/api_contact_controller_test.exs @@ -204,6 +204,26 @@ defmodule KeilaWeb.ApiContactControllerTest do end end + describe "PATCH /api/v1/contacts/:id/data" do + @tag :api_contact_controller + test "updates contact data", %{authorized_conn: conn, project: project} do + contact = insert!(:contact, project_id: project.id, data: %{"foo" => "bar"}) + body = %{"data" => %{"fizz" => "buzz"}} + conn = patch_json(conn, Routes.api_contact_path(conn, :update_data, contact.id), body) + assert %{"foo" => "bar", "fizz" => "buzz"} == json_response(conn, 200)["data"]["data"] + end + end + + describe "POST /api/v1/contacts/:id/data" do + @tag :api_contact_controller + test "replaces contact data", %{authorized_conn: conn, project: project} do + contact = insert!(:contact, project_id: project.id, data: %{"foo" => "bar"}) + body = %{"data" => %{"fizz" => "buzz"}} + conn = post_json(conn, Routes.api_contact_path(conn, :update_data, contact.id), body) + assert %{"fizz" => "buzz"} == json_response(conn, 200)["data"]["data"] + end + end + describe "DELETE /api/v1/contacts/:id" do @tag :api_contact_controller test "always returns 204", %{authorized_conn: conn, project: project} do