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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/SlackDotNet/Enums/InteractiveMessageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using SlackDotNet.Models.Messages.Payloads.EventsAPI;
using SlackDotNet.Models.Messages.Payloads.Interactive;

namespace SlackDotNet.Enums
{
public enum InteractiveMessageType
{
block_actions,

shortcut,

message_actions,

[Type(typeof(ViewSubmission))]
view_submission,

view_closed
}
}
3 changes: 3 additions & 0 deletions src/SlackDotNet/Extensions/IServiceCollectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ public static IServiceCollection AddSlackDotNet(this IServiceCollection services
services.TryAddSingleton<ISlashCommandHandler, SlashCommandHandler>();
services.TryAddSingleton<IHelloHandler, HelloHandler>();
services.TryAddSingleton<IEventsAPIHandler, EventsAPIHandler>();
services.TryAddSingleton<IInteractiveHandler, InteractiveHandler>();

services.AddSingleton<ISlackSocket, SlackSocket>();

services.AddSingleton<ISlackClient, SlackClient>();
return services;
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/SlackDotNet/Handlers/IInteractiveHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Threading.Tasks;
using SlackDotNet.Models;
using SlackDotNet.Models.Messages;

namespace SlackDotNet.Handlers
{
/// <summary>
/// Handler for WebSocket "interactive" messages.
/// </summary>
public interface IInteractiveHandler
{
Task<SlackWebSocketMessageResponse> Handle(InteractiveMessage interactiveMessage);
}
}
26 changes: 26 additions & 0 deletions src/SlackDotNet/Handlers/InteractiveHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SlackDotNet.Models;
using SlackDotNet.Models.Messages;

namespace SlackDotNet.Handlers
{
public class InteractiveHandler : IInteractiveHandler
{
public ILogger<InteractiveHandler> Logger { get; }

public InteractiveHandler(ILogger<InteractiveHandler> logger)
{
Logger = logger;
}

public async Task<SlackWebSocketMessageResponse> Handle(InteractiveMessage interactiveMessage)
{
await Task.Run(() =>
Logger.LogWarning($"Received unhandled `{interactiveMessage.Type}` message from WebSocket.")
);

return new SlackWebSocketMessageResponse(interactiveMessage);
}
}
}
65 changes: 65 additions & 0 deletions src/SlackDotNet/ISlackClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Threading.Tasks;
using SlackDotNet.Models;
using SlackDotNet.Models.Messages;
using SlackDotNet.Models.Responses;

namespace SlackDotNet
{
public interface ISlackClient
{
/// <summary>
/// Get's a slack user's information
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<User> GetUser(string userId);

/// <summary>
/// Posts a message to a channel
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
Task<ChatMessageResponse> PostMessage(ChatMessage message, bool ephemeral = false);

/// <summary>
/// Deletes a message in response to an interactive command
/// </summary>
/// <param name="responseUrl"></param>
/// <returns></returns>
Task<bool> DeleteResponse(string responseUrl);

/// <summary>
/// Gets the user's ID from their display name
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
Task<string> GetUserId(string username);

/// <summary>
/// Gets the user's display name from their username
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<string> GetUserName(string userId);

/// <summary>
/// Get's all the emojis in the workspace as a dictionary of name => URL
/// </summary>
/// <returns></returns>
Task<Emojis> GetEmojisAndUrls();

/// <summary>
/// Publish a view.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
Task<PublishViewResponse> PublishView(PublishViewRequest request);

/// <summary>
/// Open a view.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
Task<PublishViewResponse> OpenView(OpenViewRequest request);
}
}
152 changes: 152 additions & 0 deletions src/SlackDotNet/Models/Block.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace SlackDotNet.Models
{
public class Block
{
/// <summary>
/// The type of the block:
/// `actions`, `context`, `divider`, `file`, `header`, `image`, `input`, `section`
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }

/// <summary>
/// An array of interactive elemnts.
/// Max of 25.
///
/// Valid for: `actions`, `context`
/// </summary>
[JsonProperty("elements")]
public List<BlockElement> Elements { get; set; }

/// <summary>
/// A string acting as a unique identifier for a block.
/// If not specified, a block_id will be generated.
/// You can use this block_id when you receive an interaction payload to identify the source of the action.
/// Maximum length for this field is 255 characters.
/// block_id should be unique for each message and each iteration of a message.
/// If a message is updated, use a new block_id.
///
/// Valid for: `actions`, `context`, `divider`, `file`, `header`, `image`, `input`, `section`
/// </summary>
[JsonProperty("block_id")]
public string BlockId { get; set; }

/// <summary>
/// The external unique ID for this file.
///
/// Valid for: `file`
/// </summary>
[JsonProperty("external_id")]
public string ExternalId { get; set; }

/// <summary>
/// At the moment, source should always be `remote` for a remote file.
///
/// Valid for: `file`
/// </summary>
[JsonProperty("source")]
public string Source { get; set; }

/// <summary>
/// The text for the block, in the form of a `plain_text` text object.
/// Maximum length for the text in this field is 150 characters.
///
/// Valid for: `header`, `section`
/// </summary>
[JsonProperty("text")]
public TextBlock Text { get; set; }

/// <summary>
/// The URL of the image to be displayed. Maximum length for this field is 3000 characters.
///
/// Valid for: `image`
/// </summary>
[JsonProperty("image_url")]
public string ImageUrl { get; set; }

/// <summary>
/// A plain-text summary of the image. This should not contain any markup.
/// Maximum length for this field is 2000 characters
///
/// Valid for: `image`
/// </summary>
[JsonProperty("alt_text")]
public string AltText { get; set; }

/// <summary>
/// An optional title for the image in the form of a text object that can only be of type: plain_text.
/// Maximum length for the text in this field is 2000 characters.
///
/// Valid for: `image`
/// </summary>
[JsonProperty("title")]
public TextBlock Title { get; set; }

/// <summary>
/// A label that appears above an input element in the form of a text object that must have type of plain_text.
/// Maximum length for the text in this field is 2000 characters.
///
/// Valid for: `input`
/// </summary>
[JsonProperty("label")]
public TextBlock Label { get; set; }

/// <summary>
/// A plain-text input element, a checkbox element, a radio button element, a select menu element,
/// a multi-select menu element, or a datepicker.
///
/// Valid for: `input`
/// </summary>
[JsonProperty("element")]
public BlockElement Element { get; set; }

/// <summary>
/// A boolean that indicates whether or not the use of elements in this block should dispatch a block_actions payload.
/// Defaults to false.
///
/// Valid for: `input`
/// </summary>
[JsonProperty("dispatch_action")]
public bool? DispatchAction { get; set; }

/// <summary>
/// An optional hint that appears below an input element in a lighter grey.
/// It must be a text object with a type of plain_text.
/// Maximum length for the text in this field is 2000 characters.
///
/// Valid for: `input`
/// </summary>
[JsonProperty("hint")]
public TextBlock Hint { get; set; }

/// <summary>
/// A boolean that indicates whether the input element may be empty when a user submits the modal.
/// Defaults to false.
///
/// Valid for: `input`
/// </summary>
[JsonProperty("optional")]
public bool? Optional { get; set; }

/// <summary>
/// Required if no text is provided. A List of text objects.
/// Any text objects included with fields will be rendered in a compact format that allows for 2 columns of side-by-side text.
/// Maximum number of items is 10. Maximum length for the text in each item is 2000 characters.
///
/// Valid for: `section`
/// </summary>
[JsonProperty("fields")]
public List<TextBlock> Fields { get; set; }

/// <summary>
/// One of the available element objects.
///
/// Valid for: `section`
/// </summary>
[JsonProperty("accessory")]
public BlockElement Accessory { get; set; }
}
}
Loading