Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions libraries/Microsoft.Bot.Builder/ActivityHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class ActivityHandler : IBot
/// <see cref="OnTurnAsync(ITurnContext, CancellationToken)"/> method.
/// </remarks>
/// <seealso cref="OnMessageActivityAsync(ITurnContext{IMessageActivity}, CancellationToken)"/>
/// <seealso cref="OnMessageUpdateActivityAsync(ITurnContext{IMessageUpdateActivity}, CancellationToken)"/>
/// <seealso cref="OnMessageDeleteActivityAsync(ITurnContext{IMessageDeleteActivity}, CancellationToken)"/>
/// <seealso cref="OnConversationUpdateActivityAsync(ITurnContext{IConversationUpdateActivity}, CancellationToken)"/>
/// <seealso cref="OnMessageReactionActivityAsync(ITurnContext{IMessageReactionActivity}, CancellationToken)"/>
/// <seealso cref="OnEventActivityAsync(ITurnContext{IEventActivity}, CancellationToken)"/>
Expand Down Expand Up @@ -69,6 +71,14 @@ public class ActivityHandler : IBot
case ActivityTypes.Message:
await OnMessageActivityAsync(new DelegatingTurnContext<IMessageActivity>(turnContext), cancellationToken).ConfigureAwait(false);
break;

case ActivityTypes.MessageUpdate:
await OnMessageUpdateActivityAsync(new DelegatingTurnContext<IMessageUpdateActivity>(turnContext), cancellationToken).ConfigureAwait(false);
break;

case ActivityTypes.MessageDelete:
await OnMessageDeleteActivityAsync(new DelegatingTurnContext<IMessageDeleteActivity>(turnContext), cancellationToken).ConfigureAwait(false);
break;

case ActivityTypes.ConversationUpdate:
await OnConversationUpdateActivityAsync(new DelegatingTurnContext<IConversationUpdateActivity>(turnContext), cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -147,6 +157,42 @@ protected virtual Task OnMessageActivityAsync(ITurnContext<IMessageActivity> tur
return Task.CompletedTask;
}

/// <summary>
/// Override this in a derived class to provide logic specific to
/// <see cref="ActivityTypes.MessageUpdate"/> activities, such as the conversational logic.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
/// <remarks>
/// When the <see cref="OnTurnAsync(ITurnContext, CancellationToken)"/>
/// method receives a message update activity, it calls this method.
/// </remarks>
/// <seealso cref="OnTurnAsync(ITurnContext, CancellationToken)"/>
protected virtual Task OnMessageUpdateActivityAsync(ITurnContext<IMessageUpdateActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

/// <summary>
/// Override this in a derived class to provide logic specific to
/// <see cref="ActivityTypes.MessageDelete"/> activities, such as the conversational logic.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
/// <remarks>
/// When the <see cref="OnTurnAsync(ITurnContext, CancellationToken)"/>
/// method receives a message delete activity, it calls this method.
/// </remarks>
/// <seealso cref="OnTurnAsync(ITurnContext, CancellationToken)"/>
protected virtual Task OnMessageDeleteActivityAsync(ITurnContext<IMessageDeleteActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

/// <summary>
/// Invoked when a conversation update activity is received from the channel when the base behavior of
/// <see cref="OnTurnAsync(ITurnContext, CancellationToken)"/> is used.
Expand Down
105 changes: 105 additions & 0 deletions libraries/Microsoft.Bot.Builder/Teams/TeamsActivityHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,111 @@ protected virtual Task OnTeamsReadReceiptAsync(ReadReceiptInfo readReceiptInfo,
return Task.CompletedTask;
}

/// <summary>
/// Invoked when an message update activity is received.
/// <see cref="ActivityTypes.MessageUpdate"/> activities, such as the conversational logic.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
/// <remarks>
/// In a derived class, override this method to add logic that applies to all message update activities.
/// </remarks>
protected override Task OnMessageUpdateActivityAsync(ITurnContext<IMessageUpdateActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.ChannelId == Channels.Msteams)
{
var channelData = turnContext.Activity.GetChannelData<TeamsChannelData>();

if (channelData != null)
{
switch (channelData.EventType)
{
case "editMessage":
return OnTeamsMessageEditAsync(turnContext, cancellationToken);

case "undeleteMessage":
return OnTeamsMessageUndeleteAsync(turnContext, cancellationToken);

default:
return base.OnMessageUpdateActivityAsync(turnContext, cancellationToken);
}
}
}

return base.OnMessageUpdateActivityAsync(turnContext, cancellationToken);
}

/// <summary>
/// Invoked when an message delete activity is received.
/// <see cref="ActivityTypes.MessageDelete"/> activities, such as the conversational logic.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
/// <remarks>
/// In a derived class, override this method to add logic that applies to all message update activities.
/// </remarks>
protected override Task OnMessageDeleteActivityAsync(ITurnContext<IMessageDeleteActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.ChannelId == Channels.Msteams)
{
var channelData = turnContext.Activity.GetChannelData<TeamsChannelData>();

if (channelData != null)
{
switch (channelData.EventType)
{
case "softDeleteMessage":
return OnTeamsMessageSoftDeleteAsync(turnContext, cancellationToken);

default:
return base.OnMessageDeleteActivityAsync(turnContext, cancellationToken);
}
}
}

return base.OnMessageDeleteActivityAsync(turnContext, cancellationToken);
}

/// <summary>
/// Invoked when a edit message event activity is received.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
protected virtual Task OnTeamsMessageEditAsync(ITurnContext<IMessageUpdateActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

/// <summary>
/// Invoked when a undo soft delete message event activity is received.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
protected virtual Task OnTeamsMessageUndeleteAsync(ITurnContext<IMessageUpdateActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

/// <summary>
/// Invoked when a soft delete message event activity is received.
/// </summary>
/// <param name="turnContext">A strongly-typed context object for this turn.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns>
protected virtual Task OnTeamsMessageSoftDeleteAsync(ITurnContext<IMessageDeleteActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

/// <summary>
/// Safely casts an object to an object of type <typeparamref name="T"/> .
/// </summary>
Expand Down
44 changes: 44 additions & 0 deletions tests/Microsoft.Bot.Builder.Tests/ActivityHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,38 @@ public async Task TestMessageActivity()
Assert.Equal("OnMessageActivityAsync", bot.Record[0]);
}

[Fact]
public async Task TestMessageUpdateActivity()
{
// Arrange
var activity = new Activity { Type = ActivityTypes.MessageUpdate };
var turnContext = new TurnContext(new NotImplementedAdapter(), activity);

// Act
var bot = new TestActivityHandler();
await ((IBot)bot).OnTurnAsync(turnContext);

// Assert
Assert.Single(bot.Record);
Assert.Equal("OnMessageUpdateActivityAsync", bot.Record[0]);
}

[Fact]
public async Task TestMessageDeleteActivity()
{
// Arrange
var activity = new Activity { Type = ActivityTypes.MessageDelete };
var turnContext = new TurnContext(new NotImplementedAdapter(), activity);

// Act
var bot = new TestActivityHandler();
await ((IBot)bot).OnTurnAsync(turnContext);

// Assert
Assert.Single(bot.Record);
Assert.Equal("OnMessageDeleteActivityAsync", bot.Record[0]);
}

[Fact]
public async Task TestEndOfConversationActivity()
{
Expand Down Expand Up @@ -798,6 +830,18 @@ protected override Task OnMessageActivityAsync(ITurnContext<IMessageActivity> tu
return base.OnMessageActivityAsync(turnContext, cancellationToken);
}

protected override Task OnMessageUpdateActivityAsync(ITurnContext<IMessageUpdateActivity> turnContext, CancellationToken cancellationToken)
{
Record.Add(MethodBase.GetCurrentMethod().Name);
return base.OnMessageUpdateActivityAsync(turnContext, cancellationToken);
}

protected override Task OnMessageDeleteActivityAsync(ITurnContext<IMessageDeleteActivity> turnContext, CancellationToken cancellationToken)
{
Record.Add(MethodBase.GetCurrentMethod().Name);
return base.OnMessageDeleteActivityAsync(turnContext, cancellationToken);
}

protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
Record.Add(MethodBase.GetCurrentMethod().Name);
Expand Down
Loading