Skip to content

Commit

Permalink
Adds support for file uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkors committed Apr 3, 2023
1 parent 3c58d5c commit 0c4a28d
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 1 deletion.
1 change: 1 addition & 0 deletions Samples/HelloWorld/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class DoStuff : IHandleAppMentions
public Task<EventHandledResponse> Handle(EventMetaData eventMetadata, AppMentionEvent slackEvent)
{
Console.WriteLine("Doing stuff!");
Console.WriteLine(JsonSerializer.Serialize(slackEvent));
return Task.FromResult(new EventHandledResponse("yolo"));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,40 @@ public static async Task<T> PostParametersAsForm<T>(this HttpClient httpClient,

return resObj;
}

public static async Task<T> PostParametersAsMultiPartFormData<T>(this HttpClient httpClient, IEnumerable<KeyValuePair<string, string>> parameters, Byte[] bytes, string api, Action<string> logger = null) where T: Response
{
var request = new HttpRequestMessage(HttpMethod.Post, api);

if (parameters != null && parameters.Any())
{
var formData = new MultipartFormDataContent();
foreach (KeyValuePair<string,string> param in parameters)
{
formData.Add(new StringContent(param.Value), param.Key);
}
formData.Add(new ByteArrayContent(bytes), "file", parameters.First(p => p.Key == "filename").Value);

request.Content = formData;
}

var response = await httpClient.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
logger?.Invoke($"{response.StatusCode} \n {responseContent}");
}

response.EnsureSuccessStatusCode();

var resObj = JsonSerializer.Deserialize<T>(responseContent, JsonSerializerSettings);

if(!resObj.Ok)
throw new WellKnownSlackApiException(error: $"{resObj.Error}", responseContent:responseContent);

return resObj;
}
}

internal class LowerCaseNaming : JsonNamingPolicy
Expand Down
11 changes: 11 additions & 0 deletions source/src/Slackbot.Net.SlackClients.Http/ISlackClient.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Slackbot.Net.SlackClients.Http.Models.Requests.ChatPostMessage;
using Slackbot.Net.SlackClients.Http.Models.Requests.FileUpload;
using Slackbot.Net.SlackClients.Http.Models.Requests.ViewPublish;
using Slackbot.Net.SlackClients.Http.Models.Responses;
using Slackbot.Net.SlackClients.Http.Models.Responses.ChatGetPermalink;
using Slackbot.Net.SlackClients.Http.Models.Responses.ChatPostMessage;
using Slackbot.Net.SlackClients.Http.Models.Responses.ConversationsList;
using Slackbot.Net.SlackClients.Http.Models.Responses.ConversationsRepliesResponse;
using Slackbot.Net.SlackClients.Http.Models.Responses.FileUpload;
using Slackbot.Net.SlackClients.Http.Models.Responses.UserProfile;
using Slackbot.Net.SlackClients.Http.Models.Responses.UsersList;
using Slackbot.Net.SlackClients.Http.Models.Responses.ViewPublish;
Expand Down Expand Up @@ -88,4 +90,13 @@ public interface ISlackClient
/// </summary>
/// <remarks>https://api.slack.com/methods/users.profile.get</remarks>
Task<UserProfileResponse> UserProfile(string user);

/// <summary>
/// Scopes required: files.write
/// Uploads a file
/// </summary>
/// <remarks>https://api.slack.com/methods/files.upload</remarks>
Task<FileUploadResponse> FilesUpload(FileUploadRequest fileupload);

Task<FileUploadResponse> FilesUpload(FileUploadMultiPartRequest req);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Slackbot.Net.SlackClients.Http.Models.Requests.FileUpload;

public class FileUploadRequest
{
public string Channels { get; set; }
public string Content { get; set; }
public string Filename { get; set; }
public string Filetype { get; set; }
public string Initial_Comment { get; set; }
public string Thread_Ts { get; set; }
public string Title { get; set; }
}

public class FileUploadMultiPartRequest
{
public string Channels { get; set; }
public Byte[] File { get; set; }
public string Filename { get; set; }
public string Filetype { get; set; }
public string Initial_Comment { get; set; }
public string Thread_Ts { get; set; }
public string Title { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Slackbot.Net.SlackClients.Http.Models.Responses.FileUpload;

public class FileUploadResponse : Response
{
public FileUploadFile File { get; set; }
}

public class FileUploadFile
{
public string Id { get; set; }
public int Created { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string FileType { get; set; }
public string Pretty_Type { get; set; }
public string User { get; set; }
public bool Is_Public { get; set; }
}
41 changes: 41 additions & 0 deletions source/src/Slackbot.Net.SlackClients.Http/SlackClient.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using Microsoft.Extensions.Logging;
using Slackbot.Net.SlackClients.Http.Extensions;
using Slackbot.Net.SlackClients.Http.Models.Requests.ChatPostMessage;
using Slackbot.Net.SlackClients.Http.Models.Requests.FileUpload;
using Slackbot.Net.SlackClients.Http.Models.Requests.ViewPublish;
using Slackbot.Net.SlackClients.Http.Models.Responses;
using Slackbot.Net.SlackClients.Http.Models.Responses.ChatGetPermalink;
using Slackbot.Net.SlackClients.Http.Models.Responses.ChatPostMessage;
using Slackbot.Net.SlackClients.Http.Models.Responses.ConversationsList;
using Slackbot.Net.SlackClients.Http.Models.Responses.ConversationsRepliesResponse;
using Slackbot.Net.SlackClients.Http.Models.Responses.FileUpload;
using Slackbot.Net.SlackClients.Http.Models.Responses.UserProfile;
using Slackbot.Net.SlackClients.Http.Models.Responses.UsersList;
using Slackbot.Net.SlackClients.Http.Models.Responses.ViewPublish;
Expand Down Expand Up @@ -141,4 +143,43 @@ public async Task<UserProfileResponse> UserProfile(string user)
};
return await _client.PostParametersAsForm<UserProfileResponse>(parameters,"users.profile.get", s => _logger.LogTrace(s));
}

/// <inheritdoc/>
public async Task<FileUploadResponse> FilesUpload(FileUploadRequest req)
{
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("channels", req.Channels),
new KeyValuePair<string, string>("title", req.Title),
new KeyValuePair<string, string>("content", req.Content),
new KeyValuePair<string, string>("filename", req.Filename),
new KeyValuePair<string, string>("filetype", req.Filetype),
new KeyValuePair<string, string>("initial_comment", req.Initial_Comment),
new KeyValuePair<string, string>("thread_ts", req.Thread_Ts),
};
return await _client.PostParametersAsForm<FileUploadResponse>(parameters, "files.upload", s => _logger.LogTrace(s));
}

/// <inheritdoc/>
public async Task<FileUploadResponse> FilesUpload(FileUploadMultiPartRequest req)
{
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("channels", req.Channels),
new KeyValuePair<string, string>("title", req.Title),
new KeyValuePair<string, string>("filename", req.Filename),
};

if (req.Initial_Comment is { })
{
parameters.Add(new KeyValuePair<string, string>("initial_comment", req.Initial_Comment));
}

if (req.Thread_Ts is { })
{
parameters.Add(new KeyValuePair<string, string>("thread_ts", req.Thread_Ts));
}

return await _client.PostParametersAsMultiPartFormData<FileUploadResponse>(parameters, req.File, "files.upload", s => _logger.LogTrace(s));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Slackbot.Net.SlackClients.Http.Models.Requests.FileUpload;
using Slackbot.Net.Tests.Helpers;

namespace Slackbot.Net.Tests
{
public class FileUploadTests : Setup
{
public FileUploadTests(ITestOutputHelper helper) : base(helper)
{
}

[Fact]
public async Task FilesUploadTests()
{
var response = await SlackClient.FilesUpload(new FileUploadRequest
{
Channels = $"{Channel}",
Title = "Man in field",
Initial_Comment = "My initial comment!",
Content = "https://assets3.thrillist.com/v1/image/1682388/size/tl-horizontal_main.jpg",
Filename = "heisann.jpg",
Filetype = "jpg"
});

Assert.True(response.Ok);
}

[Fact]
public async Task FilesUploadFileTests()
{
var bytes = Convert.FromBase64String(File.ReadAllText("./Helpers/ImageBase64Encoded.txt"));
var response = await SlackClient.FilesUpload(new FileUploadMultiPartRequest
{
Channels = $"{Channel}",
Title = "Man holding beer",
File = bytes,
Filename = "beer.png",
Filetype = "png"
});

Assert.True(response.Ok);
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<IsPackable>false</IsPackable>
<RootNamespace>Slackbot.Net.Tests</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<LangVersion>Preview</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -25,5 +25,12 @@
<Using Include="Xunit" />
<Using Include="Xunit.Abstractions" />
</ItemGroup>

<ItemGroup>
<None Remove="Helpers\ImageBase64Encoded.txt" />
<Content Include="Helpers\ImageBase64Encoded.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>

0 comments on commit 0c4a28d

Please sign in to comment.