diff --git a/README.md b/README.md index 8f6845b..c08188f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ All contributions are welcome! * [Support arrays as parameter types](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#parameter-types) * [Update current user](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#updating-the-current-user) * Fix method: [Uploading media attachment](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#uploading-a-media-attachment) -* [Getting who reblogged/favourited a status](https://github.com/milmazz/hunter/pull/2) * Verify each endpoint * Improve unit tests * Improve documentation diff --git a/lib/hunter.ex b/lib/hunter.ex index 3cad633..f57addb 100644 --- a/lib/hunter.ex +++ b/lib/hunter.ex @@ -125,7 +125,7 @@ defmodule Hunter do """ @spec accept_follow_request(Hunter.Client.t, non_neg_integer) :: boolean - defdelegate accept_follow_request(conn, id), to: Hunter.Account + defdelegate accept_follow_request(conn, id), to: Hunter.Account @doc """ Rejects a follow request @@ -136,7 +136,7 @@ defmodule Hunter do * `id` - follow request id """ - @spec reject_follow_request(Hunter.Client.t, non_neg_integer) :: boolean + @spec reject_follow_request(Hunter.Client.t, non_neg_integer) :: boolean defdelegate reject_follow_request(conn, id), to: Hunter.Account ## Application @@ -356,6 +356,18 @@ defmodule Hunter do @spec unreblog(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t defdelegate unreblog(conn, id), to: Hunter.Status + @doc """ + Fetch the list of users who reblogged the status. + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + @spec reblogged_by(Hunter.Client.t, non_neg_integer) :: [Hunter.Account.t] + defdelegate reblogged_by(conn, id), to: Hunter.Status + @doc """ Favorite a status @@ -391,6 +403,19 @@ defmodule Hunter do @spec favourites(Hunter.Client.t) :: [Hunter.Status.t] defdelegate favourites(conn), to: Hunter.Status + @doc """ + Fetch the list of users who favourited the status + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + + @spec favourited_by(Hunter.Client.t, non_neg_integer) :: [Hunter.Account.t] + defdelegate favourited_by(conn, id), to: Hunter.Status + @doc """ Get a list of statuses by a user diff --git a/lib/hunter/account.ex b/lib/hunter/account.ex index 208fe17..9165488 100644 --- a/lib/hunter/account.ex +++ b/lib/hunter/account.ex @@ -205,8 +205,8 @@ defmodule Hunter.Account do * `id` - follow request id """ - @spec reject_follow_request(Hunter.Client.t, non_neg_integer) :: boolean + @spec reject_follow_request(Hunter.Client.t, non_neg_integer) :: boolean def reject_follow_request(conn, id ) do @hunter_api.follow_request_action(conn, id, :reject) - end + end end diff --git a/lib/hunter/api.ex b/lib/hunter/api.ex index 7c10ccc..91763bd 100644 --- a/lib/hunter/api.ex +++ b/lib/hunter/api.ex @@ -120,7 +120,7 @@ defmodule Hunter.Api do * `:reject` - reject a follow request """ - @callback follow_request_action(conn :: Hunter.Client.t, id :: non_neg_integer, action :: atom) :: boolean + @callback follow_request_action(conn :: Hunter.Client.t, id :: non_neg_integer, action :: atom) :: boolean ## Application @@ -312,6 +312,17 @@ defmodule Hunter.Api do """ @callback unreblog(conn :: Hunter.Client.t, id :: non_neg_integer) :: Hunter.Status.t + @doc """ + Fetch the list of users who reblogged the status. + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + @callback reblogged_by(conn :: Hunter.Client.t, id :: non_neg_integer) :: [Hunter.Account.t] + @doc """ Favorite a status @@ -344,6 +355,17 @@ defmodule Hunter.Api do """ @callback favourites(conn :: Hunter.Client.t) :: [Hunter.Status.t] + @doc """ + Fetch the list of users who favourited the status. + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + @callback favourited_by(conn :: Hunter.Client.t, id :: non_neg_integer) :: [Hunter.Account.t] + @doc """ Get a list of statuses by a user diff --git a/lib/hunter/api/http_client.ex b/lib/hunter/api/http_client.ex index d131127..a4c0efa 100644 --- a/lib/hunter/api/http_client.ex +++ b/lib/hunter/api/http_client.ex @@ -161,6 +161,11 @@ defmodule Hunter.Api.HTTPClient do to_status(body) end + def reblogged_by(%Hunter.Client{base_url: base_url} = conn, id) do + %HTTPoison.Response{body: body, status_code: 200} = HTTPoison.get!(base_url <> "/api/v1/statuses/#{id}/reblogged_by", get_headers(conn)) + to_accounts(body) + end + def favourite(%Hunter.Client{base_url: base_url} = conn, id) do payload = Poison.encode!(%{}) @@ -180,6 +185,11 @@ defmodule Hunter.Api.HTTPClient do to_statuses(body) end + def favourited_by(%Hunter.Client{base_url: base_url} = conn, id) do + %HTTPoison.Response{body: body, status_code: 200} = HTTPoison.get!(base_url <> "/api/v1/statuses/#{id}/favourited_by", get_headers(conn)) + to_accounts(body) + end + @doc """ Get an account's statuses @@ -271,6 +281,10 @@ defmodule Hunter.Api.HTTPClient do Poison.decode!(body, as: [status_nested_struct()]) end + defp to_accounts(body) do + Poison.decode!(body, as: [%Hunter.Account{}]) + end + defp status_nested_struct do %Hunter.Status{ account: %Hunter.Account{}, diff --git a/lib/hunter/status.ex b/lib/hunter/status.ex index 0e0b75d..6126704 100644 --- a/lib/hunter/status.ex +++ b/lib/hunter/status.ex @@ -49,6 +49,8 @@ defmodule Hunter.Status do application: Hunter.Application.t } + @type status_id :: non_neg_integer + @derive [Poison.Encoder] defstruct [:id, :uri, @@ -82,7 +84,7 @@ defmodule Hunter.Status do * `media_ids` - [Array] """ - @spec create_status(Hunter.Client.t, String.t, non_neg_integer, [non_neg_integer]) :: Hunter.Status.t + @spec create_status(Hunter.Client.t, String.t, status_id, [non_neg_integer]) :: Hunter.Status.t def create_status(conn, text, in_reply_to_id \\ nil, media_ids \\ []) do @hunter_api.create_status(conn, text, in_reply_to_id, media_ids) end @@ -96,7 +98,7 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec status(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t + @spec status(Hunter.Client.t, status_id) :: Hunter.Status.t def status(conn, id) do @hunter_api.status(conn, id) end @@ -110,7 +112,7 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec destroy_status(Hunter.Client.t, non_neg_integer) :: boolean + @spec destroy_status(Hunter.Client.t, status_id) :: boolean def destroy_status(conn, id) do @hunter_api.destroy_status(conn, id) end @@ -124,7 +126,7 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec reblog(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t + @spec reblog(Hunter.Client.t, status_id) :: Hunter.Status.t def reblog(conn, id) do @hunter_api.reblog(conn, id) end @@ -138,11 +140,25 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec unreblog(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t + @spec unreblog(Hunter.Client.t, status_id) :: Hunter.Status.t def unreblog(conn, id) do @hunter_api.unreblog(conn, id) end + @doc """ + Fetch the list of users who reblogged the status. + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + @spec reblogged_by(Hunter.Client.t, status_id) :: [Hunter.Account.t] + def reblogged_by(conn, id) do + @hunter_api.reblogged_by(conn, id) + end + @doc """ Favorite a status @@ -152,7 +168,7 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec favourite(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t + @spec favourite(Hunter.Client.t, status_id) :: Hunter.Status.t def favourite(conn, id) do @hunter_api.favourite(conn, id) end @@ -166,7 +182,7 @@ defmodule Hunter.Status do * `id` - status identifier """ - @spec unfavourite(Hunter.Client.t, non_neg_integer) :: Hunter.Status.t + @spec unfavourite(Hunter.Client.t, status_id) :: Hunter.Status.t def unfavourite(conn, id) do @hunter_api.unfavourite(conn, id) end @@ -184,6 +200,21 @@ defmodule Hunter.Status do @hunter_api.favourites(conn) end + @doc """ + Fetch the list of users who favourited the status + + ## Parameters + + * `conn` - connection credentials + * `id` - status identifier + + """ + + @spec favourited_by(Hunter.Client.t, status_id) :: [Hunter.Account.t] + def favourited_by(conn, id) do + @hunter_api.favourited_by(conn, id) + end + @doc """ Get a list of statuses by a user @@ -200,7 +231,7 @@ defmodule Hunter.Status do * `limit` - [Integer] """ - @spec statuses(Hunter.Client.t, non_neg_integer, Keyword.t) :: [Hunter.Status.t] + @spec statuses(Hunter.Client.t, status_id, Keyword.t) :: [Hunter.Status.t] def statuses(conn, account_id, options \\ []) do @hunter_api.statuses(conn, account_id, options) end diff --git a/test/fixtures/favourited_by.json b/test/fixtures/favourited_by.json new file mode 100644 index 0000000..10b13d6 --- /dev/null +++ b/test/fixtures/favourited_by.json @@ -0,0 +1,36 @@ +[ + { + "id": 2286, + "username": "marxistvegan", + "acct": "marxistvegan", + "display_name": "stephen 🌹✪", + "locked": false, + "created_at": "2017-04-12T13:21:32.932Z", + "followers_count": 45, + "following_count": 62, + "statuses_count": 65, + "note": "Luxemburgist. Organizer in the labor & social movements. Co-host https://cyberunions.org podcast, member of https://glocal.coop. Pronoun he/him #AntiFa #marxist", + "url": "https://soc.ialis.me/@marxistvegan", + "avatar": "https://pictor.ialis.me/accounts/avatars/000/002/286/original/a7154cd28f490be2.jpeg?1492003901", + "avatar_static": "https://pictor.ialis.me/accounts/avatars/000/002/286/original/a7154cd28f490be2.jpeg?1492003901", + "header": "https://pictor.ialis.me/accounts/headers/000/002/286/original/b0457c9d6168b53e.png?1492080325", + "header_static": "https://pictor.ialis.me/accounts/headers/000/002/286/original/b0457c9d6168b53e.png?1492080325" + }, + { + "id": 1, + "username": "href", + "acct": "href", + "display_name": "href", + "locked": false, + "created_at": "2017-04-09T12:19:29.077Z", + "followers_count": 132, + "following_count": 198, + "statuses_count": 418, + "note": "cybermenace & mauvaise influence. #freebsd, #erlang, #elixir. #fr & #en.\r\n\r\nhttp://href.rocks - https://random.sh\r\n\r\nhttps://soc.ialis.me admin", + "url": "https://soc.ialis.me/@href", + "avatar": "https://pictor.ialis.me/accounts/avatars/000/000/001/original/42fe522de966bd8a.jpg?1491741513", + "avatar_static": "https://pictor.ialis.me/accounts/avatars/000/000/001/original/42fe522de966bd8a.jpg?1491741513", + "header": "https://pictor.ialis.me/accounts/headers/000/000/001/original/53b5cb6b4bb97932.jpg?1491745462", + "header_static": "https://pictor.ialis.me/accounts/headers/000/000/001/original/53b5cb6b4bb97932.jpg?1491745462" + } +] diff --git a/test/fixtures/reblogged_by.json b/test/fixtures/reblogged_by.json new file mode 100644 index 0000000..e44cddb --- /dev/null +++ b/test/fixtures/reblogged_by.json @@ -0,0 +1,36 @@ +[ + { + "id": 970, + "username": "maliciarogue", + "acct": "maliciarogue@mastodon.social", + "display_name": "R ✅", + "locked": false, + "created_at": "2017-04-10T14:30:57.949Z", + "followers_count": 3, + "following_count": 2, + "statuses_count": 156, + "note": "I troll, therefore I am. Writer; OSINT & sec analyst; I do risk & crisis mngmnt so u don't have to.Polylingual bookworm. I toot 4 chocolate /!\\Parental advisory", + "url": "https://mastodon.social/@maliciarogue", + "avatar": "https://pictor.ialis.me/accounts/avatars/000/000/970/original/d5a601a0133d75c1.jpg?1491834658", + "avatar_static": "https://pictor.ialis.me/accounts/avatars/000/000/970/original/d5a601a0133d75c1.jpg?1491834658", + "header": "/headers/original/missing.png", + "header_static": "/headers/original/missing.png" + }, + { + "id": 2495, + "username": "hecate", + "acct": "hecate", + "display_name": "Hecatée Irssiainen", + "locked": false, + "created_at": "2017-04-12T20:05:42.369Z", + "followers_count": 5, + "following_count": 6, + "statuses_count": 9, + "note": "Cyber-postrock technoqueer. I go by she/her, and it's usually with your mum.", + "url": "https://soc.ialis.me/@hecate", + "avatar": "https://pictor.ialis.me/accounts/avatars/000/002/495/original/7c78b503266e4bdf.png?1492027924", + "avatar_static": "https://pictor.ialis.me/accounts/avatars/000/002/495/original/7c78b503266e4bdf.png?1492027924", + "header": "https://pictor.ialis.me/accounts/headers/000/002/495/original/a1f76633a274cb61.jpg?1492027924", + "header_static": "https://pictor.ialis.me/accounts/headers/000/002/495/original/a1f76633a274cb61.jpg?1492027924" + } +] diff --git a/test/support/in_memory.ex b/test/support/in_memory.ex index 93e506d..b7f8f94 100644 --- a/test/support/in_memory.ex +++ b/test/support/in_memory.ex @@ -14,6 +14,7 @@ defmodule Hunter.Api.InMemory do %{name: :create_app, arity: 5, as: %Hunter.Application{}}, %{name: :create_status, arity: 4, as: %Hunter.Status{}}, %{name: :favourite, arity: 2, as: %Hunter.Status{}}, + %{name: :favourited_by, arity: 2, as: [%Hunter.Account{}]}, %{name: :favourites, arity: 1, as: [%Hunter.Status{}]}, %{name: :follow, arity: 2, as: %Hunter.Relationship{}}, %{name: :follow_by_uri, arity: 2, as: %Hunter.Account{}}, @@ -29,6 +30,7 @@ defmodule Hunter.Api.InMemory do %{name: :notifications, arity: 1, as: [%Hunter.Notification{}]}, %{name: :public_timeline, arity: 2, as: [%Hunter.Status{}]}, %{name: :reblog, arity: 2, as: %Hunter.Status{}}, + %{name: :reblogged_by, arity: 2, as: [%Hunter.Account{}]}, %{name: :relationships, arity: 2, as: [%Hunter.Relationship{}]}, %{name: :report, arity: 4, as: %Hunter.Report{}}, %{name: :reports, arity: 1, as: [%Hunter.Report{}]}, @@ -50,7 +52,7 @@ defmodule Hunter.Api.InMemory do as = Macro.escape(as) def unquote(name)(unquote_splicing(params)) do - file = unquote(name) |> to_string() + file = to_string(unquote(name)) "../fixtures/#{file}.json" |> Path.expand(__DIR__)