defmodule ExMicrosoftBot.Client.Conversations do
@moduledoc """
This module provides the functions for conversations
"""
import ExMicrosoftBot.Client,
only: [deserialize_response: 2, delete: 1, get: 1, post: 2, put: 2]
alias ExMicrosoftBot.Models
alias ExMicrosoftBot.Client
@doc """
Create a new Conversation.
@see [API Reference](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#conversation-object)
"""
@spec create_conversation(
service_url :: String.t(),
params :: Models.ConversationParameters.t()
) :: {:ok, Models.ConversationResourceResponse.t()} | Client.error_type()
def create_conversation(service_url, %Models.ConversationParameters{} = params) do
service_url
|> conversations_url()
|> post(params)
|> deserialize_response(&Models.ConversationResourceResponse.parse/1)
end
@doc """
This method allows you to send an activity to a conversation regardless of
previous posts to a conversation.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_SendToConversation)
"""
@spec send_to_conversation(conversation_id :: String.t(), activity :: Models.Activity.t()) ::
{:ok, Models.ResourceResponse.t()} | Client.error_type()
def send_to_conversation(conversation_id, %Models.Activity{serviceUrl: service_url} = activity),
do: send_to_conversation(service_url, conversation_id, activity)
@doc """
This method allows you to send an activity to a conversation regardless of
previous posts to a conversation.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_SendToConversation)
"""
@spec send_to_conversation(
service_url :: String.t(),
conversation_id :: String.t(),
activity :: Models.Activity.t()
) :: {:ok, Models.ResourceResponse.t()} | Client.error_type()
def send_to_conversation(service_url, conversation_id, %Models.Activity{} = activity) do
service_url
|> conversations_url("/#{conversation_id}/activities")
|> post(activity)
|> deserialize_response(&Models.ResourceResponse.parse/1)
end
@doc """
This method allows you to reply to an activity.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_ReplyToActivity)
"""
@spec reply_to_activity(
conversation_id :: String.t(),
activity_id :: String.t(),
activity :: Models.Activity.t()
) :: {:ok, Models.ResourceResponse.t()} | Client.error_type()
def reply_to_activity(
conversation_id,
activity_id,
%Models.Activity{serviceUrl: service_url} = activity
),
do: reply_to_activity(service_url, conversation_id, activity_id, activity)
@doc """
This method allows you to reply to an activity.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_ReplyToActivity)
"""
@spec reply_to_activity(
service_url :: String.t(),
conversation_id :: String.t(),
activity_id :: String.t(),
activity :: Models.Activity.t()
) :: {:ok, Models.ResourceResponse.t()} | Client.error_type()
def reply_to_activity(service_url, conversation_id, activity_id, %Models.Activity{} = activity) do
service_url
|> conversations_url("/#{conversation_id}/activities/#{activity_id}")
|> post(activity)
|> deserialize_response(&Models.ResourceResponse.parse/1)
end
@doc """
This function takes a ConversationId and returns an array of ChannelAccount[]
objects which are the members of the conversation.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_GetConversationMembers).
When ActivityId is passed in then it returns the members of the particular
activity in the conversation.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_GetActivityMembers)
"""
@spec get_members(
service_url :: String.t(),
conversation_id :: String.t(),
activity_id :: String.t() | nil
) :: {:ok, [Models.ChannelAccount.t()]} | Client.error_type()
def get_members(service_url, conversation_id, activity_id \\ nil) do
path =
if activity_id,
do: "/#{conversation_id}/activities/#{activity_id}/members",
else: "/#{conversation_id}/members"
service_url
|> conversations_url(path)
|> get()
|> deserialize_response(&Models.ChannelAccount.parse/1)
end
@doc """
This function takes a conversation ID and a member ID and returns a
ChannelAccount struct for that member of the conversation.
@see [API Reference](https://github.com/microsoft/botbuilder-js/blob/5b164105a2f289baaa7b89829e09ddbeda88bfc5/libraries/botframework-connector/src/connectorApi/operations/conversations.ts#L733-L749).
"""
@spec get_member(
service_url :: String.t(),
conversation_id :: String.t(),
member_id :: String.t()
) :: {:ok, Models.ChannelAccount.t()} | Client.error_type()
def get_member(service_url, conversation_id, member_id) do
service_url
|> conversations_url("/#{conversation_id}/members/#{member_id}")
|> get()
|> deserialize_response(&Models.ChannelAccount.parse/1)
end
@doc """
This method allows you to upload an attachment directly into a channels blob
storage.
@see [API Reference](https://docs.botframework.com/en-us/restapi/connector/#!/Conversations/Conversations_UploadAttachment)
"""
@spec upload_attachment(
service_url :: String.t(),
conversation_id :: String.t(),
attachment :: Models.AttachmentData.t()
) :: {:ok, Models.ResourceResponse.t()} | Client.error_type()
def upload_attachment(service_url, conversation_id, %Models.AttachmentData{} = attachment) do
service_url
|> conversations_url("/#{conversation_id}/attachments")
|> post(attachment)
|> deserialize_response(&Models.ResourceResponse.parse/1)
end
@doc """
Updates an existing activity. The activity struct is expected to have an ID.
@see [API Reference](https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#update-activity)
"""
@spec update_activity(
service_url :: String.t(),
conversation_id :: String.t(),
activity :: Models.Activity.t()
) :: {:ok, Models.ResourceResponse.t()} | Client.error_type()
def update_activity(service_url, conversation_id, %Models.Activity{id: activity_id} = activity) do
service_url
|> conversations_url("/#{conversation_id}/activities/#{activity_id}")
|> put(activity)
|> deserialize_response(&Models.ResourceResponse.parse/1)
end
@doc """
Deletes an existing activity. The returned content will always be empty.
@see [API Reference](https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/update-and-delete-bot-messages?tabs=rest#deleting-messages)
"""
@spec delete_activity(
service_url :: String.t(),
conversation_id :: String.t(),
activity_or_id :: Models.Activity.t() | String.t()
) :: {:ok, binary()} | Client.error_type()
def delete_activity(service_url, conversation_id, %Models.Activity{id: activity_id}),
do: delete_activity(service_url, conversation_id, activity_id)
def delete_activity(service_url, conversation_id, activity_id) do
service_url
|> conversations_url("/#{conversation_id}/activities/#{activity_id}")
|> delete()
|> deserialize_response(nil)
end
defp conversations_url(service_url) do
service_url = String.trim_trailing(service_url, "/")
"#{service_url}/v3/conversations"
end
defp conversations_url(service_url, path),
do: conversations_url(service_url) <> path
end