From 6fe898355e76fe459a1f27261d1b0aa8855d373a Mon Sep 17 00:00:00 2001 From: Kanishka Naik <39029787+iamkanishka@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:56:14 +0530 Subject: [PATCH] refactor: "Refactor Appwrite services: Accounts, Avatars, and Storage; remove Client dependency, update function signatures, and modify API calls." --- lib/appwrite/services/accounts.ex | 1 + lib/appwrite/services/avatars.ex | 225 +++++++++++++++--------------- lib/appwrite/services/storage.ex | 7 +- 3 files changed, 116 insertions(+), 117 deletions(-) diff --git a/lib/appwrite/services/accounts.ex b/lib/appwrite/services/accounts.ex index 157f84e..9f12efa 100644 --- a/lib/appwrite/services/accounts.ex +++ b/lib/appwrite/services/accounts.ex @@ -950,6 +950,7 @@ defmodule Appwrite.Services.Accounts do end ) + query_string = URI.encode_query(Client.flatten(params)) {to_string(url) <> "?" <> query_string} diff --git a/lib/appwrite/services/avatars.ex b/lib/appwrite/services/avatars.ex index b9933c4..4c9ce5c 100644 --- a/lib/appwrite/services/avatars.ex +++ b/lib/appwrite/services/avatars.ex @@ -7,11 +7,9 @@ defmodule Appwrite.Services.Avatars do All endpoints in this service allow you to resize, crop, and change the output image quality for maximum performance and visibility in your app. - - Status: In Testing """ - alias Appwrite.Types.Client + alias Appwrite.Utils.Client alias Appwrite.Exceptions.AppwriteException alias Appwrite.Utils.Service @@ -22,7 +20,6 @@ defmodule Appwrite.Services.Avatars do ## Parameters - - `client` (`Client.t`): The Appwrite client instance. - `code` (`String.t`): The browser code. - `width` (`integer`): The width of the icon. - `height` (`integer`): The height of the icon. @@ -37,23 +34,28 @@ defmodule Appwrite.Services.Avatars do - `AppwriteException` if any required parameter is missing. """ - @spec get_browser(Client.t(), String.t(), integer() | nil, integer() | nil, integer() | nil) :: String.t() - def get_browser(client, code, width \\ nil, height \\ nil, quality \\ nil) do - validate_params(%{client: client, code: code}) + @spec get_browser(String.t(), integer() | nil, integer() | nil, integer() | nil) :: + String.t() + def get_browser(code, width \\ nil, height \\ nil, quality \\ nil) do + if is_nil(code) do + {:error, %AppwriteException{message: "Missing required parameters: code"}} + else + api_path = "/v1/avatars/browsers/#{code}" - api_path = "/avatars/browsers/#{code}" - uri = URI.merge(client.config.endpoint, api_path) + payload = + %{ + "quality" => quality, + "width" => width, + "height" => height, + "project" => Client.default_config()["project"] + } + |> Enum.reject(fn {_, v} -> v == nil end) - payload = - %{} - |> maybe_put("width", width) - |> maybe_put("height", height) - |> maybe_put("quality", quality) - |> Map.put("project", client.config.project) - |> Service.flatten() - - uri = build_query_params(uri, payload) - Client.call(client, :get, uri) + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} + end end @doc """ @@ -63,7 +65,6 @@ defmodule Appwrite.Services.Avatars do ## Parameters - - `client` (`Client.t`): The Appwrite client instance. - `code` (`String.t`): The credit card code. - `width` (`integer`): The width of the icon. - `height` (`integer`): The height of the icon. @@ -78,47 +79,30 @@ defmodule Appwrite.Services.Avatars do - `AppwriteException` if any required parameter is missing. """ - @spec get_credit_card(Client.t(), String.t(), integer() | nil, integer() | nil, integer() | nil) :: String.t() - def get_credit_card(client, code, width \\ nil, height \\ nil, quality \\ nil) do - validate_params(%{client: client, code: code}) + @spec get_credit_card(String.t(), integer() | nil, integer() | nil, integer() | nil) :: + String.t() + def get_credit_card(code, width \\ nil, height \\ nil, quality \\ nil) do + if is_nil(code) do + {:error, %AppwriteException{message: "Missing required parameters: code"}} + else + api_path = "/v1/avatars/credit-cards/#{code}" - api_path = "/avatars/credit-cards/#{code}" - uri = URI.merge(client.config.endpoint, api_path) + payload = + %{ + "quality" => quality, + "width" => width, + "height" => height, + "project" => Client.default_config()["project"] + } + |> Enum.reject(fn {_, v} -> v == nil end) - payload = - %{} - |> maybe_put("width", width) - |> maybe_put("height", height) - |> maybe_put("quality", quality) - |> Map.put("project", client.config.project) - |> Service.flatten() - - uri = build_query_params(uri, payload) - Client.call(client, :get, uri) - end + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) - # Helper function to validate parameters - @spec validate_params(map()) :: :ok | no_return() - defp validate_params(params) do - Enum.each(params, fn {key, value} -> - if is_nil(value) do - raise AppwriteException, "Missing required parameter: #{inspect(key)}" - end - end) - end - - # Helper function to build query params - @spec build_query_params(URI.t(), map()) :: URI.t() - defp build_query_params(uri, payload) do - Enum.reduce(payload, uri, fn {key, value}, acc -> - query = URI.decode_query(acc.query || "") |> Map.put(key, to_string(value)) - %{acc | query: URI.encode_query(query)} - end) + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} + end end - - - @doc """ Fetches the favicon of a given URL. @@ -131,25 +115,28 @@ defmodule Appwrite.Services.Avatars do ## Raises - `AppwriteException` if the `url` is nil. """ - @spec get_favicon(Client.t(), String.t()) :: String.t() - def get_favicon(client, url) when is_binary(url) do - api_path = "/avatars/favicon" - payload = %{"url" => url, "project" => client.config.project} + @spec get_favicon(String.t()) :: String.t() + def get_favicon(url) when is_binary(url) do + api_path = "/v1/avatars/favicon" - with {:ok, uri} <- prepare_uri(client.config.endpoint, api_path, payload) do - Client.call(client, uri) - else - {:error, reason} -> raise AppwriteException, message: reason - end + payload = %{ + "url" => url, + "project" => Client.default_config()["project"] + } + + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} end - def get_favicon(_client, nil), do: raise AppwriteException, message: "Missing required parameter: 'url'" + def get_favicon(_client, nil), + do: raise(AppwriteException, message: "Missing required parameter: 'url'") @doc """ Fetches a country flag icon by its ISO 3166-1 code. ## Parameters - - `client` (Client.t): The client instance. - `code` (string): ISO 3166-1 2-letter country code. - `width` (optional, integer): The width of the flag icon. - `height` (optional, integer): The height of the flag icon. @@ -161,27 +148,27 @@ defmodule Appwrite.Services.Avatars do ## Raises - `AppwriteException` if the `code` is nil. """ - @spec get_flag(Client.t(), String.t(), integer(), integer(), integer()) :: String.t() - def get_flag(client, code, width \\ nil, height \\ nil, quality \\ nil) when is_binary(code) do - api_path = "/avatars/flags/#{code}" + @spec get_flag(String.t(), integer(), integer(), integer()) :: String.t() + def get_flag(code, width \\ nil, height \\ nil, quality \\ nil) when is_binary(code) do + api_path = "/v1/avatars/flags/#{code}" + payload = %{ + "quality" => quality, "width" => width, "height" => height, - "quality" => quality, - "project" => client.config.project + "project" => Client.default_config()["project"] } |> Enum.reject(fn {_, v} -> v == nil end) - with {:ok, uri} <- prepare_uri(client.config.endpoint, api_path, payload) do - Client.call(client, uri) - else - {:error, reason} -> raise AppwriteException, message: reason - end + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} end def get_flag(_client, nil, _width, _height, _quality), - do: raise AppwriteException, message: "Missing required parameter: 'code'" + do: raise(AppwriteException, message: "Missing required parameter: 'code'") @doc """ Fetches and optionally crops a remote image by URL. @@ -198,33 +185,32 @@ defmodule Appwrite.Services.Avatars do ## Raises - `AppwriteException` if the `url` is nil. """ - @spec get_image(Client.t(), String.t(), integer(), integer()) :: String.t() - def get_image(client, url, width \\ nil, height \\ nil) when is_binary(url) do - api_path = "/avatars/image" + @spec get_image(String.t(), integer(), integer()) :: String.t() + def get_image(url, width \\ nil, height \\ nil) when is_binary(url) do + api_path = "/v1/avatars/image" + payload = %{ "url" => url, "width" => width, "height" => height, - "project" => client.config.project + "project" => Client.default_config()["project"] } |> Enum.reject(fn {_, v} -> v == nil end) - with {:ok, uri} <- prepare_uri(client.config.endpoint, api_path, payload) do - Client.call(client, uri) - else - {:error, reason} -> raise AppwriteException, message: reason - end + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} end def get_image(_client, nil, _width, _height), - do: raise AppwriteException, message: "Missing required parameter: 'url'" + do: raise(AppwriteException, message: "Missing required parameter: 'url'") @doc """ Generates a user initials avatar. ## Parameters - - `client` (Client.t): The client instance. - `name` (optional, string): The name or initials of the user. - `width` (optional, integer): The width of the avatar. - `height` (optional, integer): The height of the avatar. @@ -233,31 +219,30 @@ defmodule Appwrite.Services.Avatars do ## Returns - `String.t`: The URI for fetching the initials avatar. """ - @spec get_initials(Client.t(), String.t(), integer(), integer(), String.t()) :: String.t() - def get_initials(client, name \\ nil, width \\ nil, height \\ nil, background \\ nil) do - api_path = "/avatars/initials" + @spec get_initials(String.t(), integer(), integer(), String.t()) :: String.t() + def get_initials(name \\ nil, width \\ nil, height \\ nil, background \\ nil) do + api_path = "/v1/avatars/initials" + payload = %{ "name" => name, + "background" => background, "width" => width, "height" => height, - "background" => background, - "project" => client.config.project + "project" => Client.default_config()["project"] } |> Enum.reject(fn {_, v} -> v == nil end) - with {:ok, uri} <- prepare_uri(client.config.endpoint, api_path, payload) do - Client.call(client, uri) - else - {:error, reason} -> raise AppwriteException, message: reason - end + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} end @doc """ Generates a QR code from the given text. ## Parameters - - `client` (Client.t): The client instance. - `text` (string): The text to encode in the QR code. - `size` (optional, integer): The size of the QR code. - `margin` (optional, integer): The margin around the QR code. @@ -269,28 +254,28 @@ defmodule Appwrite.Services.Avatars do ## Raises - `AppwriteException` if the `text` is nil. """ - @spec get_qr(Client.t(), String.t(), integer(), integer(), boolean()) :: String.t() - def get_qr(client, text, size \\ nil, margin \\ nil, download \\ nil) when is_binary(text) do - api_path = "/avatars/qr" + @spec get_qr(String.t(), integer(), integer(), boolean()) :: String.t() + def get_qr(text, size \\ nil, margin \\ nil, download \\ nil) when is_binary(text) do + api_path = "/v1/avatars/qr" + payload = %{ "text" => text, "size" => size, "margin" => margin, "download" => download, - "project" => client.config.project + "project" => Client.default_config()["project"] } |> Enum.reject(fn {_, v} -> v == nil end) - with {:ok, uri} <- prepare_uri(client.config.endpoint, api_path, payload) do - Client.call(client, uri) - else - {:error, reason} -> raise AppwriteException, message: reason - end + url = URI.merge(Client.default_config()[~c"endpoint"], api_path) + + query_string = URI.encode_query(Service.flatten(payload)) + {to_string(url) <> "?" <> query_string} end def get_qr(_client, nil, _size, _margin, _download), - do: raise AppwriteException, message: "Missing required parameter: 'text'" + do: raise(AppwriteException, message: "Missing required parameter: 'text'") defp prepare_uri(endpoint, api_path, payload) do uri = URI.merge(endpoint, api_path) @@ -300,13 +285,27 @@ defmodule Appwrite.Services.Avatars do e -> {:error, Exception.message(e)} end - - # Helper function to optionally add a key to a map @spec maybe_put(map(), String.t(), any()) :: map() defp maybe_put(map, key, value) when is_nil(value), do: map defp maybe_put(map, key, value), do: Map.put(map, key, value) + # Helper function to validate parameters + @spec validate_params(map()) :: :ok | no_return() + defp validate_params(params) do + Enum.each(params, fn {key, value} -> + if is_nil(value) do + raise AppwriteException, "Missing required parameter: #{inspect(key)}" + end + end) + end - + # Helper function to build query params + @spec build_query_params(URI.t(), map()) :: URI.t() + defp build_query_params(uri, payload) do + Enum.reduce(payload, uri, fn {key, value}, acc -> + query = URI.decode_query(acc.query || "") |> Map.put(key, to_string(value)) + %{acc | query: URI.encode_query(query)} + end) + end end diff --git a/lib/appwrite/services/storage.ex b/lib/appwrite/services/storage.ex index 37f7969..9ab6637 100644 --- a/lib/appwrite/services/storage.ex +++ b/lib/appwrite/services/storage.ex @@ -14,8 +14,7 @@ defmodule Appwrite.Services.Storage do alias Appwrite.Exceptions.AppwriteException alias Appwrite.Types.{File, FileList} alias Appwrite.Utils.Service - alias Appwrite.Consts.{ImageGravity, ImageFormat} - alias Appwrite.Types.Client.Payload + @type bucket_id :: String.t() @type file_id :: String.t() @@ -87,11 +86,11 @@ defmodule Appwrite.Services.Storage do "permissions" => permissions } - api_header = %{"content-type" => "application/json"} + api_header = %{"content-type" => "multipart/form-data"} Task.async(fn -> try do - file = Client.chunked_upload("post", api_path, api_header, payload) + file = Client.call("post", api_path, api_header, payload) {:ok, file} rescue error -> {:error, error}