diff --git a/SlackNet.AspNetCore/AspNetCoreExtensions.cs b/SlackNet.AspNetCore/AspNetCoreExtensions.cs index cb6c5c8..34df98d 100644 --- a/SlackNet.AspNetCore/AspNetCoreExtensions.cs +++ b/SlackNet.AspNetCore/AspNetCoreExtensions.cs @@ -1,6 +1,8 @@ using System; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { @@ -14,6 +16,7 @@ public static IServiceCollection AddSlackNet(this IServiceCollection serviceColl serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.TryAddSingleton(); serviceCollection.AddTransient(c => new SlackApiClient(c.GetService(), c.GetService(), c.GetService(), configuration.ApiToken)); return serviceCollection; diff --git a/SlackNet.AspNetCore/NullDialogSubmissionHandler.cs b/SlackNet.AspNetCore/NullDialogSubmissionHandler.cs new file mode 100644 index 0000000..655b8f4 --- /dev/null +++ b/SlackNet.AspNetCore/NullDialogSubmissionHandler.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using SlackNet.Interaction; + +namespace SlackNet.AspNetCore +{ + public class NullDialogSubmissionHandler : IDialogSubmissionHandler + { + public Task> Handle(DialogSubmission dialog) => Task.FromResult(Enumerable.Empty()); + } +} \ No newline at end of file diff --git a/SlackNet.AspNetCore/ResolvedActionHandler.cs b/SlackNet.AspNetCore/ResolvedActionHandler.cs index d5f9fe8..926ad76 100644 --- a/SlackNet.AspNetCore/ResolvedActionHandler.cs +++ b/SlackNet.AspNetCore/ResolvedActionHandler.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { @@ -24,10 +25,13 @@ public ResolvedActionHandler(IServiceProvider serviceProvider, string actionName _serviceProvider = serviceProvider; } - public override Task Handle(InteractiveMessage message) + public override async Task Handle(InteractiveMessage message) { - var handler = _serviceProvider.GetRequiredService(); - return handler.Handle(message); + using (var scope = _serviceProvider.CreateScope()) + { + var handler = scope.ServiceProvider.GetRequiredService(); + return await handler.Handle(message).ConfigureAwait(false); + } } } } \ No newline at end of file diff --git a/SlackNet.AspNetCore/ResolvedDialogSubmissionHandler.cs b/SlackNet.AspNetCore/ResolvedDialogSubmissionHandler.cs new file mode 100644 index 0000000..cf6443e --- /dev/null +++ b/SlackNet.AspNetCore/ResolvedDialogSubmissionHandler.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using SlackNet.Interaction; + +namespace SlackNet.AspNetCore +{ + public class ResolvedDialogSubmissionHandler : IDialogSubmissionHandler + where T : IDialogSubmissionHandler + { + private readonly IServiceProvider _serviceProvider; + public ResolvedDialogSubmissionHandler(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; + + public async Task> Handle(DialogSubmission dialog) + { + using (var scope = _serviceProvider.CreateScope()) + { + var handler = scope.ServiceProvider.GetRequiredService(); + return await handler.Handle(dialog).ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/SlackNet.AspNetCore/ResolvedOptionProvider.cs b/SlackNet.AspNetCore/ResolvedOptionProvider.cs index 59558af..5c91d52 100644 --- a/SlackNet.AspNetCore/ResolvedOptionProvider.cs +++ b/SlackNet.AspNetCore/ResolvedOptionProvider.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { diff --git a/SlackNet.AspNetCore/SlackActionsService.cs b/SlackNet.AspNetCore/SlackActionsService.cs index b79535d..1a509c7 100644 --- a/SlackNet.AspNetCore/SlackActionsService.cs +++ b/SlackNet.AspNetCore/SlackActionsService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { diff --git a/SlackNet.AspNetCore/SlackEventsMiddleware.cs b/SlackNet.AspNetCore/SlackEventsMiddleware.cs index 247770b..22ddbd6 100644 --- a/SlackNet.AspNetCore/SlackEventsMiddleware.cs +++ b/SlackNet.AspNetCore/SlackEventsMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; @@ -5,6 +6,7 @@ using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using SlackNet.Events; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { @@ -15,14 +17,16 @@ class SlackEventsMiddleware private readonly ISlackEvents _slackEvents; private readonly ISlackActions _slackActions; private readonly ISlackOptions _slackOptions; + private readonly IDialogSubmissionHandler _dialogSubmissionHandler; private readonly SlackJsonSettings _jsonSettings; public SlackEventsMiddleware( - RequestDelegate next, - SlackEndpointConfiguration configuration, - ISlackEvents slackEvents, - ISlackActions slackActions, + RequestDelegate next, + SlackEndpointConfiguration configuration, + ISlackEvents slackEvents, + ISlackActions slackActions, ISlackOptions slackOptions, + IDialogSubmissionHandler dialogSubmissionHandler, SlackJsonSettings jsonSettings) { _next = next; @@ -30,6 +34,7 @@ public SlackEventsMiddleware( _slackEvents = slackEvents; _slackActions = slackActions; _slackOptions = slackOptions; + _dialogSubmissionHandler = dialogSubmissionHandler; _jsonSettings = jsonSettings; } @@ -60,8 +65,9 @@ private async Task HandleSlackEvent(HttpContext context) if (body is EventCallback eventCallback && IsValidToken(eventCallback.Token)) { + var response = context.Respond(HttpStatusCode.OK).ConfigureAwait(false); _slackEvents.Handle(eventCallback); - return await context.Respond(HttpStatusCode.OK).ConfigureAwait(false); + return await response; } return await context.Respond(HttpStatusCode.BadRequest, body: "Invalid token or unrecognized content").ConfigureAwait(false); @@ -72,22 +78,43 @@ private async Task HandleSlackAction(HttpContext context) if (context.Request.Method != "POST") return await context.Respond(HttpStatusCode.MethodNotAllowed).ConfigureAwait(false); - var interactiveMessage = await DeserializePayload(context).ConfigureAwait(false); + var interactionRequest = await DeserializePayload(context).ConfigureAwait(false); - if (interactiveMessage != null && IsValidToken(interactiveMessage.Token)) + if (interactionRequest != null && IsValidToken(interactionRequest.Token)) { - var response = await _slackActions.Handle(interactiveMessage).ConfigureAwait(false); - - var responseJson = response == null ? null - : interactiveMessage.IsAppUnfurl ? Serialize(new AttachmentUpdateResponse(response)) - : Serialize(new MessageUpdateResponse(response)); - - return await context.Respond(HttpStatusCode.OK, "application/json", responseJson).ConfigureAwait(false); + switch (interactionRequest) + { + case InteractiveMessage interactiveMessage: + return await HandleInteractiveMessage(context, interactiveMessage).ConfigureAwait(false); + case DialogSubmission dialogSubmission: + return await HandleDialogSubmission(context, dialogSubmission).ConfigureAwait(false); + } } return await context.Respond(HttpStatusCode.BadRequest, body: "Invalid token or unrecognized content").ConfigureAwait(false); } + private async Task HandleInteractiveMessage(HttpContext context, InteractiveMessage interactiveMessage) + { + var response = await _slackActions.Handle(interactiveMessage).ConfigureAwait(false); + + var responseJson = response == null ? null + : interactiveMessage.IsAppUnfurl ? Serialize(new AttachmentUpdateResponse(response)) + : Serialize(new MessageUpdateResponse(response)); + + return await context.Respond(HttpStatusCode.OK, "application/json", responseJson).ConfigureAwait(false); + } + + private async Task HandleDialogSubmission(HttpContext context, DialogSubmission dialog) + { + var errors = (await _dialogSubmissionHandler.Handle(dialog).ConfigureAwait(false))?.ToList() + ?? new List(); + + return errors.Any() + ? await context.Respond(HttpStatusCode.OK, "application/json", Serialize(new DialogErrorResponse { Errors = errors })).ConfigureAwait(false) + : await context.Respond(HttpStatusCode.OK).ConfigureAwait(false); + } + private async Task HandleSlackOptions(HttpContext context) { if (context.Request.Method != "POST") diff --git a/SlackNet.AspNetCore/SlackOptionsService.cs b/SlackNet.AspNetCore/SlackOptionsService.cs index 55fa5c9..d44b8b1 100644 --- a/SlackNet.AspNetCore/SlackOptionsService.cs +++ b/SlackNet.AspNetCore/SlackOptionsService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { diff --git a/SlackNet.AspNetCore/SlackServiceConfiguration.cs b/SlackNet.AspNetCore/SlackServiceConfiguration.cs index 1c52c72..91a5d67 100644 --- a/SlackNet.AspNetCore/SlackServiceConfiguration.cs +++ b/SlackNet.AspNetCore/SlackServiceConfiguration.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using SlackNet.Events; +using SlackNet.Interaction; namespace SlackNet.AspNetCore { @@ -43,6 +44,13 @@ public SlackServiceConfiguration RegisterOptionProvider(string action return this; } + public SlackServiceConfiguration RegisterDialogSubmissionHandler() + where THandler : IDialogSubmissionHandler + { + _serviceCollection.AddSingleton(c => new ResolvedDialogSubmissionHandler(c)); + return this; + } + public string ApiToken { get; private set; } } } \ No newline at end of file diff --git a/SlackNet.EventsExample/ColorSelector.cs b/SlackNet.EventsExample/ColorSelector.cs index c00df94..e8e9cee 100644 --- a/SlackNet.EventsExample/ColorSelector.cs +++ b/SlackNet.EventsExample/ColorSelector.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Linq; using System.Threading.Tasks; +using SlackNet.Interaction; namespace SlackNet.EventsExample { @@ -11,12 +12,13 @@ public class ColorSelector : IActionHandler, IOptionProvider public async Task Handle(InteractiveMessage message) { - message.OriginalAttachment.Color = message.Action.SelectedValue; - message.OriginalAttachment.Actions[0].SelectedOptions = new List