// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder
{
///
/// Base class for Bot Framework protocol implementation.
///
public abstract class ChannelServiceHandlerBase
{
///
/// Sends an activity to the end of a conversation.
///
/// The authentication header.
/// The conversation Id.
/// The activity to send.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleSendToConversationAsync(string authHeader, string conversationId, Activity activity, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnSendToConversationAsync(claimsIdentity, conversationId, activity, cancellationToken).ConfigureAwait(false);
}
///
/// Sends a reply to an activity.
///
/// The authentication header.
/// The conversation Id.
/// The activity Id the reply is to.
/// The activity to send.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleReplyToActivityAsync(string authHeader, string conversationId, string activityId, Activity activity, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnReplyToActivityAsync(claimsIdentity, conversationId, activityId, activity, cancellationToken).ConfigureAwait(false);
}
///
/// Edits a previously sent existing activity.
///
/// The authentication header.
/// The conversation Id.
/// The activity Id to update.
/// The replacement activity.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleUpdateActivityAsync(string authHeader, string conversationId, string activityId, Activity activity, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnUpdateActivityAsync(claimsIdentity, conversationId, activityId, activity, cancellationToken).ConfigureAwait(false);
}
///
/// Deletes an existing activity.
///
/// The authentication header.
/// The conversation Id.
/// The activity Id.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleDeleteActivityAsync(string authHeader, string conversationId, string activityId, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
await OnDeleteActivityAsync(claimsIdentity, conversationId, activityId, cancellationToken).ConfigureAwait(false);
}
///
/// Enumerates the members of an activity.
///
/// The authentication header.
/// The conversation Id.
/// The activity Id.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task> HandleGetActivityMembersAsync(string authHeader, string conversationId, string activityId, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnGetActivityMembersAsync(claimsIdentity, conversationId, activityId, cancellationToken).ConfigureAwait(false);
}
///
/// Create a new Conversation.
///
/// The authentication header.
/// Parameters to create the conversation from.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleCreateConversationAsync(string authHeader, ConversationParameters parameters, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnCreateConversationAsync(claimsIdentity, parameters, cancellationToken).ConfigureAwait(false);
}
///
/// Lists the Conversations in which the bot has participated.
///
/// The authentication header.
/// The conversation Id.
/// A skip or continuation token.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleGetConversationsAsync(string authHeader, string conversationId, string continuationToken = default, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnGetConversationsAsync(claimsIdentity, conversationId, continuationToken, cancellationToken).ConfigureAwait(false);
}
///
/// Enumerates the members of a conversation.
///
/// The authentication header.
/// The conversation Id.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task> HandleGetConversationMembersAsync(string authHeader, string conversationId, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnGetConversationMembersAsync(claimsIdentity, conversationId, cancellationToken).ConfigureAwait(false);
}
///
/// Gets the account of a single conversation member.
///
/// The authentication header.
/// The user id.
/// The conversation Id.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleGetConversationMemberAsync(string authHeader, string userId, string conversationId, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnGetConversationMemberAsync(claimsIdentity, userId, conversationId, cancellationToken).ConfigureAwait(false);
}
///
/// Enumerates the members of a conversation one page at a time.
///
/// The authentication header.
/// The conversation Id.
/// Suggested page size.
/// A continuation token.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleGetConversationPagedMembersAsync(string authHeader, string conversationId, int? pageSize = default, string continuationToken = default, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnGetConversationPagedMembersAsync(claimsIdentity, conversationId, pageSize, continuationToken, cancellationToken).ConfigureAwait(false);
}
///
/// Deletes a member from a conversation.
///
/// The authentication header.
/// The conversation Id.
/// Id of the member to delete from this conversation.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the asynchronous operation.
public async Task HandleDeleteConversationMemberAsync(string authHeader, string conversationId, string memberId, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
await OnDeleteConversationMemberAsync(claimsIdentity, conversationId, memberId, cancellationToken).ConfigureAwait(false);
}
///
/// Uploads the historic activities of the conversation.
///
/// The authentication header.
/// The conversation Id.
/// Transcript of activities.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleSendConversationHistoryAsync(string authHeader, string conversationId, Transcript transcript, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnSendConversationHistoryAsync(claimsIdentity, conversationId, transcript, cancellationToken).ConfigureAwait(false);
}
///
/// Stores data in a compliant store when dealing with enterprises.
///
/// The authentication header.
/// The conversation Id.
/// Attachment data.
/// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
/// A representing the result of the asynchronous operation.
public async Task HandleUploadAttachmentAsync(string authHeader, string conversationId, AttachmentData attachmentUpload, CancellationToken cancellationToken = default)
{
var claimsIdentity = await AuthenticateAsync(authHeader, cancellationToken).ConfigureAwait(false);
return await OnUploadAttachmentAsync(claimsIdentity, conversationId, attachmentUpload, cancellationToken).ConfigureAwait(false);
}
///
/// Helper to authenticate the header token and extract the claims.
///
/// The auth header containing JWT token.
/// A cancellation token.
/// A representing the claims associated with given header.
internal abstract Task AuthenticateAsync(string authHeader, CancellationToken cancellationToken);
///
/// SendToConversation() API for Skill.
///
///
/// This method allows you to send an activity to the end of a conversation.
///
/// This is slightly different from ReplyToActivity().
/// * SendToConversation(conversationId) - will append the activity to the end
/// of the conversation according to the timestamp or semantics of the channel.
/// * ReplyToActivity(conversationId,ActivityId) - adds the activity as a reply
/// to another activity, if the channel supports it. If the channel does not
/// support nested replies, ReplyToActivity falls back to SendToConversation.
///
/// Use ReplyToActivity when replying to a specific activity in the
/// conversation.
///
/// Use SendToConversation in all other cases.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// conversationId.
/// Activity to send.
/// The cancellation token.
/// task for a resource response.
protected virtual Task OnSendToConversationAsync(ClaimsIdentity claimsIdentity, string conversationId, Activity activity, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// OnReplyToActivityAsync() API.
///
///
/// Override this method allows to reply to an Activity.
///
/// This is slightly different from SendToConversation().
/// * SendToConversation(conversationId) - will append the activity to the end
/// of the conversation according to the timestamp or semantics of the channel.
/// * ReplyToActivity(conversationId,ActivityId) - adds the activity as a reply
/// to another activity, if the channel supports it. If the channel does not
/// support nested replies, ReplyToActivity falls back to SendToConversation.
///
/// Use ReplyToActivity when replying to a specific activity in the
/// conversation.
///
/// Use SendToConversation in all other cases.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// activityId the reply is to (OPTIONAL).
/// Activity to send.
/// The cancellation token.
/// task for a resource response.
protected virtual Task OnReplyToActivityAsync(ClaimsIdentity claimsIdentity, string conversationId, string activityId, Activity activity, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// OnUpdateActivityAsync() API.
///
///
/// Override this method to edit a previously sent existing activity.
///
/// Some channels allow you to edit an existing activity to reflect the new
/// state of a bot conversation.
///
/// For example, you can remove buttons after someone has clicked "Approve"
/// button.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// activityId to update.
/// replacement Activity.
/// The cancellation token.
/// task for a resource response.
protected virtual Task OnUpdateActivityAsync(ClaimsIdentity claimsIdentity, string conversationId, string activityId, Activity activity, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// OnDeleteActivityAsync() API.
///
///
/// Override this method to Delete an existing activity.
///
/// Some channels allow you to delete an existing activity, and if successful
/// this method will remove the specified activity.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// activityId to delete.
/// The cancellation token.
/// task for a resource response.
protected virtual Task OnDeleteActivityAsync(ClaimsIdentity claimsIdentity, string conversationId, string activityId, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// OnGetActivityMembersAsync() API.
///
///
/// Override this method to enumerate the members of an activity.
///
/// This REST API takes a ConversationId and a ActivityId, returning an array
/// of ChannelAccount objects representing the members of the particular
/// activity in the conversation.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// Activity ID.
/// The cancellation token.
/// task with result.
protected virtual Task> OnGetActivityMembersAsync(ClaimsIdentity claimsIdentity, string conversationId, string activityId, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// CreateConversation() API.
///
///
/// Override this method to create a new Conversation.
///
/// POST to this method with a
/// * Bot being the bot creating the conversation
/// * IsGroup set to true if this is not a direct message (default is false)
/// * Array containing the members to include in the conversation
///
/// The return value is a ResourceResponse which contains a conversation ID
/// which is suitable for use
/// in the message payload and REST API URIs.
///
/// Most channels only support the semantics of bots initiating a direct
/// message conversation. An example of how to do that would be:
///
/// var resource = await connector.conversations.CreateConversation(new
/// ConversationParameters(){ Bot = bot, members = new ChannelAccount[] { new
/// ChannelAccount("user1") } );
/// await connect.Conversations.OnSendToConversationAsync(resource.Id, new
/// Activity() ... ) ;
///
/// end.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Parameters to create the conversation from.
/// The cancellation token.
/// task for a conversation resource response.
protected virtual Task OnCreateConversationAsync(ClaimsIdentity claimsIdentity, ConversationParameters parameters, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// OnGetConversationsAsync() API for Skill.
///
///
/// Override this method to list the Conversations in which this bot has participated.
///
/// GET from this method with a skip token
///
/// The return value is a ConversationsResult, which contains an array of
/// ConversationMembers and a skip token. If the skip token is not empty, then
/// there are further values to be returned. Call this method again with the
/// returned token to get more values.
///
/// Each ConversationMembers object contains the ID of the conversation and an
/// array of ChannelAccounts that describe the members of the conversation.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// conversationId.
/// skip or continuation token.
/// The cancellation token.
/// task for ConversationsResult.
protected virtual Task OnGetConversationsAsync(ClaimsIdentity claimsIdentity, string conversationId, string continuationToken = default, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// GetConversationMembers() API for Skill.
///
///
/// Override this method to enumerate the members of a conversation.
///
/// This REST API takes a ConversationId and returns an array of ChannelAccount
/// objects representing the members of the conversation.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// The cancellation token.
/// task for a response.
protected virtual Task> OnGetConversationMembersAsync(ClaimsIdentity claimsIdentity, string conversationId, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// GetConversationMember() API for Skill.
///
///
/// Override this method to get the account of a single conversation member.
///
/// This REST API takes a ConversationId and UserId and returns the ChannelAccount
/// objects representing the member of the conversation.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// User ID.
/// Conversation ID.
/// The cancellation token.
/// task for a response.
protected virtual Task OnGetConversationMemberAsync(ClaimsIdentity claimsIdentity, string userId, string conversationId, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// GetConversationPagedMembers() API for Skill.
///
///
/// Override this method to enumerate the members of a conversation one page at a time.
///
/// This REST API takes a ConversationId. Optionally a pageSize and/or
/// continuationToken can be provided. It returns a PagedMembersResult, which
/// contains an array
/// of ChannelAccounts representing the members of the conversation and a
/// continuation token that can be used to get more values.
///
/// One page of ChannelAccounts records are returned with each call. The number
/// of records in a page may vary between channels and calls. The pageSize
/// parameter can be used as
/// a suggestion. If there are no additional results the response will not
/// contain a continuation token. If there are no members in the conversation
/// the Members will be empty or not present in the response.
///
/// A response to a request that has a continuation token from a prior request
/// may rarely return members from a previous request.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// Suggested page size.
/// Continuation Token.
/// The cancellation token.
/// task for a response.
protected virtual Task OnGetConversationPagedMembersAsync(ClaimsIdentity claimsIdentity, string conversationId, int? pageSize = default, string continuationToken = default, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// DeleteConversationMember() API for Skill.
///
///
/// Override this method to deletes a member from a conversation.
///
/// This REST API takes a ConversationId and a memberId (of type string) and
/// removes that member from the conversation. If that member was the last
/// member
/// of the conversation, the conversation will also be deleted.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// ID of the member to delete from this conversation.
/// The cancellation token.
/// task.
protected virtual Task OnDeleteConversationMemberAsync(ClaimsIdentity claimsIdentity, string conversationId, string memberId, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// SendConversationHistory() API for Skill.
///
///
/// Override this method to this method allows you to upload the historic activities to the conversation.
///
/// Sender must ensure that the historic activities have unique ids and
/// appropriate timestamps. The ids are used by the client to deal with
/// duplicate activities and the timestamps are used by the client to render
/// the activities in the right order.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// Transcript of activities.
/// The cancellation token.
/// task for a resource response.
protected virtual Task OnSendConversationHistoryAsync(ClaimsIdentity claimsIdentity, string conversationId, Transcript transcript, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
///
/// UploadAttachment() API.
///
///
///
/// Override this method to store data in a compliant store when dealing with enterprises.
///
/// The response is a ResourceResponse which contains an AttachmentId which is
/// suitable for using with the attachments API.
///
/// claimsIdentity for the bot, should have AudienceClaim, AppIdClaim and ServiceUrlClaim.
/// Conversation ID.
/// Attachment data.
/// The cancellation token.
/// task with result.
protected virtual Task OnUploadAttachmentAsync(ClaimsIdentity claimsIdentity, string conversationId, AttachmentData attachmentUpload, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
}