diff --git a/libraries/Microsoft.Bot.Builder/Teams/TeamsActivityHandler.cs b/libraries/Microsoft.Bot.Builder/Teams/TeamsActivityHandler.cs index 6a66d42a22..06b57931db 100644 --- a/libraries/Microsoft.Bot.Builder/Teams/TeamsActivityHandler.cs +++ b/libraries/Microsoft.Bot.Builder/Teams/TeamsActivityHandler.cs @@ -92,6 +92,12 @@ protected override async Task OnInvokeActivityAsync(ITurnContext case "tab/submit": return CreateInvokeResponse(await OnTeamsTabSubmitAsync(turnContext, SafeCast(turnContext.Activity.Value), cancellationToken).ConfigureAwait(false)); + case "config/fetch": + return CreateInvokeResponse(await OnTeamsConfigFetchAsync(turnContext, turnContext.Activity.Value as JObject, cancellationToken).ConfigureAwait(false)); + + case "config/submit": + return CreateInvokeResponse(await OnTeamsConfigSubmitAsync(turnContext, turnContext.Activity.Value as JObject, cancellationToken).ConfigureAwait(false)); + default: return await base.OnInvokeActivityAsync(turnContext, cancellationToken).ConfigureAwait(false); } @@ -431,6 +437,32 @@ protected virtual Task OnTeamsTabSubmitAsync(ITurnContext + /// Override this in a derived class to provide logic for when a config is fetched. + /// + /// A strongly-typed context object for this turn. + /// The config fetch invoke request value payload. + /// A cancellation token that can be used by other objects + /// or threads to receive notice of cancellation. + /// A Config Response for the request. + protected virtual Task OnTeamsConfigFetchAsync(ITurnContext turnContext, JObject configData, CancellationToken cancellationToken) + { + throw new InvokeResponseException(HttpStatusCode.NotImplemented); + } + + /// + /// Override this in a derived class to provide logic for when a config is submitted. + /// + /// A strongly-typed context object for this turn. + /// The config fetch invoke request value payload. + /// A cancellation token that can be used by other objects + /// or threads to receive notice of cancellation. + /// A Config Response for the request. + protected virtual Task OnTeamsConfigSubmitAsync(ITurnContext turnContext, JObject configData, CancellationToken cancellationToken) + { + throw new InvokeResponseException(HttpStatusCode.NotImplemented); + } + /// /// Invoked when a conversation update activity is received from the channel. /// Conversation update activities are useful when it comes to responding to users being added to or removed from the channel. diff --git a/libraries/Microsoft.Bot.Schema/Teams/BotConfigAuth.cs b/libraries/Microsoft.Bot.Schema/Teams/BotConfigAuth.cs new file mode 100644 index 0000000000..2574fd123a --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/Teams/BotConfigAuth.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +using Newtonsoft.Json; + +namespace Microsoft.Bot.Schema.Teams +{ + /// + /// Specifies bot config auth, including type and suggestedActions. + /// + public partial class BotConfigAuth + { + /// + /// Initializes a new instance of the class. + /// + public BotConfigAuth() + { + CustomInit(); + } + + /// + /// Gets or sets type of bot config auth. + /// + /// + /// The type of bot config auth. + /// + [JsonProperty(PropertyName = "type")] + public string Type { get; set; } = "auth"; + + /// + /// Gets or sets suggested actions. + /// + /// + /// The suggested actions of bot config auth. + /// + [JsonProperty(PropertyName = "suggestedActions")] + public SuggestedActions SuggestedActions { get; set; } + + /// + /// An initialization method that performs custom operations like setting defaults. + /// + partial void CustomInit(); + } +} diff --git a/libraries/Microsoft.Bot.Schema/Teams/ConfigAuthResponse.cs b/libraries/Microsoft.Bot.Schema/Teams/ConfigAuthResponse.cs new file mode 100644 index 0000000000..e6992d3b72 --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/Teams/ConfigAuthResponse.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Bot.Schema.Teams +{ + /// + /// Envelope for Config Auth Response. + /// + public partial class ConfigAuthResponse : ConfigResponse + { + /// + /// Initializes a new instance of the class. + /// + public ConfigAuthResponse() + { + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults. + /// + partial void CustomInit(); + } +} diff --git a/libraries/Microsoft.Bot.Schema/Teams/ConfigResponse.cs b/libraries/Microsoft.Bot.Schema/Teams/ConfigResponse.cs new file mode 100644 index 0000000000..366b6fb3d7 --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/Teams/ConfigResponse.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Bot.Schema.Teams +{ + using Newtonsoft.Json; + + /// + /// Envelope for Config Response Payload. + /// + /// The first generic type parameter.. + public partial class ConfigResponse : ConfigResponseBase + { + /// + /// Initializes a new instance of the class. + /// + public ConfigResponse() + : base("config") + { + CustomInit(); + } + + /// + /// Gets or sets the response to the config message. + /// Possible values for the config type include: 'auth'or 'task'. + /// + /// + /// Response to a config request. + /// + [JsonProperty(PropertyName = "config")] + public T Config { get; set; } + + /// + /// Gets or sets response cache Info. + /// + /// Value of cache info. + [JsonProperty(PropertyName = "cacheInfo")] + public CacheInfo CacheInfo { get; set; } + + /// + /// An initialization method that performs custom operations like setting defaults. + /// + partial void CustomInit(); + } +} diff --git a/libraries/Microsoft.Bot.Schema/Teams/ConfigResponseBase.cs b/libraries/Microsoft.Bot.Schema/Teams/ConfigResponseBase.cs new file mode 100644 index 0000000000..b2a7eb9fa3 --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/Teams/ConfigResponseBase.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Newtonsoft.Json; + +namespace Microsoft.Bot.Schema.Teams +{ + /// + /// Specifies Invoke response base including response type. + /// + public partial class ConfigResponseBase + { + /// + /// Initializes a new instance of the class. + /// + protected ConfigResponseBase() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// response type for invoke. + protected ConfigResponseBase(string responseType) + { + ResponseType = responseType; + } + + /// + /// Gets or sets response type invoke request. + /// + /// Invoke request response type. + [JsonProperty("responseType")] + public string ResponseType { get; set; } + } +} diff --git a/libraries/Microsoft.Bot.Schema/Teams/ConfigTaskResponse.cs b/libraries/Microsoft.Bot.Schema/Teams/ConfigTaskResponse.cs new file mode 100644 index 0000000000..04252c6716 --- /dev/null +++ b/libraries/Microsoft.Bot.Schema/Teams/ConfigTaskResponse.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Bot.Schema.Teams +{ + /// + /// Envelope for Config Task Response. + /// + public partial class ConfigTaskResponse : ConfigResponse + { + /// + /// Initializes a new instance of the class. + /// + public ConfigTaskResponse() + { + CustomInit(); + } + + /// + /// An initialization method that performs custom operations like setting defaults. + /// + partial void CustomInit(); + } +} diff --git a/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerNotImplementedTests.cs b/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerNotImplementedTests.cs index e01a6fcaa3..2d3650573a 100644 --- a/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerNotImplementedTests.cs +++ b/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerNotImplementedTests.cs @@ -484,6 +484,66 @@ void CaptureSend(Activity[] arg) Assert.Equal(501, ((InvokeResponse)activitiesToSend[0].Value).Status); } + [Fact] + public async Task TestConfigFetch() + { + // Arrange + var activity = new Activity + { + Type = ActivityTypes.Invoke, + Name = "config/fetch", + Value = JObject.Parse(@"{""data"":{""key"":""value"",""type"":""config / fetch""},""context"":{""theme"":""default""}}"), + }; + + Activity[] activitiesToSend = null; + void CaptureSend(Activity[] arg) + { + activitiesToSend = arg; + } + + var turnContext = new TurnContext(new SimpleAdapter(CaptureSend), activity); + + // Act + var bot = new TestActivityHandler(); + await ((IBot)bot).OnTurnAsync(turnContext); + + // Assert + Assert.NotNull(activitiesToSend); + Assert.Single(activitiesToSend); + Assert.IsType(activitiesToSend[0].Value); + Assert.Equal(501, ((InvokeResponse)activitiesToSend[0].Value).Status); + } + + [Fact] + public async Task TestConfigSubmit() + { + // Arrange + var activity = new Activity + { + Type = ActivityTypes.Invoke, + Name = "config/submit", + Value = JObject.Parse(@"{""data"":{""key"":""value"",""type"":""config / submit""},""context"":{""theme"":""default""}}"), + }; + + Activity[] activitiesToSend = null; + void CaptureSend(Activity[] arg) + { + activitiesToSend = arg; + } + + var turnContext = new TurnContext(new SimpleAdapter(CaptureSend), activity); + + // Act + var bot = new TestActivityHandler(); + await ((IBot)bot).OnTurnAsync(turnContext); + + // Assert + Assert.NotNull(activitiesToSend); + Assert.Single(activitiesToSend); + Assert.IsType(activitiesToSend[0].Value); + Assert.Equal(501, ((InvokeResponse)activitiesToSend[0].Value).Status); + } + [Fact] public async Task TestFileConsentAcceptImplemented() { diff --git a/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerTests.cs b/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerTests.cs index 243f4cb1e2..f13d0326d0 100644 --- a/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerTests.cs +++ b/tests/Microsoft.Bot.Builder.Tests/Teams/TeamsActivityHandlerTests.cs @@ -1052,6 +1052,72 @@ void CaptureSend(Activity[] arg) Assert.Equal(200, ((InvokeResponse)activitiesToSend[0].Value).Status); } + [Fact] + public async Task TestConfigFetch() + { + // Arrange + var activity = new Activity + { + Type = ActivityTypes.Invoke, + Name = "config/fetch", + Value = JObject.Parse(@"{""data"":{""key"":""value"",""type"":""config / fetch""},""context"":{""theme"":""default""}}"), + }; + + Activity[] activitiesToSend = null; + void CaptureSend(Activity[] arg) + { + activitiesToSend = arg; + } + + var turnContext = new TurnContext(new SimpleAdapter(CaptureSend), activity); + + // Act + var bot = new TestActivityHandler(); + await ((IBot)bot).OnTurnAsync(turnContext); + + // Assert + Assert.Equal(2, bot.Record.Count); + Assert.Equal("OnInvokeActivityAsync", bot.Record[0]); + Assert.Equal("OnTeamsConfigFetchAsync", bot.Record[1]); + Assert.NotNull(activitiesToSend); + Assert.Single(activitiesToSend); + Assert.IsType(activitiesToSend[0].Value); + Assert.Equal(200, ((InvokeResponse)activitiesToSend[0].Value).Status); + } + + [Fact] + public async Task TestConfigSubmit() + { + // Arrange + var activity = new Activity + { + Type = ActivityTypes.Invoke, + Name = "config/submit", + Value = JObject.Parse(@"{""data"":{""key"":""value"",""type"":""config / submit""},""context"":{""theme"":""default""}}"), + }; + + Activity[] activitiesToSend = null; + void CaptureSend(Activity[] arg) + { + activitiesToSend = arg; + } + + var turnContext = new TurnContext(new SimpleAdapter(CaptureSend), activity); + + // Act + var bot = new TestActivityHandler(); + await ((IBot)bot).OnTurnAsync(turnContext); + + // Assert + Assert.Equal(2, bot.Record.Count); + Assert.Equal("OnInvokeActivityAsync", bot.Record[0]); + Assert.Equal("OnTeamsConfigSubmitAsync", bot.Record[1]); + Assert.NotNull(activitiesToSend); + Assert.Single(activitiesToSend); + Assert.IsType(activitiesToSend[0].Value); + Assert.Equal(200, ((InvokeResponse)activitiesToSend[0].Value).Status); + } + [Fact] public async Task TestSigninVerifyState() { @@ -1609,6 +1675,20 @@ protected override Task OnTeamsTabSubmitAsync(ITurnContext OnTeamsConfigFetchAsync(ITurnContext turnContext, JObject configRequest, CancellationToken cancellationToken) + { + ConfigResponseBase configResponse = new ConfigTaskResponse(); + Record.Add(MethodBase.GetCurrentMethod().Name); + return Task.FromResult(configResponse); + } + + protected override Task OnTeamsConfigSubmitAsync(ITurnContext turnContext, JObject configRequest, CancellationToken cancellationToken) + { + ConfigResponseBase configResponse = new ConfigTaskResponse(); + Record.Add(MethodBase.GetCurrentMethod().Name); + return Task.FromResult(configResponse); + } + protected override Task OnEventActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { Record.Add(MethodBase.GetCurrentMethod().Name); diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/BotConfigAuthTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/BotConfigAuthTests.cs new file mode 100644 index 0000000000..e11ab86087 --- /dev/null +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/BotConfigAuthTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Schema.Teams; +using Xunit; + +namespace Microsoft.Bot.Schema.Tests.Teams +{ + public class BotConfigAuthTests + { + [Fact] + public void BotConfigAuthInitsWithNoArgs() + { + var botConfigAuthResponse = new BotConfigAuth(); + + Assert.NotNull(botConfigAuthResponse); + Assert.IsType(botConfigAuthResponse); + Assert.Equal("auth", botConfigAuthResponse.Type); + } + } +} diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigAuthResponseTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigAuthResponseTests.cs new file mode 100644 index 0000000000..f7c3522793 --- /dev/null +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigAuthResponseTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Schema.Teams; +using Xunit; + +namespace Microsoft.Bot.Schema.Tests.Teams +{ + public class ConfigAuthResponseTests + { + [Fact] + public void ConfigAuthResponseInitWithNoArgs() + { + var configAuthResponse = new ConfigAuthResponse(); + + Assert.NotNull(configAuthResponse); + Assert.IsType(configAuthResponse); + Assert.Equal("config", configAuthResponse.ResponseType); + } + } +} diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigResponseTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigResponseTests.cs new file mode 100644 index 0000000000..120a991643 --- /dev/null +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigResponseTests.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Schema.Teams; +using Xunit; + +namespace Microsoft.Bot.Schema.Tests.Teams +{ + public class ConfigResponseTests + { + [Fact] + public void ConfigResponseInitsWithNoArgs() + { + var configResponse = new ConfigResponse(); + + Assert.NotNull(configResponse); + Assert.IsType>(configResponse); + } + } +} diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigTaskResponseTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigTaskResponseTests.cs new file mode 100644 index 0000000000..f177a9141b --- /dev/null +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/ConfigTaskResponseTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Schema.Teams; +using Xunit; + +namespace Microsoft.Bot.Schema.Tests.Teams +{ + public class ConfigTaskResponseTests + { + [Fact] + public void ConfigTaskResponseInitWithNoArgs() + { + var configTaskResponse = new ConfigTaskResponse(); + + Assert.NotNull(configTaskResponse); + Assert.IsType(configTaskResponse); + Assert.Equal("config", configTaskResponse.ResponseType); + } + } +} diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleContinueResponseTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleContinueResponseTests.cs index ae238603be..c3075d73f6 100644 --- a/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleContinueResponseTests.cs +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleContinueResponseTests.cs @@ -18,6 +18,7 @@ public void TaskModuleContinueResponseInits() Assert.NotNull(continueResponse); Assert.IsType(continueResponse); Assert.Equal(value, continueResponse.Value); + Assert.Equal("continue", continueResponse.Type); } [Fact] @@ -27,6 +28,7 @@ public void TaskModuleContinueResponseInitsWithNoArgs() Assert.NotNull(continueResponse); Assert.IsType(continueResponse); + Assert.Equal("continue", continueResponse.Type); } } } diff --git a/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleMessageResponseTests.cs b/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleMessageResponseTests.cs index 380d10a368..f097144366 100644 --- a/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleMessageResponseTests.cs +++ b/tests/Microsoft.Bot.Schema.Tests/Teams/TaskModuleMessageResponseTests.cs @@ -18,6 +18,7 @@ public void TaskModuleMessageResponseInits() Assert.NotNull(messageResponse); Assert.IsType(messageResponse); Assert.Equal(value, messageResponse.Value); + Assert.Equal("message", messageResponse.Type); } [Fact] @@ -27,6 +28,7 @@ public void TaskModuleMessageResponseInitsWithNoArgs() Assert.NotNull(messageResponse); Assert.IsType(messageResponse); + Assert.Equal("message", messageResponse.Type); } } }