Adam Millerchip
7915b6d4ed
I originally developed this as an employee under the assumption that this would be released as an official SDK maintained by the company. But this is not the case, so I'm resetting the history to develop this in a personal capacity. This commit represents the progress until now.
390 lines
15 KiB
Elixir
390 lines
15 KiB
Elixir
defmodule LineBot do
|
|
alias LineBot.EventInfo
|
|
|
|
@api_client Application.get_env(:line_bot, :api_client, LineBot.APIClient)
|
|
|
|
@moduledoc """
|
|
A module for sending and receiving messages with the Line Messaging API.
|
|
|
|
This module:
|
|
* Provides functions for calling the various Line Messaging API endpoints.
|
|
* Specifies a behaviour that defines event handlers which are called to handle
|
|
[webhook event objects](https://developers.line.biz/en/reference/messaging-api/#webhook-event-objects)
|
|
from the Messaging API.
|
|
|
|
## Callbacks
|
|
If an event contains event-specific data, it is passed as the first argument to the event handler.
|
|
Each callback is provided with a `t:LineBot.EventInfo.t/0` struct, which contains common metadata for
|
|
each request. If available, a `reply_token` for use with the `send_reply/3`
|
|
is included as the final argument.
|
|
|
|
Unknown events are passed to `c:handle_other/4`.
|
|
|
|
All of the callbacks are optional. If a callback is not implemented, the event will be ignored.
|
|
"""
|
|
|
|
@doc """
|
|
Called when a [Message event](https://developers.line.biz/en/reference/messaging-api/#message-event)
|
|
is received.
|
|
"""
|
|
@callback handle_message(message :: map, info :: EventInfo.t(), reply_token :: binary) :: any
|
|
|
|
@doc """
|
|
Called when a [Follow event](https://developers.line.biz/en/reference/messaging-api/#follow-event)
|
|
is received.
|
|
"""
|
|
@callback handle_follow(info :: EventInfo.t(), reply_token :: binary) :: any
|
|
|
|
@doc """
|
|
Called when an [Unfollow event](https://developers.line.biz/en/reference/messaging-api/#unfollow-event)
|
|
is received.
|
|
"""
|
|
@callback handle_unfollow(info :: EventInfo.t()) :: any
|
|
|
|
@doc """
|
|
Called when a [Join event](https://developers.line.biz/en/reference/messaging-api/#join-event)
|
|
is received.
|
|
"""
|
|
@callback handle_join(info :: EventInfo.t(), reply_token :: binary) :: any
|
|
|
|
@doc """
|
|
Called when a [Leave event](https://developers.line.biz/en/reference/messaging-api/#leave-event)
|
|
is received.
|
|
"""
|
|
@callback handle_leave(info :: EventInfo.t()) :: any
|
|
|
|
@doc """
|
|
Called when a [Member Joined event](https://developers.line.biz/en/reference/messaging-api/#member-joined-event)
|
|
is received.
|
|
"""
|
|
@callback handle_member_joined(
|
|
members :: list,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary
|
|
) :: any
|
|
|
|
@doc """
|
|
Called when a [Member Left event](https://developers.line.biz/en/reference/messaging-api/#member-left-event)
|
|
is received.
|
|
"""
|
|
@callback handle_member_left(members :: list, info :: EventInfo.t()) :: any
|
|
|
|
@doc """
|
|
Called when a [Postback event](https://developers.line.biz/en/reference/messaging-api/#postback-event)
|
|
is received.
|
|
"""
|
|
@callback handle_postback(
|
|
data :: any,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary
|
|
) :: any
|
|
|
|
@doc """
|
|
Called when a [Beacon event](https://developers.line.biz/en/reference/messaging-api/#beacon-event)
|
|
is received.
|
|
"""
|
|
@callback handle_beacon(
|
|
data :: map,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary
|
|
) :: any
|
|
|
|
@doc """
|
|
Called when an [Account Link event](https://developers.line.biz/en/reference/messaging-api/#account-link-event)
|
|
is received.
|
|
"""
|
|
@callback handle_account_link(
|
|
data :: map,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary
|
|
) :: any
|
|
|
|
@doc """
|
|
Called when a [LINE Things Scenario Execution event](https://developers.line.biz/en/reference/messaging-api/#scenario result)
|
|
is received.
|
|
"""
|
|
@callback handle_things(
|
|
data :: map,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary
|
|
) :: any
|
|
|
|
@doc """
|
|
Called when an unknown even it received. The `type` contains the unknown event type, and the full event is passed as the `event` argument. If a reply token was not present in the event, `reply_token` will be `nil`.
|
|
"""
|
|
@callback handle_other(
|
|
type :: binary,
|
|
event :: map,
|
|
info :: EventInfo.t(),
|
|
reply_token :: binary | nil
|
|
) :: any
|
|
|
|
@optional_callbacks handle_message: 3,
|
|
handle_follow: 2,
|
|
handle_unfollow: 1,
|
|
handle_join: 2,
|
|
handle_leave: 1,
|
|
handle_member_joined: 3,
|
|
handle_member_left: 2,
|
|
handle_postback: 3,
|
|
handle_beacon: 3,
|
|
handle_account_link: 3,
|
|
handle_things: 3,
|
|
handle_other: 4
|
|
|
|
defmacro __using__(_opts) do
|
|
quote do
|
|
@behaviour LineBot
|
|
|
|
def handle_message(message, info, reply_token), do: :ok
|
|
def handle_follow(info, reply_token), do: :ok
|
|
def handle_unfollow(info), do: :ok
|
|
def handle_join(info, reply_token), do: :ok
|
|
def handle_leave(info), do: :ok
|
|
def handle_member_joined(members, info, reply_token), do: :ok
|
|
def handle_member_left(members, info), do: :ok
|
|
def handle_postback(data, info, reply_token), do: :ok
|
|
def handle_beacon(data, info, reply_token), do: :ok
|
|
def handle_account_link(data, info, reply_token), do: :ok
|
|
def handle_things(data, info, reply_token), do: :ok
|
|
def handle_other(type, event, info, reply_token), do: :ok
|
|
|
|
defoverridable LineBot
|
|
end
|
|
end
|
|
|
|
@type api_response ::
|
|
{:ok, map()}
|
|
| {:unauthorized, map()}
|
|
| {:forbidden, map()}
|
|
| {:not_found, map()}
|
|
| {:too_many_requests, map()}
|
|
| {:server_error, map()}
|
|
| {:error, HTTPoison.Error.t()}
|
|
|
|
defp try_get(uri, params \\ []) do
|
|
case @api_client.get(uri, [], params: params) do
|
|
{:ok, %{status_code: 200, body: body}} -> {:ok, body}
|
|
{:ok, %{status_code: 401, body: body}} -> {:unauthorized, body}
|
|
{:ok, %{status_code: 403, body: body}} -> {:forbidden, body}
|
|
{:ok, %{status_code: 404, body: body}} -> {:not_found, body}
|
|
{:ok, %{status_code: 429, body: body}} -> {:too_many_requests, body}
|
|
{:ok, %{status_code: 500, body: body}} -> {:server_error, body}
|
|
{:error, %HTTPoison.Error{} = error} -> {:error, error}
|
|
end
|
|
end
|
|
|
|
defp try_post(uri, data \\ %{}) do
|
|
case @api_client.post(uri, data) do
|
|
{:ok, %{status_code: 200, body: body}} -> {:ok, body}
|
|
{:ok, %{status_code: 401, body: body}} -> {:unauthorized, body}
|
|
{:ok, %{status_code: 403, body: body}} -> {:forbidden, body}
|
|
{:ok, %{status_code: 404, body: body}} -> {:not_found, body}
|
|
{:ok, %{status_code: 429, body: body}} -> {:too_many_requests, body}
|
|
{:ok, %{status_code: 500, body: body}} -> {:server_error, body}
|
|
{:error, %HTTPoison.Error{} = error} -> {:error, error}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Sends one or more [reply messages](https://developers.line.biz/en/reference/messaging-api/#send-reply-message).
|
|
"""
|
|
@spec send_reply(
|
|
reply_token :: String.t(),
|
|
messages :: [LineBot.Message.t()] | LineBot.Message.t(),
|
|
notification_disabled :: boolean()
|
|
) :: api_response()
|
|
def send_reply(reply_token, messages, notification_disabled \\ false)
|
|
|
|
def send_reply(reply_token, messages, notification_disabled) when is_list(messages) do
|
|
try_post("message/reply", %{
|
|
"replyToken" => reply_token,
|
|
"messages" => messages,
|
|
"notificationDisabled" => notification_disabled
|
|
})
|
|
end
|
|
|
|
def send_reply(to, message, notification_disabled),
|
|
do: send_reply(to, [message], notification_disabled)
|
|
|
|
@doc """
|
|
Sends one or more [push messages](https://developers.line.biz/en/reference/messaging-api/#send-push-message).
|
|
"""
|
|
@spec send_push(
|
|
to :: String.t(),
|
|
messages :: [LineBot.Message.t()] | LineBot.Message.t(),
|
|
notification_disabled :: boolean()
|
|
) :: api_response()
|
|
def send_push(to, messages, notification_disabled \\ false)
|
|
|
|
def send_push(to, messages, notification_disabled) when is_list(messages) do
|
|
try_post("message/push", %{
|
|
"to" => to,
|
|
"messages" => messages,
|
|
"notificationDisabled" => notification_disabled
|
|
})
|
|
end
|
|
|
|
def send_push(to, message, notification_disabled),
|
|
do: send_push(to, [message], notification_disabled)
|
|
|
|
@doc """
|
|
Sends one or more [multicast messages](https://developers.line.biz/en/reference/messaging-api/#send-multicast-message).
|
|
|
|
"""
|
|
@spec send_multicast(
|
|
to :: [String.t()],
|
|
messages :: [LineBot.Message.t()] | LineBot.Message.t(),
|
|
notification_disabled :: boolean()
|
|
) :: api_response()
|
|
def send_multicast(to, messages, notification_disabled \\ false)
|
|
|
|
def send_multicast(to, messages, notification_disabled)
|
|
when is_list(to) and is_list(messages) do
|
|
try_post("message/multicast", %{
|
|
"to" => to,
|
|
"messages" => messages,
|
|
"notificationDisabled" => notification_disabled
|
|
})
|
|
end
|
|
|
|
def send_multicast(to, message, notification_disabled) when is_list(to) do
|
|
send_multicast(to, [message], notification_disabled)
|
|
end
|
|
|
|
@doc """
|
|
Sends one or more [broadcast messages](https://developers.line.biz/en/reference/messaging-api/#send-broadcast-message).
|
|
"""
|
|
@spec send_broadcast(
|
|
messages :: [LineBot.Message.t()] | LineBot.Message.t(),
|
|
notification_disabled :: boolean()
|
|
) :: api_response()
|
|
def send_broadcast(messages, notification_disabled \\ false)
|
|
|
|
def send_broadcast(messages, notification_disabled) when is_list(messages) do
|
|
try_post("message/broadcast", %{
|
|
"messages" => messages,
|
|
"notificationDisabled" => notification_disabled
|
|
})
|
|
end
|
|
|
|
def send_broadcast(message, notification_disabled) do
|
|
send_broadcast([message], notification_disabled)
|
|
end
|
|
|
|
@doc """
|
|
Calls the [Get content](https://developers.line.biz/en/reference/messaging-api/#get-content) API.
|
|
"""
|
|
@spec get_content(message_id :: binary()) :: HTTPoison.Response.t()
|
|
def get_content(message_id), do: @api_client.get!("message/#{message_id}/content")
|
|
|
|
@doc """
|
|
Calls the [Get number of message deliveries](https://developers.line.biz/en/reference/messaging-api/#get-number-of-delivery-messages) API.
|
|
"""
|
|
@spec get_quota(date :: String.t()) :: api_response()
|
|
def get_quota(date), do: try_get("message/quota", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of messages sent this month](https://developers.line.biz/en/reference/messaging-api/#get-consumption) API.
|
|
"""
|
|
@spec get_quota_consumption() :: api_response()
|
|
def get_quota_consumption(), do: try_get("message/quota/consumption")
|
|
|
|
@doc """
|
|
Calls the [Get number of sent reply messages](https://developers.line.biz/en/reference/messaging-api/#get-number-of-reply-messages) API.
|
|
"""
|
|
@spec get_sent_reply_count(date :: String.t()) :: api_response()
|
|
def get_sent_reply_count(date), do: try_get("message/delivery/reply", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of sent push messages](https://developers.line.biz/en/reference/messaging-api/#get-number-of-push-messages) API.
|
|
"""
|
|
@spec get_sent_push_count(date :: String.t()) :: api_response()
|
|
def get_sent_push_count(date), do: try_get("message/delivery/push", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of sent multicast messages](https://developers.line.biz/en/reference/messaging-api/#get-number-of-multicast-messages) API.
|
|
"""
|
|
@spec get_sent_multicast_count(date :: String.t()) :: api_response()
|
|
def get_sent_multicast_count(date), do: try_get("message/delivery/multicast", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of sent broadcast messages](https://developers.line.biz/en/reference/messaging-api/#get-number-of-broadcast-messages) API.
|
|
"""
|
|
@spec get_sent_broadcast_count(date :: String.t()) :: api_response()
|
|
def get_sent_broadcast_count(date), do: try_get("message/delivery/broadcast", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of message deliveries](https://developers.line.biz/en/reference/messaging-api/#get-number-of-delivery-messages) API.
|
|
"""
|
|
@spec get_sent_message_count(date :: String.t()) :: api_response()
|
|
def get_sent_message_count(date), do: try_get("insight/message/delivery", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get number of followers](https://developers.line.biz/en/reference/messaging-api/#get-number-of-followers) API.
|
|
"""
|
|
@spec get_follower_count(date :: String.t()) :: api_response()
|
|
def get_follower_count(date), do: try_get("insight/followers", date: date)
|
|
|
|
@doc """
|
|
Calls the [Get friend demographics](https://developers.line.biz/en/reference/messaging-api/#get-demographic) API.
|
|
"""
|
|
@spec get_follower_demographics() :: api_response()
|
|
def get_follower_demographics(), do: try_get("insight/demographic")
|
|
|
|
@doc """
|
|
Calls the [Get profile](https://developers.line.biz/en/reference/messaging-api/#get-profile) API.
|
|
"""
|
|
@spec get_profile(user_id :: String.t()) :: api_response()
|
|
def get_profile(user_id), do: try_get("profile/#{user_id}")
|
|
|
|
@doc """
|
|
Calls the [Get group member user IDs](https://developers.line.biz/en/reference/messaging-api/#get-group-member-user-ids) API.
|
|
"""
|
|
@spec get_group_member_ids(group_id :: String.t(), start :: binary() | nil) :: api_response()
|
|
def get_group_member_ids(group_id, start \\ nil) do
|
|
start = if start, do: [start: start], else: []
|
|
try_get("group/#{group_id}/members/ids", start)
|
|
end
|
|
|
|
@doc """
|
|
Calls the [Get group member profile](https://developers.line.biz/en/reference/messaging-api/#get-group-member-profile) API.
|
|
"""
|
|
@spec get_group_member_profile(group_id :: String.t(), user_id :: String.t()) :: api_response()
|
|
def get_group_member_profile(group_id, user_id) do
|
|
try_get("group/#{group_id}/member/#{user_id}")
|
|
end
|
|
|
|
@doc """
|
|
Calls the [Leave group](https://developers.line.biz/en/reference/messaging-api/#leave-group) API.
|
|
"""
|
|
@spec leave_group(group_id :: String.t()) :: api_response()
|
|
def leave_group(group_id), do: try_post("group/#{group_id}/leave")
|
|
|
|
@doc """
|
|
Calls the [Get room member user IDs](https://developers.line.biz/en/reference/messaging-api/#get-room-member-user-ids) API.
|
|
"""
|
|
@spec get_room_member_ids(room_id :: String.t(), start :: binary() | nil) :: api_response()
|
|
def get_room_member_ids(room_id, start \\ nil) do
|
|
start = if start, do: [start: start], else: []
|
|
try_get("room/#{room_id}/members/ids", start)
|
|
end
|
|
|
|
@doc """
|
|
Calls the [Get room member profile](https://developers.line.biz/en/reference/messaging-api/#get-room-member-profile) API.
|
|
"""
|
|
@spec get_room_member_profile(room_id :: String.t(), user_id :: String.t()) :: api_response()
|
|
def get_room_member_profile(room_id, user_id), do: try_get("room/#{room_id}/member/#{user_id}")
|
|
|
|
@doc """
|
|
Calls the [Leave room](https://developers.line.biz/en/reference/messaging-api/#leave-room) API.
|
|
"""
|
|
@spec leave_room(room_id :: String.t()) :: api_response()
|
|
def leave_room(room_id), do: try_post("room/#{room_id}/leave")
|
|
|
|
@doc """
|
|
Calls the [Issue link token](https://developers.line.biz/en/reference/messaging-api/#issue-link-token) API.
|
|
"""
|
|
@spec issue_link_token(user_id :: String.t()) :: api_response()
|
|
def issue_link_token(user_id), do: try_post("user/#{user_id}/linkToken")
|
|
end
|