diff --git a/MessengerBot/Controllers/WebhookController.cs b/MessengerBot/Controllers/WebhookController.cs index acef78d..8de3d22 100644 --- a/MessengerBot/Controllers/WebhookController.cs +++ b/MessengerBot/Controllers/WebhookController.cs @@ -8,93 +8,180 @@ using System.Text; using System.Threading.Tasks; using System.Web.Http; -using MessengerBot.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Bot.Messenger; +using System.Web.Http.Controllers; +using Bot.Messenger.Models; namespace MessengerBot.Controllers { - public class WebhookController : ApiController - { - string pageToken = "page token"; - string appSecret = "app secret"; - - public HttpResponseMessage Get() - { - var querystrings = Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value); - if (querystrings["hub.verify_token"] == "hello") - { - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(querystrings["hub.challenge"], Encoding.UTF8, "text/plain") - }; - } - return new HttpResponseMessage(HttpStatusCode.Unauthorized); - } - - [HttpPost] - public async Task Post() - { - var signature = Request.Headers.GetValues("X-Hub-Signature").FirstOrDefault().Replace("sha1=", ""); - var body = await Request.Content.ReadAsStringAsync(); - if (!VerifySignature(signature, body)) - return new HttpResponseMessage(HttpStatusCode.BadRequest); - - var value = JsonConvert.DeserializeObject(body); - if (value._object != "page") - return new HttpResponseMessage(HttpStatusCode.OK); - - foreach (var item in value.entry[0].messaging) - { - if (item.message == null && item.postback == null) - continue; - else - await SendMessage(GetMessageTemplate(item.message.text, item.sender.id)); - } - - return new HttpResponseMessage(HttpStatusCode.OK); - } - - private bool VerifySignature(string signature, string body) - { - var hashString = new StringBuilder(); - using (var crypto = new HMACSHA1(Encoding.UTF8.GetBytes(appSecret))) - { - var hash = crypto.ComputeHash(Encoding.UTF8.GetBytes(body)); - foreach (var item in hash) - hashString.Append(item.ToString("X2")); - } - - return hashString.ToString().ToLower() == signature.ToLower(); - } - - /// - /// get text message template - /// - /// text - /// sender id - /// json - private JObject GetMessageTemplate(string text, string sender) - { - return JObject.FromObject(new - { - recipient = new { id = sender }, - message = new { text = text } - }); - } - - /// - /// send message - /// - /// json - private async Task SendMessage(JObject json) - { - using (HttpClient client = new HttpClient()) - { - client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - HttpResponseMessage res = await client.PostAsync($"https://graph.facebook.com/v2.6/me/messages?access_token={pageToken}", new StringContent(json.ToString(), Encoding.UTF8, "application/json")); - } - } - } + public class WebhookController : ApiController + { + string _pageToken = "page token"; + string _appSecret = "app secret"; + string _verifyToken = "hello"; + + string _quickReplyPayload_IsUserMsg = "WAS_USER_MESSAGE"; + string _quickReplyPayload_IsNotUserMsg = "WAS_NOT_USER_MESSAGE"; + + + private MessengerPlatform _Bot { get; set; } + + protected override void Initialize(HttpControllerContext controllerContext) + { + base.Initialize(controllerContext); + + /***Credentials are fetched from web.config ApplicationSettings when the CreateInstance + ----method is called without a credentials parameter or if the parameterless constructor + ----is used to initialize the MessengerPlatform class. This holds true for all types that inherit from + ----Bot.Messenger.ApiBase + + _Bot = MessengerPlatform.CreateInstance(); + _Bot = new MessengerPlatform(); + ***/ + + _Bot = MessengerPlatform.CreateInstance( + MessengerPlatform.CreateCredentials(_appSecret, _pageToken, _verifyToken)); + } + + public HttpResponseMessage Get() + { + var querystrings = Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value); + + if (_Bot.Authenticator.VerifyToken(querystrings["hub.verify_token"])) + { + return new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(querystrings["hub.challenge"], Encoding.UTF8, "text/plain") + }; + } + + return new HttpResponseMessage(HttpStatusCode.Unauthorized); + } + + [HttpPost] + public async Task Post() + { + var body = await Request.Content.ReadAsStringAsync(); + + LogInfo("WebHook_Received", new Dictionary + { + { "Request Body", body } + }); + + if (!_Bot.Authenticator.VerifySignature(Request.Headers.GetValues("X-Hub-Signature").FirstOrDefault(), body)) + return new HttpResponseMessage(HttpStatusCode.BadRequest); + + WebhookModel webhookModel = _Bot.ProcessWebhookRequest(body); + + if (webhookModel._Object != "page") + return new HttpResponseMessage(HttpStatusCode.OK); + + foreach (var entry in webhookModel.Entries) + { + foreach (var evt in entry.Events) + { + if (evt.EventType == WebhookEventType.PostbackRecievedCallback + || evt.EventType == WebhookEventType.MessageReceivedCallback) + { + await _Bot.SendApi.SendActionAsync(evt.Sender.ID, SenderAction.typing_on); + + var userProfileRsp = await _Bot.UserProfileApi.GetUserProfileAsync(evt.Sender.ID); + + if (evt.EventType == WebhookEventType.PostbackRecievedCallback) + { + await ProcessPostBack(evt.Sender.ID, userProfileRsp?.FirstName, evt.Postback); + } + if (evt.EventType == WebhookEventType.MessageReceivedCallback) + { + if (evt.Message.IsQuickReplyPostBack) + await ProcessPostBack(evt.Sender.ID, userProfileRsp?.FirstName, evt.Message.QuickReplyPostback); + else + { + await _Bot.SendApi.SendTextAsync(evt.Sender.ID, $"We got your message {userProfileRsp?.FirstName}, to prove it, we'll send it back to you :)"); + await ResendMessageToUser(evt); + await ConfirmIfCorrect(evt); + } + } + } + + await _Bot.SendApi.SendActionAsync(evt.Sender.ID, SenderAction.typing_off); + + } + } + + return new HttpResponseMessage(HttpStatusCode.OK); + } + + private async Task ConfirmIfCorrect(WebhookEvent evt) + { + SendApiResponse sendQuickReplyResponse = await _Bot.SendApi.SendTextAsync(evt.Sender.ID, "Is that you message?", new List + { + new QuickReply + { + ContentType = QuickReplyContentType.text, + Title = "Yes", + Payload = _quickReplyPayload_IsUserMsg + }, + new QuickReply + { + ContentType = QuickReplyContentType.text, + Title = "No", + Payload = _quickReplyPayload_IsNotUserMsg + } + }); + + LogSendApiResponse(sendQuickReplyResponse); + } + + private async Task ResendMessageToUser(WebhookEvent evt) + { + SendApiResponse response = new SendApiResponse(); + + if (evt.Message.Attachments == null) + { + string text = evt.Message?.Text; + + if (string.IsNullOrWhiteSpace(text)) + text = "Hello :)"; + + response = await _Bot.SendApi.SendTextAsync(evt.Sender.ID, $"Your Message => {text}"); + } + else + { + foreach (var attachment in evt.Message.Attachments) + { + if (attachment.Type != AttachmentType.fallback && attachment.Type != AttachmentType.location) + { + response = await _Bot.SendApi.SendAttachmentAsync(evt.Sender.ID, attachment); + } + } + } + + LogSendApiResponse(response); + } + + private async Task ProcessPostBack(string userId, string username, Postback postback) + { + if (postback.Payload == _quickReplyPayload_IsNotUserMsg) + await _Bot.SendApi.SendTextAsync(userId, $"Sorry about that {username}, try sending something else."); + else if (postback.Payload == _quickReplyPayload_IsUserMsg) + await _Bot.SendApi.SendTextAsync(userId, $"Yay! We got it."); + } + + private static void LogSendApiResponse(SendApiResponse response) + { + LogInfo("SendApi Web Request", new Dictionary + { + { "Response", response?.ToString() } + }); + } + + private static void LogInfo(string eventName, Dictionary telemetryProperties) + { + //Log telemetry in DB or Application Insights + } + } } diff --git a/MessengerBot/MessengerBot.csproj b/MessengerBot/MessengerBot.csproj index bc408c9..67c651e 100644 --- a/MessengerBot/MessengerBot.csproj +++ b/MessengerBot/MessengerBot.csproj @@ -43,6 +43,10 @@ 4 + + ..\packages\Bot.Messenger.1.0.0\lib\net45\Bot.Messenger.dll + True + ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.1\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll True diff --git a/MessengerBot/Web.config b/MessengerBot/Web.config index 8adbf31..dbb71ec 100644 --- a/MessengerBot/Web.config +++ b/MessengerBot/Web.config @@ -4,6 +4,24 @@ http://go.microsoft.com/fwlink/?LinkId=301879 --> + + +
+ + + + + + page token + + + app secret + + + hello + + + diff --git a/MessengerBot/packages.config b/MessengerBot/packages.config index 98379d2..39f2d5a 100644 --- a/MessengerBot/packages.config +++ b/MessengerBot/packages.config @@ -1,5 +1,6 @@  + diff --git a/README.md b/README.md index 5b54e96..7f194f3 100644 Binary files a/README.md and b/README.md differ