Skip to content

Commit

Permalink
feat(AuditLogs, Webhooks): added endpoints for audit logs and webhooks (
Browse files Browse the repository at this point in the history
#1)

* feat(AuditLogs, Webhooks): added endpoints for audit logs and webhooks

* fix: types and docs fixes, added missing functionality

* fix:added typedoc and fixed compilation issue

* fix: actually return message struct, fixed other webhook endpoints

* fix: remove redundant case in execute_webhook

* refactor: remove redundant case
  • Loading branch information
Drahcirius authored and SpaceEEC committed Nov 3, 2018
1 parent 39e7ee0 commit a54c107
Show file tree
Hide file tree
Showing 2 changed files with 317 additions and 1 deletion.
280 changes: 279 additions & 1 deletion lib/rest.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,20 @@ defmodule Crux.Rest do
Collection of Rest functions.
"""
alias Crux.Structs
alias Crux.Structs.{Channel, Emoji, Guild, Invite, Member, Message, Role, User}

alias Crux.Structs.{
AuditLog,
Channel,
Emoji,
Guild,
Invite,
Member,
Message,
Role,
User,
Webhook
}

alias Crux.Rest
alias Crux.Rest.{Endpoints, Util}

Expand Down Expand Up @@ -1041,6 +1054,37 @@ defmodule Crux.Rest do
Rest.Base.queue(:delete, Endpoints.guild(guild_id))
end

@typedoc """
Used to filter audit log results via `get_audit_logs/2`.
The `:user_id` field refers to the executor and not the target of the log.
"""
@type audit_log_options ::
%{
optional(:user_id) => snowflake(),
optional(:action_type) => pos_integer(),
optional(:before) => snowflake(),
optional(:limit) => pos_integer()
}
| [
{:user_id, snowflake()}
| {:action_type, pos_integer()}
| {:before, snowflake()}
| {:limit, pos_integer}
]

@doc """
Gets the audit logs for a guild
"""
@spec get_audit_logs(guild :: Util.guild_id_resolvable(), options :: audit_log_options() | nil) ::
{:ok, AuditLog.t()} | {:error, term()}
def get_audit_logs(guild, options \\ []) do
guild_id = Util.resolve_guild_id(guild)
body = Map.new(options)

Rest.Base.queue(:get, Endpoints.guild_audit_logs(guild_id), "", [], params: body)
|> create(AuditLog)
end

@doc """
Gets all channels from a guild via the api.
This should usually, due to caching, __NOT__ be necessary.
Expand Down Expand Up @@ -1710,6 +1754,240 @@ defmodule Crux.Rest do

### End Guild

### Start Webhook

@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()) ::
{:ok, [Webhook.t()]} | {:error, term()}
def list_guild_webhooks(guild) do
guild_id = Util.resolve_guild_id(guild)

Rest.Base.queue(:get, Endpoints.guild_webhooks(guild_id))
|> create(Webhook)
end

@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()) ::
{:ok, [Webhook.t()]} | {:error, term()}
def list_channel_webhooks(channel) do
channel_id = Util.resolve_channel_id(channel)

Rest.Base.queue(:get, Endpoints.channel_webhooks(channel_id))
|> create(Webhook)
end

@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) ::
{:ok, [Webhook.t()]} | {:error, term()}
def get_webhook(user, token \\ nil) do
user_id = Util.resolve_user_id(user)

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

@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(
user :: Util.user_id_resolvable(),
token :: String.t() | nil,
data ::
%{
optional(:name) => String.t(),
optional(:avatar) => String.t(),
optional(:channel_id) => snowflake()
}
| [{:name, String.t()} | {:avatar, String.t()} | {:channel_id, snowflake()}]
) :: {: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)
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) ::
:ok | {:error, term()}
def delete_webhook(user, token \\ nil) do
user_id = Util.resolve_user_id(user)
Rest.Base.queue(:delete, Endpoints.webhook(user_id, token))
end

@typedoc """
Used for sending discord webhooks. For more information on non-discord webhooks, check
[Slack Docs](https://api.slack.com/custom-integrations/outgoing-webhooks) or
[Github Docs](https://developer.github.com/webhooks/)
"""
@type execute_webhook_options :: %{
optional(:content) => String.t(),
optional(:username) => String.t(),
optional(:avatar_url) => String.t(),
optional(:tts) => boolean(),
optional(:file) => file_list_entry(),
optional(:embeds) => [embed()]
}
@doc """
Executes a webhook
> Returns :ok by default. If wait parameter is set to true, returns a tuple returning the message object or error
For more information see [Discord Docs](https://discordapp.com/developers/docs/resources/webhook#execute-webhook)
"""
@spec execute_webhook(
webhook :: Webhook.t(),
wait :: boolean | nil,
data :: execute_webhook_options()
) :: :ok | {:ok, Message.t()} | {:error, term}
@spec execute_webhook(
user :: Util.user_id_resolvable(),
token :: String.t(),
wait :: boolean | nil,
data :: execute_webhook_options()
) :: :ok | {:ok, Message.t()} | {:error, term}
def execute_webhook(webhook = %Webhook{}, data) do
execute_webhook(webhook.id, webhook.token, false, data)
end

def execute_webhook(user, token, wait \\ false, data)

def execute_webhook(webhook = %Webhook{}, wait, _, data) do
execute_webhook(webhook.id, webhook.token, wait, data)
end

def execute_webhook(user, token, wait, data) do
user_id = Util.resolve_user_id(user)
body = Map.new(data)

Rest.Base.queue(:post, Endpoints.webhook(user_id, token), body, [], params: [wait: wait])
|> create(Message)
end

@doc """
Executes a slack webhook
> Returns :ok by default. If wait parameter is set to true, it will either return :ok or an error tuple. Discord does not return the message object unlike the regular webhook endpoint.
For more information see [Slack Docs](https://api.slack.com/custom-integrations/outgoing-webhooks)
"""
@spec execute_slack_webhook(
webhook :: Webhook.t(),
wait :: boolean | nil,
data :: term()
) :: :ok | {:error, term}
@spec execute_slack_webhook(
user :: Util.user_id_resolvable(),
token :: String.t(),
wait :: boolean | nil,
data :: term()
) :: :ok | {:error, term}
def execute_slack_webhook(webhook = %Webhook{}, data) do
execute_slack_webhook(webhook.id, webhook.token, false, data)
end

def execute_slack_webhook(user, token, wait \\ false, data)

def execute_slack_webhook(webhook = %Webhook{}, wait, _, data) do
execute_slack_webhook(webhook.id, webhook.token, wait, data)
end

def execute_slack_webhook(user, token, wait, data) do
user_id = Util.resolve_user_id(user)
body = Map.new(data)

response =
Rest.Base.queue(
:post,
Endpoints.webhook_slack(user_id, token),
body,
[],
params: [wait: wait]
)

# returns "ok" in the response string, not json
case response do
{:ok, _} -> :ok
_ -> response
end
end

@doc """
Executes a github webhook
> Returns :ok by default. If wait parameter is set to true, it will either return :ok or an error tuple. Discord does not return the message object unlike the regular webhook endpoint.
The event parameter is passed into the "x-github-event" header. If this is not set to a valid event (e.g, "push", "issue"), discord will not send the webhook but still return 204 OK
For more information see [Github Docs](https://developer.github.com/webhooks/)
"""
@spec execute_github_webhook(
webhook :: Webhook.t(),
event :: String.t(),
wait :: boolean | nil,
data :: term()
) :: :ok | {:error, term}
@spec execute_github_webhook(
user :: Util.user_id_resolvable(),
token :: String.t(),
event :: String.t(),
wait :: boolean | nil,
data :: term()
) :: :ok | {:error, term}
def execute_github_webhook(webhook = %Webhook{}, event, data) do
execute_github_webhook(webhook.id, webhook.token, event, false, data)
end

def execute_github_webhook(user, token, event, wait \\ false, data)

def execute_github_webhook(webhook = %Webhook{}, event, wait, _, data) do
execute_github_webhook(webhook.id, webhook.token, event, wait, data)
end

def execute_github_webhook(user, token, event, wait, data) do
user_id = Util.resolve_user_id(user)
body = Map.new(data)

Rest.Base.queue(
:post,
Endpoints.webhook_github(user_id, token),
body,
[{"x-github-event", event}],
params: [wait: wait]
)
end

### End Webhook

@doc """
Fetches an invite from the api.
Expand Down
38 changes: 38 additions & 0 deletions lib/rest/endpoints.ex
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ defmodule Crux.Rest.Endpoints do
def guild(guild_id, nil), do: "/guilds/#{guild_id}"
def guild(guild_id, suffix), do: "#{guild(guild_id)}/#{suffix}"

@doc """
Used for guild audit logs fetching.
"""
@spec guild_audit_logs(guild_id :: Crux.Rest.snowflake()) :: String.t()
def guild_audit_logs(guild_id), do: guild(guild_id, "audit-logs")

@doc """
Used for guild emoji related functions.
"""
Expand Down Expand Up @@ -171,6 +177,38 @@ defmodule Crux.Rest.Endpoints do
def guild_member_roles(guild_id, member_id, role_id),
do: "#{guild_members(guild_id, member_id)}/roles/#{role_id}"

@doc """
Used to fetch channel webhooks.
"""
@spec channel_webhooks(channel_id :: Crux.Rest.snowflake()) :: String.t()
def channel_webhooks(channel_id), do: channel(channel_id, "webhooks")

@doc """
Used to fetch guild webhooks.
"""
@spec guild_webhooks(guild_id :: Crux.Rest.snowflake()) :: String.t()
def guild_webhooks(guild_id), do: guild(guild_id, "webhooks")

@doc """
Used for webhook related functions.
"""
@spec webhook(guild_id :: Crux.Rest.snowflake(), token :: String.t() | nil) :: String.t()
def webhook(webhook_id, token \\ nil)
def webhook(webhook_id, nil), do: "/webhooks/#{webhook_id}"
def webhook(webhook_id, token), do: "#{webhook(webhook_id)}/#{token}"

@doc """
Used to send slack formatted webhooks.
"""
@spec webhook_slack(webhook_id :: Crux.Rest.snowflake(), token :: String.t()) :: String.t()
def webhook_slack(webhook_id, token), do: "#{webhook(webhook_id, token)}/slack"

@doc """
Used to send github formatted webhooks.
"""
@spec webhook_github(webhook_id :: Crux.Rest.snowflake(), token :: String.t()) :: String.t()
def webhook_github(webhook_id, token), do: "#{webhook(webhook_id, token)}/github"

@doc """
Discord being special.
"""
Expand Down

0 comments on commit a54c107

Please sign in to comment.