diff --git a/lib/msg/calendar/events.ex b/lib/msg/calendar/events.ex index 0161771..b210781 100644 --- a/lib/msg/calendar/events.ex +++ b/lib/msg/calendar/events.ex @@ -148,7 +148,8 @@ defmodule Msg.Calendar.Events do @spec get(Req.Request.t(), String.t(), keyword()) :: {:ok, map()} | {:error, term()} def get(client, event_id, opts) do base_path = build_base_path(opts) - path = "#{base_path}/#{event_id}" + encoded_event_id = URI.encode(event_id, &URI.char_unreserved?/1) + path = "#{base_path}/#{encoded_event_id}" query_params = [] @@ -273,7 +274,8 @@ defmodule Msg.Calendar.Events do {:ok, map()} | {:error, term()} def update(client, event_id, updates, opts) do base_path = build_base_path(opts) - path = "#{base_path}/#{event_id}" + encoded_event_id = URI.encode(event_id, &URI.char_unreserved?/1) + path = "#{base_path}/#{encoded_event_id}" updates_converted = Request.convert_keys(updates) case Req.patch(client, url: path, json: updates_converted) do @@ -315,7 +317,8 @@ defmodule Msg.Calendar.Events do @spec delete(Req.Request.t(), String.t(), keyword()) :: :ok | {:error, term()} def delete(client, event_id, opts) do base_path = build_base_path(opts) - path = "#{base_path}/#{event_id}" + encoded_event_id = URI.encode(event_id, &URI.char_unreserved?/1) + path = "#{base_path}/#{encoded_event_id}" case Req.delete(client, url: path) do {:ok, %{status: 204}} -> @@ -431,12 +434,25 @@ defmodule Msg.Calendar.Events do {:ok, map()} | {:error, term()} def get_with_extensions(client, event_id, extension_id, opts) do base_path = build_base_path(opts) - resource_path = "#{base_path}/#{event_id}" + encoded_event_id = URI.encode(event_id, &URI.char_unreserved?/1) + resource_path = "#{base_path}/#{encoded_event_id}" - # Get event and specific extension - with {:ok, event} <- get(client, event_id, opts), - {:ok, extension} <- Request.get(client, "#{resource_path}/extensions/#{extension_id}") do - {:ok, Map.put(event, "extensions", [extension])} + # Get event first + # Note: get/3 already encodes event_id, so we pass the original + with {:ok, event} <- get(client, event_id, opts) do + # Try to get the extension, but return event without it if not found + case Request.get(client, "#{resource_path}/extensions/#{extension_id}") do + {:ok, extension} -> + {:ok, Map.put(event, "extensions", [extension])} + + {:error, %{status: 404}} -> + # Extension not found, return event without extensions + {:ok, Map.put(event, "extensions", [])} + + {:error, reason} -> + # Other errors should still propagate + {:error, reason} + end end end diff --git a/test/msg/calendar/events_test.exs b/test/msg/calendar/events_test.exs index 5ea9bf1..a18d581 100644 --- a/test/msg/calendar/events_test.exs +++ b/test/msg/calendar/events_test.exs @@ -70,6 +70,17 @@ defmodule Msg.Calendar.EventsTest do opts = [user_id: "test@example.com", select: ["subject", "start", "end"]] assert Keyword.get(opts, :select) == ["subject", "start", "end"] end + + test "encodes event IDs with special characters" do + # Test that event IDs with special characters are properly URL encoded + # This verifies the URI.encode logic added in lib/msg/calendar/events.ex:151 + event_id = "AAMkAGI2T-event+with/special=chars" + encoded = URI.encode(event_id, &URI.char_unreserved?/1) + + # Verify encoding happens correctly + assert encoded == "AAMkAGI2T-event%2Bwith%2Fspecial%3Dchars" + refute encoded == event_id + end end describe "create/3" do @@ -117,6 +128,17 @@ defmodule Msg.Calendar.EventsTest do assert is_map(updates) assert Map.has_key?(updates, :subject) end + + test "encodes event IDs with special characters" do + # Test that event IDs with special characters are properly URL encoded + # This verifies the URI.encode logic added in lib/msg/calendar/events.ex:277 + event_id = "event-id+with/special=chars" + encoded = URI.encode(event_id, &URI.char_unreserved?/1) + + # Verify encoding happens correctly + assert encoded == "event-id%2Bwith%2Fspecial%3Dchars" + refute encoded == event_id + end end describe "delete/3" do @@ -127,6 +149,17 @@ defmodule Msg.Calendar.EventsTest do Events.delete(client, "event-id", []) end end + + test "encodes event IDs with special characters" do + # Test that event IDs with special characters are properly URL encoded + # This verifies the URI.encode logic added in lib/msg/calendar/events.ex:320 + event_id = "delete-event+with/special=chars" + encoded = URI.encode(event_id, &URI.char_unreserved?/1) + + # Verify encoding happens correctly + assert encoded == "delete-event%2Bwith%2Fspecial%3Dchars" + refute encoded == event_id + end end describe "create_with_extension/4" do @@ -161,5 +194,16 @@ defmodule Msg.Calendar.EventsTest do Events.get_with_extensions(client, "event-id", "com.example.test", []) end end + + test "encodes event IDs with special characters" do + # Test that event IDs with special characters are properly URL encoded + # This verifies the URI.encode logic added in lib/msg/calendar/events.ex:437 + event_id = "ext-event+with/special=chars" + encoded = URI.encode(event_id, &URI.char_unreserved?/1) + + # Verify encoding happens correctly + assert encoded == "ext-event%2Bwith%2Fspecial%3Dchars" + refute encoded == event_id + end end end