Skip to content

Commit

Permalink
Josh/file upload (microsoft#1881)
Browse files Browse the repository at this point in the history
* adding initial file bot

* removing project dependicies

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* updating file upload sample

* removing dupe file upload

* Update README.md

* updating web page defaults
  • Loading branch information
Virtual-Josh authored Oct 30, 2019
1 parent 4873f33 commit 4c794e4
Show file tree
Hide file tree
Showing 17 changed files with 871 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Microsoft.BotBuilderSamples
{
public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
public AdapterWithErrorHandler(IConfiguration configuration, ILogger<BotFrameworkHttpAdapter> logger)
: base(configuration, logger)
{
OnTurnError = async (turnContext, exception) =>
{
// Log any leaked exception from the application.
logger.LogError($"Exception caught : {exception.Message}");

// Send a catch-all apology to the user.
await turnContext.SendActivityAsync("Sorry, it looks like something went wrong.");
};
}
}
}
159 changes: 159 additions & 0 deletions samples/csharp_dotnetcore/56.teams-file-upload/Bots/TeamsFileBot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Teams;
using Microsoft.Bot.Schema;
using Microsoft.Bot.Schema.Teams;
using Newtonsoft.Json.Linq;

namespace Microsoft.BotBuilderSamples.Bots
{
public class TeamsFileBot : TeamsActivityHandler
{
/*
* You can install this bot at any scope. You can @mention the bot and it will present you with the file prompt. You can accept and
* the file will be uploaded, or you can decline and it won't.
*/

private readonly IHttpClientFactory _clientFactory;

public TeamsFileBot(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
bool messageWithFileDownloadInfo = turnContext.Activity.Attachments?[0].ContentType == FileDownloadInfo.ContentType;
if (messageWithFileDownloadInfo)
{
var file = turnContext.Activity.Attachments[0];
var fileDownload = JObject.FromObject(file.Content).ToObject<FileDownloadInfo>();

string filePath = Path.Combine("Files", file.Name);

var client = _clientFactory.CreateClient();
var response = await client.GetAsync(fileDownload.DownloadUrl);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
await response.Content.CopyToAsync(fileStream);
}

var reply = ((Activity)turnContext.Activity).CreateReply();
reply.TextFormat = "xml";
reply.Text = $"Complete downloading <b>{file.Name}</b>";
await turnContext.SendActivityAsync(reply, cancellationToken);
}
else
{
string filename = "teams-logo.png";
string filePath = Path.Combine("Files", filename);
long fileSize = new FileInfo(filePath).Length;
await SendFileCardAsync(turnContext, filename, fileSize, cancellationToken);
}
}

private async Task SendFileCardAsync(ITurnContext turnContext, string filename, long filesize, CancellationToken cancellationToken)
{
var consentContext = new Dictionary<string, string>
{
{ "filename", filename },
};

var fileCard = new FileConsentCard
{
Description = "This is the file I want to send you",
SizeInBytes = filesize,
AcceptContext = consentContext,
DeclineContext = consentContext,
};

var asAttachment = new Attachment
{
Content = fileCard,
ContentType = FileConsentCard.ContentType,
Name = filename,
};

var replyActivity = turnContext.Activity.CreateReply();
replyActivity.Attachments = new List<Attachment>() { asAttachment };

await turnContext.SendActivityAsync(replyActivity, cancellationToken);
}

protected override async Task OnTeamsFileConsentAcceptAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{
try
{
JToken context = JObject.FromObject(fileConsentCardResponse.Context);

string filePath = Path.Combine("Files", context["filename"].ToString());
long fileSize = new FileInfo(filePath).Length;
var client = _clientFactory.CreateClient();
using (var fileStream = File.OpenRead(filePath))
{
var fileContent = new StreamContent(fileStream);
fileContent.Headers.ContentLength = fileSize;
fileContent.Headers.ContentRange = new ContentRangeHeaderValue(0, fileSize - 1, fileSize);
await client.PutAsync(fileConsentCardResponse.UploadInfo.UploadUrl, fileContent, cancellationToken);
}

await FileUploadCompletedAsync(turnContext, fileConsentCardResponse, cancellationToken);
}
catch (Exception e)
{
await FileUploadFailedAsync(turnContext, e.ToString(), cancellationToken);
}
}

protected override async Task OnTeamsFileConsentDeclineAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{
JToken context = JObject.FromObject(fileConsentCardResponse.Context);

var reply = ((Activity)turnContext.Activity).CreateReply();
reply.TextFormat = "xml";
reply.Text = $"Declined. We won't upload file <b>{context["filename"]}</b>.";
await turnContext.SendActivityAsync(reply, cancellationToken);
}

private async Task FileUploadCompletedAsync(ITurnContext turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{
var downloadCard = new FileInfoCard
{
UniqueId = fileConsentCardResponse.UploadInfo.UniqueId,
FileType = fileConsentCardResponse.UploadInfo.FileType,
};

var asAttachment = new Attachment
{
Content = downloadCard,
ContentType = FileInfoCard.ContentType,
Name = fileConsentCardResponse.UploadInfo.Name,
ContentUrl = fileConsentCardResponse.UploadInfo.ContentUrl,
};

var reply = turnContext.Activity.CreateReply();
reply.TextFormat = "xml";
reply.Text = $"<b>File uploaded.</b> Your file <b>{fileConsentCardResponse.UploadInfo.Name}</b> is ready to download";
reply.Attachments = new List<Attachment> { asAttachment };

await turnContext.SendActivityAsync(reply, cancellationToken);
}

private async Task FileUploadFailedAsync(ITurnContext turnContext, string error, CancellationToken cancellationToken)
{
var reply = turnContext.Activity.CreateReply();
reply.TextFormat = "xml";
reply.Text = $"<b>File upload failed.</b> Error: <pre>{error}</pre>";
await turnContext.SendActivityAsync(reply, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;

namespace Microsoft.BotBuilderSamples.Controllers
{
// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
// implementation at runtime. Multiple different IBot implementations running at different endpoints can be
// achieved by specifying a more specific type for the bot constructor argument.
[Route("api/messages")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter Adapter;
private readonly IBot Bot;

public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
{
Adapter = adapter;
Bot = bot;
}

[HttpPost]
public async Task PostAsync()
{
// Delegate the processing of the HTTP POST to the adapter.
// The adapter will invoke the bot.
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 17 additions & 3 deletions samples/csharp_dotnetcore/56.teams-file-upload/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Microsoft.BotBuilderSamples
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((logging) =>
{
logging.AddDebug();
logging.AddConsole();
})
.UseStartup<Startup>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:10757/",
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
Expand All @@ -15,13 +15,13 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"TeamsFileUpload": {
"TeamsFileBot": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:10758/"
"applicationUrl": "http://localhost:3978/"
}
}
}
Loading

0 comments on commit 4c794e4

Please sign in to comment.