Skip to content

Commit

Permalink
Block interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
soxtoby committed Jun 24, 2019
1 parent a200749 commit 286ddf8
Show file tree
Hide file tree
Showing 58 changed files with 936 additions and 217 deletions.
2 changes: 2 additions & 0 deletions SlackNet.AspNetCore/AspNetCoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public static IServiceCollection AddSlackNet(this IServiceCollection serviceColl
configure(configuration);
Default.RegisterServices((serviceType, createService) => serviceCollection.AddTransient(serviceType, c => createService(c.GetService)));
serviceCollection.AddSingleton<ISlackEvents, SlackEventsService>();
serviceCollection.AddSingleton<ISlackBlockActions, SlackBlockActionsService>();
serviceCollection.AddSingleton<ISlackBlockOptions, SlackBlockOptionsService>();
serviceCollection.AddSingleton<ISlackInteractiveMessages, SlackInteractiveMessagesService>();
serviceCollection.AddSingleton<ISlackMessageActions, SlackMessageActionsService>();
serviceCollection.AddSingleton<ISlackOptions, SlackOptionsService>();
Expand Down
25 changes: 25 additions & 0 deletions SlackNet.AspNetCore/ResolvedBlockActionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using SlackNet.Blocks;
using SlackNet.Interaction;

namespace SlackNet.AspNetCore
{
class ResolvedBlockActionHandler<TAction, THandler> : IBlockActionHandler<TAction>
where TAction : BlockAction
where THandler : IBlockActionHandler<TAction>
{
private readonly IServiceProvider _serviceProvider;
public ResolvedBlockActionHandler(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;

public async Task Handle(TAction action, BlockActionRequest request)
{
using (var scope = _serviceProvider.CreateScope())
{
var handler = scope.ServiceProvider.GetRequiredService<THandler>();
await handler.Handle(action, request).ConfigureAwait(false);
}
}
}
}
34 changes: 34 additions & 0 deletions SlackNet.AspNetCore/ResolvedBlockOptionProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using SlackNet.Interaction;

namespace SlackNet.AspNetCore
{
abstract class ResolvedBlockOptionProvider : IBlockOptionProvider
{
protected ResolvedBlockOptionProvider(string actionId) => ActionName = actionId;

public string ActionName { get; }

public abstract Task<BlockOptionsResponse> GetOptions(BlockOptionsRequest request);
}

class ResolvedBlockOptionProvider<T> : ResolvedBlockOptionProvider
where T : IBlockOptionProvider
{
private readonly IServiceProvider _serviceProvider;

public ResolvedBlockOptionProvider(IServiceProvider serviceProvider, string actionId)
: base(actionId)
{
_serviceProvider = serviceProvider;
}

public override Task<BlockOptionsResponse> GetOptions(BlockOptionsRequest request)
{
var handler = _serviceProvider.GetRequiredService<T>();
return handler.GetOptions(request);
}
}
}
21 changes: 6 additions & 15 deletions SlackNet.AspNetCore/ResolvedMessageActionHandler.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
using System;

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using SlackNet.Interaction;

namespace SlackNet.AspNetCore
{
abstract class ResolvedMessageActionHandler : IMessageActionHandler
{
protected ResolvedMessageActionHandler(string callbackId) => CallbackId = callbackId;

public string CallbackId { get; }

public abstract Task<MessageActionResponse> Handle(MessageAction request);
}

class ResolvedMessageActionHandler<T> : ResolvedMessageActionHandler
class ResolvedMessageActionHandler<T> : IMessageActionHandler
where T : IMessageActionHandler
{
private readonly IServiceProvider _serviceProvider;

public ResolvedMessageActionHandler(IServiceProvider serviceProvider, string callbackId)
: base(callbackId)
public ResolvedMessageActionHandler(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public override async Task<MessageActionResponse> Handle(MessageAction request)
public async Task Handle(MessageAction request)
{
using (var scope = _serviceProvider.CreateScope())
{
var handler = scope.ServiceProvider.GetRequiredService<T>();
return await handler.Handle(request).ConfigureAwait(false);
await handler.Handle(request).ConfigureAwait(false);
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions SlackNet.AspNetCore/SlackBlockActionsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using SlackNet.Blocks;
using SlackNet.Interaction;

namespace SlackNet.AspNetCore
{
class SlackBlockActionsService : ISlackBlockActions
{
private readonly SlackBlockActions _slackBlockActions = new SlackBlockActions();

public SlackBlockActionsService(IEnumerable<IBlockActionHandler> handlers)
{
foreach (var handler in handlers)
AddHandler((dynamic)handler);
}

public Task Handle(BlockActionRequest request) => _slackBlockActions.Handle(request);

public void AddHandler<TAction>(IBlockActionHandler<TAction> handler) where TAction : BlockAction => _slackBlockActions.AddHandler(handler);
}
}
20 changes: 20 additions & 0 deletions SlackNet.AspNetCore/SlackBlockOptionsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using SlackNet.Interaction;

namespace SlackNet.AspNetCore
{
class SlackBlockOptionsService : ISlackBlockOptions
{
private readonly ISlackBlockOptions _options = new SlackBlockOptions();

public SlackBlockOptionsService(IEnumerable<ResolvedBlockOptionProvider> providers)
{
foreach (var provider in providers)
_options.SetProvider(provider.ActionName, provider);
}

public Task<BlockOptionsResponse> Handle(BlockOptionsRequest request) => _options.Handle(request);
public void SetProvider(string actionId, IBlockOptionProvider handler) => _options.SetProvider(actionId, handler);
}
}
48 changes: 37 additions & 11 deletions SlackNet.AspNetCore/SlackEventsMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class SlackEventsMiddleware
private readonly RequestDelegate _next;
private readonly SlackEndpointConfiguration _configuration;
private readonly ISlackEvents _slackEvents;
private readonly ISlackBlockActions _slackBlockActions;
private readonly ISlackBlockOptions _slackBlockOptions;
private readonly ISlackInteractiveMessages _slackInteractiveMessages;
private readonly ISlackMessageActions _slackMessageActions;
private readonly ISlackOptions _slackOptions;
Expand All @@ -25,15 +27,19 @@ public SlackEventsMiddleware(
RequestDelegate next,
SlackEndpointConfiguration configuration,
ISlackEvents slackEvents,
ISlackBlockActions slackBlockActions,
ISlackBlockOptions slackBlockOptions,
ISlackInteractiveMessages slackInteractiveMessages,
ISlackMessageActions slackMessageActions,
ISlackOptions slackOptions,
ISlackOptions slackOptions,
IDialogSubmissionHandler dialogSubmissionHandler,
SlackJsonSettings jsonSettings)
{
_next = next;
_configuration = configuration;
_slackEvents = slackEvents;
_slackBlockActions = slackBlockActions;
_slackBlockOptions = slackBlockOptions;
_slackInteractiveMessages = slackInteractiveMessages;
_slackMessageActions = slackMessageActions;
_slackOptions = slackOptions;
Expand Down Expand Up @@ -87,6 +93,8 @@ private async Task<HttpResponse> HandleSlackAction(HttpContext context)
{
switch (interactionRequest)
{
case BlockActionRequest blockActions:
return await HandleBlockActions(context, blockActions).ConfigureAwait(false);
case InteractiveMessage interactiveMessage:
return await HandleInteractiveMessage(context, interactiveMessage).ConfigureAwait(false);
case DialogSubmission dialogSubmission:
Expand All @@ -101,6 +109,12 @@ private async Task<HttpResponse> HandleSlackAction(HttpContext context)
return await context.Respond(HttpStatusCode.BadRequest, body: "Invalid token or unrecognized content").ConfigureAwait(false);
}

private async Task<HttpResponse> HandleBlockActions(HttpContext context, BlockActionRequest blockActionRequest)
{
await _slackBlockActions.Handle(blockActionRequest).ConfigureAwait(false);
return await context.Respond(HttpStatusCode.OK).ConfigureAwait(false);
}

private async Task<HttpResponse> HandleInteractiveMessage(HttpContext context, InteractiveMessage interactiveMessage)
{
var response = await _slackInteractiveMessages.Handle(interactiveMessage).ConfigureAwait(false);
Expand Down Expand Up @@ -130,31 +144,43 @@ private async Task<HttpResponse> HandleDialogCancellation(HttpContext context, D

private async Task<HttpResponse> HandleMessageAction(HttpContext context, MessageAction messageAction)
{
var response = await _slackMessageActions.Handle(messageAction).ConfigureAwait(false);

var responseJson = response == null
? null
: Serialize(response);

return await context.Respond(HttpStatusCode.OK, "application/json", responseJson).ConfigureAwait(false);
await _slackMessageActions.Handle(messageAction).ConfigureAwait(false);
return await context.Respond(HttpStatusCode.OK).ConfigureAwait(false);
}

private async Task<HttpResponse> HandleSlackOptions(HttpContext context)
{
if (context.Request.Method != "POST")
return await context.Respond(HttpStatusCode.MethodNotAllowed).ConfigureAwait(false);

var optionsRequest = await DeserializePayload<OptionsRequest>(context).ConfigureAwait(false);
var optionsRequest = await DeserializePayload<OptionsRequestBase>(context).ConfigureAwait(false);

if (optionsRequest != null && IsValidToken(optionsRequest.Token))
{
var response = await _slackOptions.Handle(optionsRequest).ConfigureAwait(false);
return await context.Respond(HttpStatusCode.OK, "application/json", Serialize(response)).ConfigureAwait(false);
switch (optionsRequest)
{
case OptionsRequest legacyOptionsRequest:
return await HandleLegacyOptionsRequest(context, legacyOptionsRequest).ConfigureAwait(false);
case BlockOptionsRequest blockOptionsRequest:
return await HandleBlockOptionsRequest(context, blockOptionsRequest).ConfigureAwait(false);
}
}

return await context.Respond(HttpStatusCode.BadRequest, body: "Invalid token or unrecognized content").ConfigureAwait(false);
}

private async Task<HttpResponse> HandleLegacyOptionsRequest(HttpContext context, OptionsRequest optionsRequest)
{
var response = await _slackOptions.Handle(optionsRequest).ConfigureAwait(false);
return await context.Respond(HttpStatusCode.OK, "application/json", Serialize(response)).ConfigureAwait(false);
}

private async Task<HttpResponse> HandleBlockOptionsRequest(HttpContext context, BlockOptionsRequest blockOptionsRequest)
{
var response = await _slackBlockOptions.Handle(blockOptionsRequest).ConfigureAwait(false);
return await context.Respond(HttpStatusCode.OK, "application/json", Serialize(response)).ConfigureAwait(false);
}

private async Task<T> DeserializePayload<T>(HttpContext context)
{
var form = await context.Request.ReadFormAsync().ConfigureAwait(false);
Expand Down
8 changes: 4 additions & 4 deletions SlackNet.AspNetCore/SlackMessageActionsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class SlackMessageActionsService : ISlackMessageActions
{
private readonly ISlackMessageActions _actions = new SlackMessageActions();

public SlackMessageActionsService(IEnumerable<ResolvedMessageActionHandler> handlers)
public SlackMessageActionsService(IEnumerable<IMessageActionHandler> handlers)
{
foreach (var handler in handlers)
_actions.SetHandler(handler.CallbackId, handler);
AddHandler(handler);
}

public Task<MessageActionResponse> Handle(MessageAction request) => _actions.Handle(request);
public void SetHandler(string callbackId, IMessageActionHandler handler) => _actions.SetHandler(callbackId, handler);
public Task Handle(MessageAction request) => _actions.Handle(request);
public void AddHandler(IMessageActionHandler handler) => _actions.AddHandler(handler);
}
}
77 changes: 73 additions & 4 deletions SlackNet.AspNetCore/SlackServiceConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using Microsoft.Extensions.DependencyInjection;
using SlackNet.Blocks;
using SlackNet.Events;
using SlackNet.Interaction;

Expand All @@ -24,7 +26,48 @@ public SlackServiceConfiguration RegisterEventHandler<TEvent, THandler>()
where THandler : class, IEventHandler<TEvent>
{
_serviceCollection.AddTransient<THandler>();
_serviceCollection.AddSingleton<IEventHandler, ResolvedEventHandler<TEvent, THandler>>();
return RegisterEventHandler(c => new ResolvedEventHandler<TEvent, THandler>(c));
}

public SlackServiceConfiguration RegisterEventHandler<TEvent>(IEventHandler<TEvent> handler)
where TEvent : Event
{
return RegisterEventHandler(c => handler);
}

public SlackServiceConfiguration RegisterEventHandler<TEvent>(Func<IServiceProvider, IEventHandler<TEvent>> handlerFactory)
where TEvent : Event
{
_serviceCollection.AddSingleton<IEventHandler>(handlerFactory);
return this;
}

public SlackServiceConfiguration RegisterBlockActionHandler<TAction, THandler>()
where TAction : BlockAction
where THandler : class, IBlockActionHandler<TAction>
{
_serviceCollection.AddTransient<THandler>();
return RegisterBlockActionHandler(c => new ResolvedBlockActionHandler<TAction, THandler>(c));
}

public SlackServiceConfiguration RegisterBlockActionHandler<TAction, THandler>(string actionId)
where TAction : BlockAction
where THandler : class, IBlockActionHandler<TAction>
{
_serviceCollection.AddTransient<THandler>();
return RegisterBlockActionHandler(c => new SpecificBlockActionHandler<TAction>(actionId, new ResolvedBlockActionHandler<TAction, THandler>(c)));
}

public SlackServiceConfiguration RegisterBlockActionHandler<TAction>(IBlockActionHandler<TAction> handler)
where TAction : BlockAction
{
return RegisterBlockActionHandler(c => handler);
}

public SlackServiceConfiguration RegisterBlockActionHandler<TAction>(Func<IServiceProvider, IBlockActionHandler<TAction>> handlerFactory)
where TAction : BlockAction
{
_serviceCollection.AddSingleton<IBlockActionHandler>(handlerFactory);
return this;
}

Expand All @@ -36,11 +79,28 @@ public SlackServiceConfiguration RegisterInteractiveMessageHandler<THandler>(str
return this;
}

public SlackServiceConfiguration RegisterMessageActionHandler<THandler>()
where THandler : class, IMessageActionHandler
{
_serviceCollection.AddTransient<THandler>();
return RegisterMessageActionHandler(c => new ResolvedMessageActionHandler<THandler>(c));
}

public SlackServiceConfiguration RegisterMessageActionHandler<THandler>(string callbackId)
where THandler : class, IMessageActionHandler
{
_serviceCollection.AddTransient<THandler>();
_serviceCollection.AddSingleton<ResolvedMessageActionHandler>(c => new ResolvedMessageActionHandler<THandler>(c, callbackId));
return RegisterMessageActionHandler(c => new SpecificMessageActionHandler(callbackId, new ResolvedMessageActionHandler<THandler>(c)));
}

public SlackServiceConfiguration RegisterMessageActionHandler(IMessageActionHandler handler)
{
return RegisterMessageActionHandler(c => handler);
}

public SlackServiceConfiguration RegisterMessageActionHandler(Func<IServiceProvider, IMessageActionHandler> handlerFactory)
{
_serviceCollection.AddSingleton(handlerFactory);
return this;
}

Expand All @@ -52,9 +112,18 @@ public SlackServiceConfiguration RegisterOptionProvider<TProvider>(string action
return this;
}

public SlackServiceConfiguration RegisterBlockOptionProvider<TProvider>(string actionId)
where TProvider : class, IBlockOptionProvider
{
_serviceCollection.AddTransient<TProvider>();
_serviceCollection.AddSingleton<ResolvedBlockOptionProvider>(c => new ResolvedBlockOptionProvider<TProvider>(c, actionId));
return this;
}

public SlackServiceConfiguration RegisterDialogSubmissionHandler<THandler>()
where THandler : IDialogSubmissionHandler
where THandler : class, IDialogSubmissionHandler
{
_serviceCollection.AddTransient<THandler>();
_serviceCollection.AddSingleton<IDialogSubmissionHandler>(c => new ResolvedDialogSubmissionHandler<THandler>(c));
return this;
}
Expand Down
Loading

0 comments on commit 286ddf8

Please sign in to comment.