diff --git a/README.md b/README.md index 2069ded..88cf77d 100644 --- a/README.md +++ b/README.md @@ -421,13 +421,12 @@ Returns a `Hunter.Account` ### Configuration -Hunter uses [HTTPoison](https://hex.pm/packages/httpoison) as HTTP client layer. +Hunter uses [HTTPoison](https://hex.pm/packages/httpoison) as HTTP client layer. HTTPoison understands a set of [HTTP options](https://hexdocs.pm/httpoison/HTTPoison.Request.html) which can be configured through Hunter configuration : ``` config :hunter, http_options: [follow_redirect: true, hackney: [{:force_redirect, true}]] - -``` +``` will tell HTTPoison to follow redirected (301) links when calling mastodon API. diff --git a/config/config.exs b/config/config.exs index 6422d4e..68a6735 100644 --- a/config/config.exs +++ b/config/config.exs @@ -27,4 +27,4 @@ use Mix.Config # Configuration from the imported file will override the ones defined # here (which is why it is important to import them last). # -import_config "#{Mix.env}.exs" +import_config "#{Mix.env()}.exs" diff --git a/lib/hunter.ex b/lib/hunter.ex index ff7842e..6836189 100644 --- a/lib/hunter.ex +++ b/lib/hunter.ex @@ -269,10 +269,16 @@ defmodule Hunter do * `conn` - connection credentials * `file` - media to be uploaded + * `options` - option list + + ## Options + + * `description` - plain-text description of the media for accessibility (max 420 chars) + * `focus` - two floating points, comma-delimited """ - @spec upload_media(Hunter.Client.t(), Path.t()) :: Hunter.Attachment.t() - defdelegate upload_media(conn, file), to: Hunter.Attachment + @spec upload_media(Hunter.Client.t(), Path.t(), Keyword.t()) :: Hunter.Attachment.t() + defdelegate upload_media(conn, file, options \\ []), to: Hunter.Attachment @doc """ Get the relationships of authenticated user towards given other users diff --git a/lib/hunter/api.ex b/lib/hunter/api.ex index 97d4295..0c0e684 100644 --- a/lib/hunter/api.ex +++ b/lib/hunter/api.ex @@ -220,9 +220,16 @@ defmodule Hunter.Api do * `conn` - connection credentials * `file` - media to be uploaded + * `options` - option list + + ## Options + + * `description` - plain-text description of the media for accessibility (max 420 chars) + * `focus` - two floating points, comma-delimited. """ - @callback upload_media(conn :: Hunter.Client.t(), file :: Path.t()) :: Hunter.Attachment.t() + @callback upload_media(conn :: Hunter.Client.t(), file :: Path.t(), options :: Keyword.t()) :: + Hunter.Attachment.t() ## Relationship diff --git a/lib/hunter/api/http_client.ex b/lib/hunter/api/http_client.ex index 0070ab6..a775c4d 100644 --- a/lib/hunter/api/http_client.ex +++ b/lib/hunter/api/http_client.ex @@ -88,11 +88,19 @@ defmodule Hunter.Api.HTTPClient do |> request!(:application, :post, payload) end - # TODO: Review this function - def upload_media(conn, file) do + def upload_media(conn, file, options) do + options = + [{:file, file, {"form-data", [name: "file", filename: Path.basename(file)]}, []}] ++ + Enum.map(options, fn {key, value} -> {to_string(key), value} end) + + headers = + conn + |> get_headers() + |> Keyword.put(:"Content-Type", "multipart/form-data") + "/api/v1/media" |> process_url(conn) - |> request!(:attachment, :post, {:file, file}, get_headers(conn)) + |> request!(:attachment, :post, {:multipart, options}, headers) end def relationships(conn, ids) do @@ -140,7 +148,7 @@ defmodule Hunter.Api.HTTPClient do def search(conn, query, options) do options = options |> Keyword.merge(q: query) |> Map.new() - "/api/v1/search" + "/api/v2/search" |> process_url(conn) |> request!(:result, :get, options, get_headers(conn)) end @@ -342,7 +350,7 @@ defmodule Hunter.Api.HTTPClient do end defp get_headers(%Hunter.Client{bearer_token: token}) do - [Authorization: "Bearer #{token}"] + [{"Authorization", "Bearer #{token}"}] end defp process_url(endpoint, %Hunter.Client{base_url: base_url}) do diff --git a/lib/hunter/api/request.ex b/lib/hunter/api/request.ex index 62e286d..e3044da 100644 --- a/lib/hunter/api/request.ex +++ b/lib/hunter/api/request.ex @@ -33,6 +33,9 @@ defmodule Hunter.Api.Request do [] -> "{}" + {:multipart, _} -> + data + data when is_binary(data) -> data diff --git a/lib/hunter/attachment.ex b/lib/hunter/attachment.ex index ad2bda3..9a46444 100644 --- a/lib/hunter/attachment.ex +++ b/lib/hunter/attachment.ex @@ -12,10 +12,15 @@ defmodule Hunter.Attachment do * `url` - URL of the locally hosted version of the image * `remote_url` - For remote images, the remote URL of the original image * `preview_url` - URL of the preview image - * `text_url` - Shorter URL for the image, for insertion into text (only present on local images) - * `meta` - `small` and `original` containing: `width`, `height`, `size`, `aspect` + * `text_url` - Shorter URL for the image, for insertion into text (only + present on local images) + * `meta` - May contain subtress `small` and `original`. Images may contain: + `width`, `height`, `size`, `aspect`, while videos (including `gifv`) may + contain: `width`, `height`, `frame_rate`, `duration`, and `bitrate`. + * `description` - attachment description - **Note**: When the type is "unknown", it is likely only `remote_url` is available and local `url` is missing + **Note**: When the type is "unknown", it is likely only `remote_url` is + available and local `url` is missing """ @hunter_api Hunter.Config.hunter_api() @@ -27,11 +32,12 @@ defmodule Hunter.Attachment do remote_url: String.t(), preview_url: String.t(), text_url: String.t(), - meta: String.t() + meta: String.t(), + description: String.t() } @derive [Poison.Encoder] - defstruct [:id, :type, :url, :remote_url, :preview_url, :text_url, :meta] + defstruct [:id, :type, :url, :remote_url, :preview_url, :text_url, :meta, :description] @doc """ Upload a media attachment @@ -40,10 +46,15 @@ defmodule Hunter.Attachment do * `conn` - connection credentials * `file` - media to be uploaded + * `options` - option list + + ## Options + * `description` - plain-text description of the media for accessibility (max 420 chars) + * `focus` - two floating points, comma-delimited. """ - @spec upload_media(Hunter.Client.t(), Path.t()) :: Hunter.Attachment.t() - def upload_media(conn, file) do - @hunter_api.upload_media(conn, file) + @spec upload_media(Hunter.Client.t(), Path.t(), Keyword.t()) :: Hunter.Attachment.t() + def upload_media(conn, file, options \\ []) do + @hunter_api.upload_media(conn, file, options) end end diff --git a/test/support/in_memory.ex b/test/support/in_memory.ex index 5130501..916c53e 100644 --- a/test/support/in_memory.ex +++ b/test/support/in_memory.ex @@ -46,22 +46,22 @@ defmodule Hunter.Api.InMemory do %{name: :unmute, arity: 2, as: %Hunter.Relationship{}}, %{name: :unreblog, arity: 2, as: %Hunter.Status{}}, %{name: :update_credentials, arity: 2, as: %Hunter.Account{}}, - %{name: :upload_media, arity: 2, as: %Hunter.Attachment{}}, + %{name: :upload_media, arity: 3, as: %Hunter.Attachment{}}, %{name: :verify_credentials, arity: 1, as: %Hunter.Account{}} ] |> Enum.map(fn %{name: name, arity: arity, as: as} -> - params = for _ <- 1..arity, do: {:_, [], nil} - as = Macro.escape(as) + params = for _ <- 1..arity, do: {:_, [], nil} + as = Macro.escape(as) - def unquote(name)(unquote_splicing(params)) do - file = to_string(unquote(name)) + def unquote(name)(unquote_splicing(params)) do + file = to_string(unquote(name)) - "../fixtures/#{file}.json" - |> Path.expand(__DIR__) - |> File.read!() - |> Poison.decode!(as: unquote(as)) - end - end) + "../fixtures/#{file}.json" + |> Path.expand(__DIR__) + |> File.read!() + |> Poison.decode!(as: unquote(as)) + end + end) def destroy_status(_, _), do: true def follow_request_action(_, _, _), do: true