diff --git a/.formatter.exs b/.formatter.exs
index 7539791..061dc09 100644
--- a/.formatter.exs
+++ b/.formatter.exs
@@ -1,5 +1,5 @@
[
- line_length: 300,
+ line_length: 150,
import_deps: [:phoenix],
inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"]
]
diff --git a/lib/ksuite_middleware/ksuite_client.ex b/lib/ksuite_middleware/ksuite_client.ex
index 186dc96..db12c36 100644
--- a/lib/ksuite_middleware/ksuite_client.ex
+++ b/lib/ksuite_middleware/ksuite_client.ex
@@ -5,7 +5,7 @@ defmodule KsuiteMiddleware.KsuiteClient do
require Logger
- plug Tesla.Middleware.BaseUrl, "https://api.infomaniak.com"
+ plug Tesla.Middleware.BaseUrl, State.get_ksuite_api_server()
plug Tesla.Middleware.Logger, debug: false
plug Tesla.Middleware.PathParams
plug Tesla.Middleware.Headers, [{"User-Agent", "ksuite-middleware"}]
diff --git a/lib/ksuite_middleware/state.ex b/lib/ksuite_middleware/state.ex
index 11b78b6..f9aea8a 100644
--- a/lib/ksuite_middleware/state.ex
+++ b/lib/ksuite_middleware/state.ex
@@ -18,6 +18,9 @@ defmodule KsuiteMiddleware.State do
@spec get_timezone() :: Timex.TimezoneInfo.t()
def get_timezone(), do: GenServer.call(State, :get_timezone)
+ @spec get_ksuite_api_server() :: String.t()
+ def get_ksuite_api_server(), do: "https://api.infomaniak.com"
+
# Callbacks
@impl true
diff --git a/lib/ksuite_middleware_web/controllers/calendar_controller.ex b/lib/ksuite_middleware_web/controllers/calendar_controller.ex
index 4824444..b92a01b 100644
--- a/lib/ksuite_middleware_web/controllers/calendar_controller.ex
+++ b/lib/ksuite_middleware_web/controllers/calendar_controller.ex
@@ -7,6 +7,8 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
require Logger
+ action_fallback KsuiteMiddleware.FallbackController
+
def get_events(conn, %{"from" => from, "to" => to, "calendar_id" => calendar_id}),
do:
parse_params(from, to, calendar_id)
@@ -14,6 +16,13 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
|> then(&translate_to_events/1)
|> then(&send_response(conn, &1))
+ def get_events(conn, _),
+ do:
+ conn
+ |> put_status(:bad_request)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"400", reason: "The arguments were missing.")
+
# Private
defp read_events({:error, error, reason}), do: {:error, error, reason}
@@ -28,19 +37,28 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
client |> CalDAVClient.Event.get_events(calendar_url, from, to)
end
- defp send_response(conn, {:ok, events}), do: json(conn, events)
+ defp send_response(conn, {:ok, events}),
+ do: render(conn, :events, events: events)
- defp send_response(conn, {:error, error, reason}),
+ defp send_response(conn, {:error, :bad_request, reason}),
do:
conn
- |> put_status(error)
- |> json(%{reason: reason})
+ |> put_status(:bad_request)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"400", reason: reason)
+
+ defp send_response(conn, {:error, :not_found, reason}),
+ do:
+ conn
+ |> put_status(:not_found)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"404", reason: reason)
defp send_response(conn, {:error, reason}),
do:
conn
- |> put_status(500)
- |> json(%{reason: reason})
+ |> put_status(:internal_server_error)
+ |> render(:"500", reason: reason)
defp parse_params(from, to, calendar_id) do
Logger.info("Parsing the arguments ...")
@@ -50,9 +68,10 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
{:ok, calendar_id} <- parse_calendar_id(calendar_id) do
{:ok, from, to, calendar_id}
else
- :invalid_to -> {:error, :bad_request, "The argument 'to' was invalid."}
- :invalid_from -> {:error, :bad_request, "The argument 'from' was invalid."}
+ {:invalid_to, reason} -> {:error, :bad_request, "The argument 'to' was invalid. #{reason}"}
+ {:invalid_from, reason} -> {:error, :bad_request, "The argument 'from' was invalid. #{reason}"}
{:invalid_calendar_id, reason} -> {:error, :bad_request, reason}
+ _ -> {:error, :internal_server_error, "Unhandled error occured"}
end
end
@@ -60,18 +79,20 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
defp parse_calendar_id(_), do: {:invalid_calendar_id, "The calendar_id was too long."}
defp parse_datetime(error_atom, datetime) when is_atom(error_atom) and is_bitstring(datetime) do
- case Timex.parse!(datetime, "{ISO:Extended:Z}") do
- %DateTime{} = x -> {:ok, x}
- _ -> error_atom
+ case Timex.parse(datetime, "{ISO:Extended:Z}") do
+ {:ok, %DateTime{} = x} -> {:ok, x}
+ {:error, reason} -> {error_atom, reason}
end
end
- defp translate_to_events({:error, :unauthorized}), do: {:error, :unauthorized, "Unauthorized access to the CalDAV server, double check your credentials."}
+ defp translate_to_events({:error, :unauthorized}),
+ do: {:error, :unauthorized, "Unauthorized access to the CalDAV server, double check your credentials."}
+
defp translate_to_events({:error, :not_found}), do: {:error, :not_found, "The given calendar_id was not found in the given server CalDAV."}
defp translate_to_events({:error, reason}), do: {:error, reason}
defp translate_to_events({:error, error, reason}), do: {:error, error, reason}
defp translate_to_events({:ok, []}), do: {:ok, []}
- defp translate_to_events({:ok, icalendar_events}), do: translate_to_events(icalendar_events, [])
+ defp translate_to_events({:ok, [%CalDAVClient.Event{} | _] = icalendar_events}), do: translate_to_events(icalendar_events, [])
defp translate_to_events([], acc) when is_list(acc), do: {:ok, acc}
defp translate_to_events([head | tail], acc) when is_list(acc) do
@@ -83,7 +104,12 @@ defmodule KsuiteMiddlewareWeb.CalendarController do
from = translate_date_to_utc(from)
to = translate_date_to_utc(to)
- new_event = %KsuiteCalendarEvent{subject: summary, from: Timex.format!(from, "{ISO:Extended:Z}"), to: Timex.format!(to, "{ISO:Extended:Z}"), description: description}
+ new_event = %KsuiteCalendarEvent{
+ subject: summary,
+ from: Timex.format!(from, "{ISO:Extended:Z}"),
+ to: Timex.format!(to, "{ISO:Extended:Z}"),
+ description: description
+ }
translate_to_events(tail, [new_event | acc])
end
diff --git a/lib/ksuite_middleware_web/controllers/calendar_json.ex b/lib/ksuite_middleware_web/controllers/calendar_json.ex
new file mode 100644
index 0000000..3f27c56
--- /dev/null
+++ b/lib/ksuite_middleware_web/controllers/calendar_json.ex
@@ -0,0 +1,25 @@
+defmodule KsuiteMiddlewareWeb.CalendarJSON do
+ alias KsuiteMiddlewareWeb.Models.KsuiteCalendarEvent
+
+ def events(%{events: [%KsuiteCalendarEvent{} | _] = events}), do: events
+
+ def render("400.json", %{reason: reason}),
+ do: %{title: "invalid argument", status: 400, detail: reason}
+
+ def render("404.json", %{reason: reason}),
+ do: %{
+ title: "not found",
+ status: 404,
+ detail: reason,
+ description:
+ "Oh snap! It seems we've hit a hiccup in our treasure hunt—what you seek is playing hide and seek in the " <>
+ "digital jungle! Keep those eagle eyes peeled, and perhaps try a different map or a clever keyword dance " <>
+ "to coax the elusive information out of hiding."
+ }
+
+ def render("500.json", %{reason: reason}),
+ do: %{title: "internal server error", status: 500, detail: reason}
+
+ def render(template, _assigns),
+ do: %{detail: Phoenix.Controller.status_message_from_template(template)}
+end
diff --git a/lib/ksuite_middleware_web/controllers/error_controller.ex b/lib/ksuite_middleware_web/controllers/error_controller.ex
deleted file mode 100644
index 1379a83..0000000
--- a/lib/ksuite_middleware_web/controllers/error_controller.ex
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule KsuiteMiddlewareWeb.ErrorController do
- use KsuiteMiddlewareWeb, :controller
-
- def not_found(conn, _params),
- do:
- conn
- |> put_resp_header("content-type", "text/html; charset=utf-8")
- |> send_file(404, Application.app_dir(:ksuite_middleware, "priv/static/not-found.html"))
-end
diff --git a/lib/ksuite_middleware_web/controllers/error_json.ex b/lib/ksuite_middleware_web/controllers/error_json.ex
index 718bb1e..33443de 100644
--- a/lib/ksuite_middleware_web/controllers/error_json.ex
+++ b/lib/ksuite_middleware_web/controllers/error_json.ex
@@ -6,6 +6,17 @@ defmodule KsuiteMiddlewareWeb.ErrorJSON do
# %{errors: %{detail: "Internal Server Error"}}
# end
+ def render("404.json", _),
+ do: %{
+ title: "not found",
+ status: 404,
+ detail: "The resource requested was not found.",
+ description:
+ "Oh snap! It seems we've hit a hiccup in our treasure hunt—what you seek is playing hide and seek in the " <>
+ "digital jungle! Keep those eagle eyes peeled, and perhaps try a different map or a clever keyword dance " <>
+ "to coax the elusive information out of hiding."
+ }
+
# By default, Phoenix returns the status message from
# the template name. For example, "404.json" becomes
# "Not Found".
diff --git a/lib/ksuite_middleware_web/controllers/fallback_controller.ex b/lib/ksuite_middleware_web/controllers/fallback_controller.ex
new file mode 100644
index 0000000..984e82f
--- /dev/null
+++ b/lib/ksuite_middleware_web/controllers/fallback_controller.ex
@@ -0,0 +1,16 @@
+defmodule KsuiteMiddlewareWeb.FallbackController do
+ @moduledoc """
+ Translates controller action results into valid `Plug.Conn` responses.
+
+ See `Phoenix.Controller.action_fallback/1` for more details.
+ """
+ use KsuiteMiddlewareWeb, :controller
+
+ # This clause is an example of how to handle resources that cannot be found.
+ def call(conn, {:error, :not_found}) do
+ conn
+ |> put_status(:not_found)
+ |> put_view(json: KsuiteMiddlewareWeb.ErrorJSON)
+ |> render(:"404")
+ end
+end
diff --git a/lib/ksuite_middleware_web/controllers/kdrive_controller.ex b/lib/ksuite_middleware_web/controllers/kdrive_controller.ex
index 895e66e..267b598 100644
--- a/lib/ksuite_middleware_web/controllers/kdrive_controller.ex
+++ b/lib/ksuite_middleware_web/controllers/kdrive_controller.ex
@@ -3,11 +3,16 @@ defmodule KsuiteMiddlewareWeb.KdriveController do
alias KsuiteMiddleware.KsuiteClient
+ action_fallback KsuiteMiddleware.FallbackController
+
def pass_thru(conn, %{"file_id" => id}) when is_integer(id) do
with {:ok, response} <- KsuiteClient.download(id) do
conn |> put_tesla_response(response)
else
- _ -> conn |> resp(500, "an unknown error occurred.")
+ _ ->
+ conn
+ |> put_status(:bad_gateway)
+ |> render(:"500")
end
end
@@ -16,21 +21,41 @@ defmodule KsuiteMiddlewareWeb.KdriveController do
{:ok, response} <- KsuiteClient.download(file_id) do
conn |> put_tesla_response(response)
else
+ :error ->
+ conn
+ |> put_status(:bad_request)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"400", reason: :invalid_integer)
+
+ {:error, _} ->
+ conn
+ |> put_status(:bad_gateway)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"502", reason: :invalid_response_from_api)
+
_ ->
- conn |> resp(500, "an unknown error occurred.")
+ conn
+ |> put_status(:internal_server_error)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"500", reason: :unknown)
end
end
def pass_thru(conn, _params),
- do: conn |> resp(400, "The file id was missing.")
+ do:
+ conn
+ |> put_status(:bad_request)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"400", reason: :missing_file_id)
# Private
defp put_tesla_response(%Plug.Conn{} = conn, %Tesla.Env{status: 401}),
do:
conn
- |> put_resp_header("content-type", "text/html; charset=utf-8")
- |> send_file(400, Application.app_dir(:ksuite_middleware, "priv/static/bad-api-key.html"))
+ |> put_status(:bad_request)
+ |> put_resp_content_type("application/problem+json")
+ |> render(:"400", reason: :bad_api_key)
defp put_tesla_response(%Plug.Conn{} = conn, %Tesla.Env{} = response) do
%Tesla.Env{status: status, body: body} = response
@@ -42,7 +67,8 @@ defmodule KsuiteMiddlewareWeb.KdriveController do
else
_ ->
conn
- |> resp(status, body)
+ |> put_status(status)
+ |> render(status |> Integer.to_string() |> String.to_atom())
end
end
diff --git a/lib/ksuite_middleware_web/controllers/kdrive_json.ex b/lib/ksuite_middleware_web/controllers/kdrive_json.ex
new file mode 100644
index 0000000..d5f53d9
--- /dev/null
+++ b/lib/ksuite_middleware_web/controllers/kdrive_json.ex
@@ -0,0 +1,29 @@
+defmodule KsuiteMiddlewareWeb.KdriveJSON do
+ alias KsuiteMiddleware.State
+
+ def render("400.json", %{reason: :invalid_integer}),
+ do: %{title: "invalid argument", status: 400, detail: "The given file_id was invalid."}
+
+ def render("400.json", %{reason: :missing_file_id}),
+ do: %{title: "missing argument", status: 400, detail: "The file_id was missing."}
+
+ def render("400.json", %{reason: :bad_api_key}),
+ do: %{
+ title: "bad api key",
+ status: 400,
+ detail: "The API key is invalid, please verify the 'KSUITE_API_TOKEN'.",
+ description:
+ "Whoopsie-daisy! Looks like we got a little lost in API land. Our secret handshake seems a bit off. " <>
+ "Double-check that magic spell in the enchanted scroll labeled `KSUITE_API_TOKEN` and make sure it's been " <>
+ "properly whispered into the winds of the environment variable realm."
+ }
+
+ def render("502.json", %{reason: :invalid_response_from_api}),
+ do: %{title: "bad gateway", status: 502, detail: "The upstream api returned an invalid response.", server: State.get_ksuite_api_server()}
+
+ def render("500.json", %{reason: :unknown}),
+ do: %{title: "internal server error", status: 500, detail: "An unhandled error was returned, please contact the administrator."}
+
+ def render(template, _assigns),
+ do: %{detail: Phoenix.Controller.status_message_from_template(template)}
+end
diff --git a/lib/ksuite_middleware_web/router.ex b/lib/ksuite_middleware_web/router.ex
index 7af385b..6d60349 100644
--- a/lib/ksuite_middleware_web/router.ex
+++ b/lib/ksuite_middleware_web/router.ex
@@ -43,10 +43,4 @@ defmodule KsuiteMiddlewareWeb.Router do
live_dashboard "/dashboard", metrics: KsuiteMiddlewareWeb.Telemetry
end
end
-
- scope "/", KsuiteMiddlewareWeb do
- pipe_through :browser
-
- get "/*path", ErrorController, :not_found
- end
end
diff --git a/priv/static/bad-api-key.html b/priv/static/bad-api-key.html
deleted file mode 100644
index 4d3a76a..0000000
--- a/priv/static/bad-api-key.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
- Ksuite Middleware - 400
-
-
-
-
-
- Ksuite Middleware - 400
-
-
- Whoopsie-daisy! Looks like we got a little lost in API land. Our secret handshake seems a bit off.
- Double-check that magic spell in the enchanted scroll labeled `KSUITE_API_TOKEN` and make sure it's been
- properly whispered into the winds of the environment variable realm.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/priv/static/not-found.html b/priv/static/not-found.html
deleted file mode 100644
index a6c43a4..0000000
--- a/priv/static/not-found.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
- Ksuite Middleware - 404
-
-
-
-
-
- Ksuite Middleware - 404
-
-
- Oh snap! It seems we've hit a hiccup in our treasure hunt—what you seek is playing hide and seek in the
- digital jungle! Keep those eagle eyes peeled, and perhaps try a different map or a clever keyword dance
- to coax the elusive information out of hiding.
-
-
-
-
-
-
\ No newline at end of file