From 4c794e4b94cbd4540c3fd045532cf6c41e714511 Mon Sep 17 00:00:00 2001 From: Josh <50158775+Virtual-Josh@users.noreply.github.com> Date: Wed, 30 Oct 2019 14:56:57 -0700 Subject: [PATCH] Josh/file upload (#1881) * 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 --- .../AdapterWithErrorHandler.cs | 27 ++ .../56.teams-file-upload/Bots/TeamsFileBot.cs | 159 +++++++ .../Controllers/BotController.cs | 35 ++ .../56.teams-file-upload/Files/teams-logo.png | Bin 0 -> 6412 bytes .../56.teams-file-upload/Program.cs | 20 +- .../Properties/launchSettings.json | 6 +- .../56.teams-file-upload/README.md | 106 +++-- .../56.teams-file-upload/Startup.cs | 59 +++ ...sFileUpload.csproj => TeamsFileBot.csproj} | 4 +- .../56.teams-file-upload/TeamsFileBot.sln | 25 ++ .../appsettings.Development.json | 9 + .../56.teams-file-upload/appsettings.json | 4 + .../56.teams-file-upload/manifest.json | 38 ++ .../56.teams-file-upload/wwwroot/default.html | 418 ++++++++++++++++++ .../57.teams-conversation-bot/README.md | 2 +- .../wwwroot/default.html | 14 +- .../50.teams-conversation-bot/README.md | 2 +- 17 files changed, 871 insertions(+), 57 deletions(-) create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/AdapterWithErrorHandler.cs create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/Bots/TeamsFileBot.cs create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/Controllers/BotController.cs create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/Files/teams-logo.png create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/Startup.cs rename samples/csharp_dotnetcore/56.teams-file-upload/{TeamsFileUpload.csproj => TeamsFileBot.csproj} (85%) create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.sln create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/appsettings.Development.json create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/appsettings.json create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/manifest.json create mode 100644 samples/csharp_dotnetcore/56.teams-file-upload/wwwroot/default.html diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/AdapterWithErrorHandler.cs b/samples/csharp_dotnetcore/56.teams-file-upload/AdapterWithErrorHandler.cs new file mode 100644 index 0000000000..a1586ace58 --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/AdapterWithErrorHandler.cs @@ -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 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."); + }; + } + } +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Bots/TeamsFileBot.cs b/samples/csharp_dotnetcore/56.teams-file-upload/Bots/TeamsFileBot.cs new file mode 100644 index 0000000000..d4f3e2e9c5 --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/Bots/TeamsFileBot.cs @@ -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 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(); + + 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 {file.Name}"; + 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 + { + { "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() { asAttachment }; + + await turnContext.SendActivityAsync(replyActivity, cancellationToken); + } + + protected override async Task OnTeamsFileConsentAcceptAsync(ITurnContext 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 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 {context["filename"]}."; + 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 = $"File uploaded. Your file {fileConsentCardResponse.UploadInfo.Name} is ready to download"; + reply.Attachments = new List { 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 = $"File upload failed. Error:
{error}
"; + await turnContext.SendActivityAsync(reply, cancellationToken); + } + } +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Controllers/BotController.cs b/samples/csharp_dotnetcore/56.teams-file-upload/Controllers/BotController.cs new file mode 100644 index 0000000000..35514d52ea --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/Controllers/BotController.cs @@ -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); + } + } +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Files/teams-logo.png b/samples/csharp_dotnetcore/56.teams-file-upload/Files/teams-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..78b0a0c308939206aee5f15e2c052def7a18a74e GIT binary patch literal 6412 zcmdT}XEa=GyC!uch!Q2b(PctHM2qr{(R&v)qD3&H4+ayjL5T9{83sWFqxVkKV3apn zgc*!BM2p@z^R4sqth3hnb=EmQ_I}pdd+ldm`+n|y-S>4p(FS_zH22u<|?CF(CwP_XuBLjE!dz-$o$Juxo!-*-uYbH{{Z zf-z!a>YX2V{c;bA|CRc6xdD`a0)CAoj>Pjf8GhSznB2E45PJ`>V9S20f@h0M9E zbMDN7DU>+`gD5CgXz6bNA_0`QR8SOu^MWZl>3HA2{y?Yv6awI31>T~g{=a@3M^Eah zZglnjag!2EXMZY;D%>y=^x=MOSMUtJ&FDU8L^uI|gq&8R3S zB-W?B7G7p!{d77}m~#~Hhl7s#nqp({Vne69a<6&CTa;Zo67d4{<{45YyaPKHLgfCM z;u+7E8}OmB)=N)@l%`5OK1h0kjF_2TgT@A0S%EpXh|O}`4!%EjY;a*+i*)vy)gUM< z{%O-!tX$<>P@|YvK@o_$v zYG*Y5@Bw{!-6z5#xk6VNw32$e~osPr)$zs2LDJ< zn&xqZ6;|cC*>uik&c9~{b1Ti#|u-E!7J?cL_(IUx2aQxsHr*Pg-47( zJOXGBm)SHk)g+^|PBBE0(y^@g=K&7+@TEutxOq`|eO_*7g=-OQkHskch~0ILrO_1FJF+#%qM5r+X-XirQRFQDx1bWRz5|$TH>EKmRrRD>*~yE>rHx=!j6tK zsI^T$Po$`!YKZ8UIStQs;~|(y(~-1Q0~ePf5iUAx zA6Xu#;uMl4&gy$N+yZ-J0~Nwo3*w?KYG~zS{&+iMG0dP}BnU#GYCjLqO_r8EpFr%ZBoPy#b&cr2L#YtDb3rqA>^`Y$Qy~6+XD74lEyvXNR?I~w z8y6cdn81-0{JS`Jpt#gH+3Asp7&{R4^SkVT^RTDI`TnsK!CSlL`_@UDQl6Pvv%Gwl zbbH-yI5K2%n`QLnML+Q}Bw0*IQR;Od9d9cwZV{8L6bxVDY=GYmPoK9yJqse#)nx`f z&OzEQ%yAzI7&n6)MqtHsydXzb=7PHeE)qq)w~!Rk95@6aNKPEYZmlPd@2rwBMKN46?5_-6>#-)p9Z07wH8 zK62(;-PmBo!(@2-kLN7e^HI0yc%5Uy@CZI>Q(r>%i2(xxZN+~doUoiyDN)KJUT zrys3;KSkc|J)E0usfV&J1h3r3-^=kU#3s!?K`7AX=$o3R4QCjSH<@VZ7f{m2l!xP!nk}SN4!(VrUZ4i&N`<@nAQ9vH&@!;H&?fFE|LdW3-xr{{NHZw zmKC1gWq>w-Gz-#!KvW)LpXN}1i`8xq}S4?i|0=EEG(gs`iEeRDaH}c?-L*S7_)aORDW$oUF3XnN(o4Lt<=^AvXH@ zEA{hS*Xtn_hFV&0*Es~8Kd)UdVSko@yzZ&~e4=WfbAH@Fh8?_qo4JuN=z+xV{u*r+ zNtMuEn*ab&b^jRb)Rf}Pb2rRDtCw@vb2C$Hmb)Q`?xn5AcX#$qIU)_&IDz0@>h3|u zIEVxiDk}dXn~O`2mSz|u^9+qE%W<+(%vq|Yv1Ep~q_!yf5mGCdi(;F1&X((F?^o8NHlBI@xXm*$T3!@Z^$vuy-&v_ z)_P>fdANq}R}@zOTqPu8tz+=_zXbe$8UG7idWuH2w>J;Ah#pV>pubv+LUf!=rnhpn zC=F~WDq0aS56=e3GpUU_9=iASuO3*BXcQbk!1{vw(O;^O49Ij3vj z?zdgkr;N~QZ!=z2WCqO*l4xwC{Rm@z<4=dIM|Al2$H$whtdppt5yV zo_w@oMqi_Sps!FqP%ki5Zfs>!`Ksi85bl89_O&CwU-Y^bZZYirnG4*v?CkPt#m+tW zG*zg=vG^OCaDHL`!opCRI<1RDkeG{OjkB1`>YkaH+v=XPB5Z|xBC~|cK^I2YAtL-? zZcQeeAsA2qNfNHxS1KK*PWZCEsGe^<*Sw`r^>(7|_wg+2e#dEK2IpugdG-vEe1MRU zq*cQqPNKm5XoZ`XWJjqL+iX2n0HZWpT`pdCAF+0S^@xOec2u9asM>rCC(Ili#PiB? zQ*WKmcVqKoX82jt1nn>uABS7ZYx>KyD%%h)SE=@*PlJ%(C%=;_9F-7#W* z-i`I~eA%C0q%)HRFTg9dJOM#XE48Htyq^2Od%ib4 zf7Q)s#U)#NKofktDSKY554+wCsbES|2JN;uqPb*)$^&L^2^j|=kzFH*(FF|)h);S_ zPRG~QKfMa$X-q2SYa2-xMZ_{ue4HB_^Y(TOYVcq&8zO6)BKY!iweZZ z;?>+-F&FIXGm?@j@u45TQK*+C?_$R!&r`(%SW(xEWls&P zXfc*wbIh7GiTpR9<^2be@-%3pdRQ-~u3JwA+p7f1Vaph81`k(SW|-mLOy>D@k?^(8 zQ#BWc(;NcwPjXHp)DL#5uB51(b`5rpOEpC8s$B~y)+ZqyMxsIEPHlfJVWtDC@@R^& z2g}Ccuy*@D&2AfJ8!wPGhtqTE-(S|x&vi{jxn>IMq$yX)W{pX=H<5g=e`Ct08;~b= zl{S4^v=`V6Apn1Jh*yTiL!3w_kh6O*Eb{ePi5=ocb%5q(=zBn?+CwxsM-?v;%g&Ez zDo)h=x7jYfMb$e?L}rcB*aGPPZtItDh`pFaw*FajP&X>RsBVY9lS9mp(gv?TZn+t% zPUR5}J3cNoh`h%hA53aFN1o4)H_T5RO*Qn1oj<`OZ*|D;ehZIMQuz#2PSs&{Zk${ zlS$QL>C4t#akDf))GG{Q-&zOW&*SB`_*gtBsmC_N?_hTRmk>_dW_IgPR5BW`zb(&? zBiGyKrrs?~QKC+gYI0>RK4yXrpP1poLsx}BW@GG9hfE($7+EQWbG53<2~9%_FL9i>A_Tx9ay0cmt(S`Ecxv9v;%_TfCXLWW{WAQo z0<$Kc$JV|h;murlS)nOCFQ890QNXO{mIyEA(`p{~eE|;Otxji#vj-h;H(d{Ua{$L0 zd)r2i|Fpj*%^c(3uQ4nk*Hl5oc=%B`!2YrZhD6bkr7QWN|4r#?ab5kYdxU%PBN>9W zfZw|%m*%*rJC#~$-;Ef$6X}#O#)XCaRAecgq_KSWZZfqxn8J{j`;k(pL>M3M`=?f1 zig|LIRy=>9D%-c_6nqyJP@vhfKf0AUj)B^ zO$TayrJxs!cJdluPV0R#BFmz{)`&qvw%zRJPiKfC=iGOwc&pbaQzB<9=leBYq)Qu# z@TE!^xe}^n98!$HB2Fm}+dromXvqjA_56bsURqj5UT((MxQu6rMswkkc)D;7v7rl> zZQKFZUGt;PalSMC&T%?sqmHre^?y`GooU8v@nWjqEO43j79D{XYlLHt6elcJz>^xJ zjCx$?TK$zsSsM{N_tNwAa{IZRLg*Vc)8edjw`;|hQLnekoO#!4uO`L|vjhD-=dY-A zleN|;WFF9WWk~4aB%b71A3)=t_{idV9Q{2#u^q@DQaOZ!q{U#y7M_QMr*Fbf+wkqT z9gA)v%WWV^N=h+1mnEmsr)7CG#4FvkbO6hXb| z=DXqM7{Gt}PnrYPA#3PsDG&m1>#RO`utQL%5-BbKx!t1gvJ6-@kAiQrdCB|<89ck7E)DzMz;(U@>sa*11@JbrLIAxEZ5QjjljYQb(-EQ^s5oqj}pdC|$|5@if+ z*qrbLFYb{AMIMSyYrDO0=Z78l#&(P~!b4Z3ZFJqY(RxsT)(IV(IPkmJq`d-0u6B_L zTv=>6L$Vx08@+uuv?Bn-R z{TNK;VDcu#XwiQuy4E{j^R?mrUol+$a#8z*|E*Kyya9M*b_IS^2}7m)C|<|+K-3PD zDPnN#kDVQ(xn$)oi3y6^-UDQpA_&p7+o;5`cPl(&Etj%X@LWv;U?1zPC-G=0BFn}9 zrKIrVQtX)NBfq|-D;mO&Rp$<4<3B`4gWsE1)Y+H9)@n=$uW%q zO7*stJz**<%O%Tf<7B&o*OX>m+w`_?6*XQ7W{7&}-MN!os3#O!Q)egL=(-n2=o~gz zpPdaiO>Li%<9-nonPi|vFZQ&f4;ji{aTV6H%Q%jr%lSzUkYQsBw#g#WumcryR`;=u zY!sWtD87pja%-sxL@n?2p=SF+7mC>am|}*)?wa3!-Kh&a6KAoWlzsP% z3vAb5@Y#fgoUenbtRJj{NQ>Ud)w0T@7#YG9|YKkh;9H_J|Tr(eS+43eCDsJ6cFmN zLTSArir>G^^?#kya2Vo_3%WrG!iPgWKnu@M4I?_TM8ky#1;;90!t3}+=ddP~SFW^c*MobKCkc*(6;gg2Dc0l6O3)}t~q zZ|14r6SzY!HjD4#1mcpgT9{<=+6)*=MtWIF%jDO(I21Jq;qe?rB_%~=yD?ni)11Io zqx;O;o_g_InL%6s@aIk}rM1}#%vpGu!fMN&tnJI*q!g;znRMW}1GIKZVR-em8blBF zC1iZ+kB@iG4%w!5swJnM9SIt9K0DLJxy9Qs8@A7_OlNOs6F>#vUB)+UoUk0&lFJA{`b%rJ1)=xF8m9gbQLMT0C8X1j(8kxz;~%^8uGv%W~hR zhN>Uz33ugYyW`?QBexW^ZUI52EMoW{CS9_!f$vty7ECwCKl^E4H3>GIG=$vMRb`d7 zj^-J@pw>!ZNTVLcu2BWxMP6BzD4}y&Jp(P%)Fx|hb*n$WOGKBvkUR_2Q8p+#%`UX2 zl`?9Bu>g|xipW4WqA5|l6XbP*CXEV9d{o2K)s?5M@;JDMCV=Pw^ySF=N6@U7>6|(J zn}LBChCJ-Fo%&0Ng{>IAg~|O!g&M{GTg&}FHw!M6L>f~9&lv2f$lDtfnyPw`a`5ZF F{{vnI6G{L8 literal 0 HcmV?d00001 diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Program.cs b/samples/csharp_dotnetcore/56.teams-file-upload/Program.cs index c86ee6a28d..4f3700fcb7 100644 --- a/samples/csharp_dotnetcore/56.teams-file-upload/Program.cs +++ b/samples/csharp_dotnetcore/56.teams-file-upload/Program.cs @@ -1,8 +1,12 @@ -// 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 { @@ -10,6 +14,16 @@ 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(); } } diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Properties/launchSettings.json b/samples/csharp_dotnetcore/56.teams-file-upload/Properties/launchSettings.json index 605769dd84..5f54d66b11 100644 --- a/samples/csharp_dotnetcore/56.teams-file-upload/Properties/launchSettings.json +++ b/samples/csharp_dotnetcore/56.teams-file-upload/Properties/launchSettings.json @@ -3,7 +3,7 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:10757/", + "applicationUrl": "http://localhost:3978/", "sslPort": 0 } }, @@ -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/" } } } \ No newline at end of file diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/README.md b/samples/csharp_dotnetcore/56.teams-file-upload/README.md index 9e57d6068f..2af02c82ef 100644 --- a/samples/csharp_dotnetcore/56.teams-file-upload/README.md +++ b/samples/csharp_dotnetcore/56.teams-file-upload/README.md @@ -1,30 +1,72 @@ -# EchoBot +## TeamsFileUploadBot -Bot Framework v4 Teams File Upload sample. +Bot Framework v4 file upload bot sample for Teams. -This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that performs file uploads. +This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back. ## Prerequisites + - [.NET Core SDK](https://dotnet.microsoft.com/download) version 2.1 ```bash # determine dotnet version dotnet --version ``` + +- Microsoft Teams is installed and you have an account ## To try this sample +### Clone the repo - Clone the repository ```bash git clone https://github.com/Microsoft/botbuilder-samples.git ``` -- In a terminal, navigate to `samples/csharp_dotnetcore/56.teams-file-upload` -- Run the bot from a terminal or from Visual Studio, choose option A or B. - - A) From a terminal +### Ngrok +- Download and install [ngrok](https://ngrok.com/download) +- In terminal navigate to where ngrok is installed and run: + +```bash +ngrok http -host-header=rewrite 3978 +``` +- Copy/paste the ```https``` **NOT** the ```http``` web address into notepad as you will need it later + +### Creating the bot registration +- Create a new bot [here](https://dev.botframework.com/bots/new) +- Enter a```Display name``` and ```Bot handle``` +- In the ```Messaging endpoint``` enter the https address from Ngrok and add ```/api/messages``` to the end + - EX: ```https://7d899fbb.ngrok.io/api/messages``` +- Open the ```Create Microsoft App ID and password``` link in a new tab +- Click on the ```New registration``` button +- Enter a name, and select the ```Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)``` +- Click ```Register``` +- Copy & paste the ```Application (client) ID``` field into notepad. This is your botID. +- Click on ```Certificates & secrets``` tab on the left +- Click ```New client secret``` +- Enter a name, select `Never`, and click ```Add``` +- Copy & paste the password into notepad. This is your app password. +- Go back to the bot registration tab and enter the ```botID``` into the app ID field +- Scroll down, agree to the Terms, and click ```Register``` +- Click the ```Microsoft Teams``` icon on the next screen +- Click ```Save``` + +### Visual Studio +- Launch Visual Studio +- Navigate to and open the `samples/csharp_dotnet/56.teams-conversation-bot` directory +- Open the ```appsettings.json``` file +- Paste your botID value into the ```MicrosoftAppId``` field +- Put the password into the ```MicrosoftAppPassword``` field +- Save the file +- Open the ```manifest.json``` +- Replace your botID everywhere you see the place holder string ```<>``` + + +- Run the bot: + + A) From a terminal ```bash # run the bot @@ -33,36 +75,26 @@ This bot has been created using [Bot Framework](https://dev.botframework.com), i B) Or from Visual Studio - - Launch Visual Studio - File -> Open -> Project/Solution - - Navigate to `samples/csharp_dotnetcore/56.teams-file-upload` folder - - Select `TeamsFileUpload.csproj` file + - Navigate to `samples/csharp_dotnetcore/56.teams-conversation-bot` folder + - Select `TeamsConversationBot.csproj` file - Press `F5` to run the project -## Testing the bot using Teams - -1) run ngrok - point to port 3978 -1) create bot framework registration - using ngrok URL -1) update your manifest.json to include the app id from bot framework -1) zip up teams-manifest folder to create a manifest.zip -1) upload manifest.zip to teams (from Apps view click "Upload a custom app") -1) pick your bot from the compose command menu - -## Deploy the bot to Azure - -To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions. - -## Further reading - -- [Bot Framework Documentation](https://docs.botframework.com) -- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) -- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0) -- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0) -- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) -- [.NET Core CLI tools](https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x) -- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest) -- [Azure Portal](https://portal.azure.com) -- [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/) -- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0) -- [Restify](https://www.npmjs.com/package/restify) -- [dotenv](https://www.npmjs.com/package/dotenv) +### Teams - App Studio +- Launch Microsoft Teams +- In the bar at the top of Teams search for and select ```App Studio``` +- Click the ```Manifest editor``` tab +- Click ```Import an existing app``` +- Navigate to and select the `manifest.json` file from the previous step +- Click on the `TeamsConversationBot` card +- Click ```Test and distribute``` on the left hand side +- Click the ```Install``` button + +| To install bot in a personal chat... | To install in a group chat... | To install in team chat... | +|:-------------------- | :------------------------- | :-----------------------| +| 1. Click ```Add``` button| This feature does not work in this scope. | This feature does not work in this scope. | + +### Interacting with the bot + +If you send a message to the bot it will respond with a card that will prompt you to upload a file. The file that's being uploaded is the `teams-logo.png` in the `Files` directory in this sample. You can message the bot again to receive another prompt. + diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/Startup.cs b/samples/csharp_dotnetcore/56.teams-file-upload/Startup.cs new file mode 100644 index 0000000000..b61cabefca --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/Startup.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Integration.AspNet.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +using Microsoft.BotBuilderSamples.Bots; + +namespace Microsoft.BotBuilderSamples +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); + + // Create the Bot Framework Adapter with error handling enabled. + services.AddSingleton(); + + // The Bot needs an HttpClient to download and upload files. + services.AddHttpClient(); + + // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. + services.AddTransient(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseHsts(); + } + + app.UseDefaultFiles(); + app.UseStaticFiles(); + + // app.UseHttpsRedirection(); + app.UseMvc(); + } + } +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileUpload.csproj b/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.csproj similarity index 85% rename from samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileUpload.csproj rename to samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.csproj index 201362ccd9..a263de480a 100644 --- a/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileUpload.csproj +++ b/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1 @@ -7,7 +7,7 @@ - + diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.sln b/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.sln new file mode 100644 index 0000000000..a5688d31c5 --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/TeamsFileBot.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29123.88 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeamsFileBot", "TeamsFileBot.csproj", "{2B15EEA3-EFD3-4766-9566-3C3FC4286B3F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2B15EEA3-EFD3-4766-9566-3C3FC4286B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B15EEA3-EFD3-4766-9566-3C3FC4286B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B15EEA3-EFD3-4766-9566-3C3FC4286B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B15EEA3-EFD3-4766-9566-3C3FC4286B3F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3D32DADF-626A-4BC5-BECB-1482B1F9A9A5} + EndGlobalSection +EndGlobal diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.Development.json b/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.Development.json new file mode 100644 index 0000000000..e203e9407e --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.json b/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.json new file mode 100644 index 0000000000..97dff81a1b --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/appsettings.json @@ -0,0 +1,4 @@ +{ + "MicrosoftAppId": "", + "MicrosoftAppPassword": "" +} diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/manifest.json b/samples/csharp_dotnetcore/56.teams-file-upload/manifest.json new file mode 100644 index 0000000000..c6192a5b76 --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/manifest.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json", + "manifestVersion": "1.5", + "version": "1.0", + "id": "<>", + "packageName": "com.microsoft.teams.fileupload", + "developer": { + "name": "Microsoft Corp", + "websiteUrl": "https://example.azurewebsites.net", + "privacyUrl": "https://example.azurewebsites.net/privacy", + "termsOfUseUrl": "https://example.azurewebsites.net/termsofuse" + }, + "name": { + "short": "FileUpload", + "full": "FileUpload" + }, + "description": { + "short": "Sample bot using V4 SDK to demo bot file features", + "full": "Sample bot using V4 Bot Builder SDK and V4 Microsoft Teams Extension SDK to demo bot file features" + }, + "icons": { + "outline": "outline.png", + "color": "color.png" + }, + "accentColor": "#abcdef", + "bots": [ + { + "botId": "<>", + "scopes": [ + "personal" + ], + "supportsFiles": true + } + ], + "validDomains": [ + "*.azurewebsites.net" + ] +} \ No newline at end of file diff --git a/samples/csharp_dotnetcore/56.teams-file-upload/wwwroot/default.html b/samples/csharp_dotnetcore/56.teams-file-upload/wwwroot/default.html new file mode 100644 index 0000000000..9585dff068 --- /dev/null +++ b/samples/csharp_dotnetcore/56.teams-file-upload/wwwroot/default.html @@ -0,0 +1,418 @@ + + + + + + + EchoBot + + + + + +
+
+
+
EchoBot
+
+
+
+
+
Your bot is ready!
+
You can test your bot in the Bot Framework Emulator
+ by connecting to http://localhost:3978/api/messages.
+ +
Visit Azure + Bot Service to register your bot and add it to
+ various channels. The bot's endpoint URL typically looks + like this:
+
https://your_bots_hostname/api/messages
+
+
+
+
+ +
+ + + diff --git a/samples/csharp_dotnetcore/57.teams-conversation-bot/README.md b/samples/csharp_dotnetcore/57.teams-conversation-bot/README.md index 6348194ee6..e615946afe 100644 --- a/samples/csharp_dotnetcore/57.teams-conversation-bot/README.md +++ b/samples/csharp_dotnetcore/57.teams-conversation-bot/README.md @@ -1,6 +1,6 @@ # TeamsConversationBot -Bot Framework v4 echo bot sample for Teams. +Bot Framework v4 Teams conversation bot sample for Teams. This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back. diff --git a/samples/csharp_dotnetcore/57.teams-conversation-bot/wwwroot/default.html b/samples/csharp_dotnetcore/57.teams-conversation-bot/wwwroot/default.html index 9585dff068..6539d15a1f 100644 --- a/samples/csharp_dotnetcore/57.teams-conversation-bot/wwwroot/default.html +++ b/samples/csharp_dotnetcore/57.teams-conversation-bot/wwwroot/default.html @@ -392,21 +392,15 @@
-
EchoBot
+
TeamsConversationBot
Your bot is ready!
-
You can test your bot in the Bot Framework Emulator
- by connecting to http://localhost:3978/api/messages.
- -
Visit Azure - Bot Service to register your bot and add it to
- various channels. The bot's endpoint URL typically looks - like this:
-
https://your_bots_hostname/api/messages
+
You can test your bot in Microsoft Teams by uploading your manifest into + App Studio.
+
diff --git a/samples/javascript_nodejs/50.teams-conversation-bot/README.md b/samples/javascript_nodejs/50.teams-conversation-bot/README.md index 5b1395f752..05c9dab5ed 100644 --- a/samples/javascript_nodejs/50.teams-conversation-bot/README.md +++ b/samples/javascript_nodejs/50.teams-conversation-bot/README.md @@ -1,6 +1,6 @@ # TeamsConversationBot -Bot Framework v4 echo bot sample for Teams. +Bot Framework v4 Teams conversation bot sample for Teams. This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back.