Skip to content

Commit

Permalink
fix(Rest, Util): properly resolve files for non create_message/2
Browse files Browse the repository at this point in the history
  • Loading branch information
SpaceEEC committed Nov 5, 2018
1 parent 20e544c commit de08648
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 54 deletions.
94 changes: 50 additions & 44 deletions lib/rest.ex
Original file line number Diff line number Diff line change
Expand Up @@ -621,13 +621,22 @@ defmodule Crux.Rest do
"""
@spec modify_channel(
channel :: Util.channel_id_resolvable(),
args :: modify_channel_data()
data :: modify_channel_data()
) :: {:ok, Channel.t()} | {:error, term()}
def modify_channel(channel, args) do
def modify_channel(channel, data) do
channel_id = Util.resolve_channel_id(channel)

Rest.Base.queue(:patch, Endpoints.channel(channel_id), Map.new(args))
|> create(Channel)
data
|> Map.new()
|> Util.encode_map_key(:icon)
|> case do
%{icon: {:error, _} = error} ->
error

data ->
Rest.Base.queue(:patch, Endpoints.channel(channel_id), data)
|> create(Channel)
end
end

@doc """
Expand Down Expand Up @@ -867,9 +876,7 @@ defmodule Crux.Rest do

data
|> Map.new()
|> Map.update!(:image, fn image ->
with {:ok, binary} <- Util.resolve_file(image), do: binary
end)
|> Util.encode_map_key(:image)
|> Map.update(:roles, [], &Enum.map(&1, fn role -> Util.resolve_role_id(role) end))
|> case do
%{image: {:error, error}} ->
Expand Down Expand Up @@ -952,9 +959,7 @@ defmodule Crux.Rest do
data =
data
|> Map.new()
|> Map.update(:icon, nil, fn icon ->
if icon, do: with({:ok, binary} <- Util.resolve_file(icon), do: binary |> Base.encode64())
end)
|> Util.encode_map_key(:icon)

Rest.Base.queue(:post, Endpoints.guild(), data)
|> create(Guild)
Expand Down Expand Up @@ -1019,26 +1024,19 @@ defmodule Crux.Rest do
def modify_guild(guild, data) do
guild_id = Util.resolve_guild_id(guild)

data =
data
|> Map.new()
|> Map.update(:icon, nil, fn icon ->
if icon, do: with({:ok, binary} <- Util.resolve_file(icon), do: binary |> Base.encode64())
end)
|> Map.update(:splash, nil, fn splash ->
if splash,
do: with({:ok, binary} <- Util.resolve_file(splash), do: binary |> Base.encode64())
end)

case data do
%{icon: {:error, error}} ->
{:error, error}
data
|> Map.new()
|> Util.encode_map_key(:icon)
|> Util.encode_map_key(:splash)
|> case do
%{icon: {:error, _error} = error} ->
error

%{splash: {:error, error}} ->
{:error, error}
%{splash: {:error, _error} = error} ->
error

_ ->
Rest.Base.queue(:post, Endpoints.guild(guild_id), data)
Rest.Base.queue(:patch, Endpoints.guild(guild_id), data)
|> create(Guild)
end
end
Expand Down Expand Up @@ -1387,7 +1385,7 @@ defmodule Crux.Rest do
guild_id = Util.resolve_guild_id(guild)

Rest.Base.queue(:get, Endpoints.guild_bans(guild_id))
|> Map.new(fn %{user: user}=entry ->
|> Map.new(fn %{user: user} = entry ->
user = Structs.create(user, User)
{user.id, %{entry | user: user}}
end)
Expand Down Expand Up @@ -1750,6 +1748,9 @@ defmodule Crux.Rest do
case Rest.Base.queue(:get, Endpoints.guild(guild_id, "vanity-url")) do
{:ok, %{code: code}} ->
{:ok, code}

{:error, _error} = error ->
error
end
end

Expand All @@ -1760,8 +1761,6 @@ defmodule Crux.Rest do
@doc """
Fetches a guild's webhook list
> Returns a list of [Webhook Objects](https://discordapp.com/developers/docs/resources/webhook#webhook-object)
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#get-guild-webhooks)
"""
@spec list_guild_webhooks(guild :: Util.guild_id_resolvable()) ::
Expand All @@ -1776,8 +1775,6 @@ defmodule Crux.Rest do
@doc """
Fetches a channel's webhook list
> Returns a list of [Webhook Objects](https://discordapp.com/developers/docs/resources/webhook#webhook-object)
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#get-channel-webhooks)
"""
@spec list_channel_webhooks(channel :: Util.channel_id_resolvable()) ::
Expand All @@ -1792,8 +1789,6 @@ defmodule Crux.Rest do
@doc """
Fetches a webhook
> Returns a [Webhook Object](https://discordapp.com/developers/docs/resources/webhook#webhook-object)
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#get-webhook)
"""
@spec get_webhook(user :: Util.user_id_resolvable(), token :: String.t() | nil) ::
Expand All @@ -1808,8 +1803,6 @@ defmodule Crux.Rest do
@doc """
Updates a webhook
> Returns the updated [Webhook Object](https://discordapp.com/developers/docs/resources/webhook#webhook-object)
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#modify-webhook)
"""
@spec update_webhook(
Expand All @@ -1825,17 +1818,23 @@ defmodule Crux.Rest do
) :: {:ok, Webhook.t()} | {:error, term()}
def update_webhook(user, token \\ nil, data) do
user_id = Util.resolve_user_id(user)
body = Map.new(data)

Rest.Base.queue(:patch, Endpoints.webhook(user_id, token), body)
|> create(Webhook)
data
|> Map.new()
|> Util.encode_map_key(:avatar)
|> case do
%{avatar: {:error, _error} = error} ->
error

data ->
Rest.Base.queue(:patch, Endpoints.webhook(user_id, token), data)
|> create(Webhook)
end
end

@doc """
Deletes a webhook
> Returns :ok on success, otherwise an error tuple
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#delete-webhook)
"""
@spec delete_webhook(user :: Util.user_id_resolvable(), token :: String.t() | nil) ::
Expand Down Expand Up @@ -2046,10 +2045,17 @@ defmodule Crux.Rest do
@spec modify_current_user(data :: modify_current_user_data()) ::
{:ok, User.t()} | {:error, term()}
def modify_current_user(data) do
data = Map.new(data)
data
|> Map.new()
|> Util.encode_map_key(:avatar)
|> case do
%{avatar: {:error, _error} = error} ->
error

Rest.Base.queue(:post, Endpoints.me(), data)
|> create(User)
data ->
Rest.Base.queue(:post, Endpoints.me(), data)
|> create(User)
end
end

@typedoc """
Expand Down
54 changes: 44 additions & 10 deletions lib/rest/util.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,36 @@ defmodule Crux.Rest.Util do
end
end

@doc """
Resolves and encodes a file resolvable under a key in a map.
If the key is not in the map nothing is done.
"""
@spec encode_map_key(map(), atom()) :: map()
def encode_map_key(%{} = map, key) when is_atom(key) do
case map do
%{^key => file} when not is_nil(file) ->
with {:ok, binary} <- resolve_file(file) do
Map.put(map, key, "data:image/jpg;base64,#{Base.encode64(binary)}")
end

_ ->
map
end
end

@typedoc """
Used when sending files via `Rest.create_message/2`.
The elements are:
1. Name of the file or :file for a local file
2. Binary of the file or the file path
3. Disposition (for form-data)
4. Headers (content-type)
"""
@type resolved_file ::
{
String.t() | :file,
String.t() | binary(),
binary() | String.t(),
{String.t(), [{String.t(), binary()}]},
[{String.t(), String.t()}]
}
Expand All @@ -48,22 +71,25 @@ defmodule Crux.Rest.Util do
Resolves a:
* path to a file
* tuple of path to a file or binary of one, and a file name
to a `resolved_file` automatically used by `Rest.create_message/2`
to a `t:resolved_file/0` automatically used by `Rest.create_message/2`
"""
# path
@spec map_file(
path ::
String.t()
| {String.t() | binary(), String.t()}
Crux.Rest.file_list_entry()
| {String.t() | :file, String.t() | binary(), String.t()}
) :: resolved_file() | {:error, term()}
def(map_file(path) when is_bitstring(path), do: map_file({path, Path.basename(path)}))
# path
def map_file(path) when is_binary(path) do
map_file({Path.basename(path), path, Path.basename(path)})
end

# {binary | path, name}
def map_file({bin_or_path, name}) when is_binary(bin_or_path) do
def map_file({bin_or_path, name})
when is_bitstring(bin_or_path) and is_binary(name) do
cond do
Regex.match?(~r{^https?://}, bin_or_path) ->
with {:ok, %{body: file}} <- HTTPoison.get(bin_or_path) do
map_file({file, Path.basename(name)})
map_file({Path.basename(name), file, Path.basename(name)})
else
{:error, _error} = error ->
error
Expand All @@ -75,14 +101,22 @@ defmodule Crux.Rest.Util do
File.exists?(bin_or_path) ->
with {:ok, %{type: :regular}} <- File.stat(bin_or_path) do
map_file({:file, bin_or_path, Path.basename(name)})
else
{:error, _error} = error ->
error

other ->
{:error, other}
end

true ->
map_file({Path.basename(name), bin_or_path, Path.basename(name)})
end
end

def map_file({name_or_atom, bin_or_path, name}) do
def map_file({name_or_atom, bin_or_path, name})
when (is_binary(name_or_atom) or name_or_atom == :file) and is_bitstring(bin_or_path) and
is_binary(name) do
disposition = {"form-data", [{"filename", "\"#{name}\""}, {"name", "\"#{name}\""}]}
headers = [{"content-type", :mimerl.filename(name)}]

Expand Down Expand Up @@ -325,7 +359,7 @@ defmodule Crux.Rest.Util do
}

@doc ~S"""
Resolves a `t:channel_poisition_resolvable/0` into a channel position.
Resolves a `t:channel_position_resolvable/0` into a channel position.
## Examples
Expand Down

0 comments on commit de08648

Please sign in to comment.