Last active
November 18, 2016 16:31
-
-
Save davidknipe/d796330255bf7703a6a6ff9cfa9c6f2f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace EpiBot.Models | |
| { | |
| public class ApprovalDecision | |
| { | |
| public string Decision; | |
| public int StepId; | |
| public int ActiveStepIndex; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| namespace EpiBot.Models | |
| { | |
| public class ApprovalDetail | |
| { | |
| public string ContentUrl; | |
| public string ThumbUrl | |
| { | |
| get | |
| { | |
| if (ContentUrl.Contains("?")) | |
| return ContentUrl + "&w=300"; | |
| return ContentUrl + "?w=300"; | |
| } | |
| } | |
| public DateTime Started; | |
| public string StartedBy; | |
| public int StepId; | |
| public int ActiveStepIndex; | |
| public int ContentId; | |
| public int WorkId; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Net.Http; | |
| using System.Net.Http.Headers; | |
| using System.Threading.Tasks; | |
| using System.Web.Compilation; | |
| using EpiBot.Models; | |
| namespace EpiBot.Impl | |
| { | |
| public class ApprovalsRepo | |
| { | |
| private readonly HttpClient _client; | |
| public ApprovalsRepo() | |
| { | |
| _client = new HttpClient(); | |
| _client.BaseAddress = new Uri(AppSettingsExpressionBuilder.GetAppSetting("EpiRootUrl").ToString()); | |
| _client.DefaultRequestHeaders.Accept.Clear(); | |
| _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | |
| } | |
| public async Task<IEnumerable<ApprovalDetail>> GetAllApprovals() | |
| { | |
| IEnumerable<ApprovalDetail> allApprovals = null; | |
| HttpResponseMessage response = await _client.GetAsync("api/approvals"); | |
| if (response.IsSuccessStatusCode) | |
| { | |
| allApprovals = await response.Content.ReadAsAsync<IEnumerable<ApprovalDetail>>(); | |
| } | |
| return allApprovals; | |
| } | |
| public async void SendApprovalDecisionAsync(ApprovalDecision approvalDecision) | |
| { | |
| HttpResponseMessage response = await _client.PostAsJsonAsync("api/approvals", approvalDecision); | |
| response.EnsureSuccessStatusCode(); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Net; | |
| using System.Net.Http; | |
| using System.Threading.Tasks; | |
| using System.Web.Http; | |
| using EpiBot.Impl; | |
| using EpiBot.Models; | |
| using Microsoft.Bot.Connector; | |
| namespace EpiBot.Controllers | |
| { | |
| [BotAuthentication] | |
| public class MessagesController : ApiController | |
| { | |
| /// <summary> | |
| /// POST: api/Messages | |
| /// Receive a message from a user and reply to it | |
| /// </summary> | |
| public async Task<HttpResponseMessage> Post([FromBody]Activity activity) | |
| { | |
| var handler = new MessageHandler(activity); | |
| var repo = new ApprovalsRepo(); | |
| if (activity.Type == ActivityTypes.Message) | |
| { | |
| ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl)); | |
| if (activity.Text.Contains("Reject")) | |
| { | |
| await handler.HandleReject(); | |
| } | |
| else if (activity.Text.Contains("Approve")) | |
| { | |
| await handler.HandleAccept(); | |
| } | |
| else | |
| { | |
| // Check for approvals | |
| var allApprovals = await repo.GetAllApprovals(); | |
| if (allApprovals == null || !allApprovals.Any()) | |
| { | |
| await handler.HandleNothingToDo(); | |
| } | |
| await handler.HandleNextApproval(allApprovals.First(), false); | |
| } | |
| } | |
| else if (activity.Type == ActivityTypes.ConversationUpdate) | |
| { | |
| await handler.HandleNewConversation(); | |
| } | |
| else | |
| { | |
| HandleSystemMessage(activity, handler); | |
| } | |
| var response = Request.CreateResponse(HttpStatusCode.OK); | |
| return response; | |
| } | |
| private Activity HandleSystemMessage(Activity message, MessageHandler handler) | |
| { | |
| if (message.Type == ActivityTypes.DeleteUserData) | |
| { | |
| // Implement user deletion here | |
| // If we handle user deletion, return a real message | |
| } | |
| else if (message.Type == ActivityTypes.ConversationUpdate) | |
| { | |
| // Handle conversation state changes, like members being added and removed | |
| // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info | |
| // Not available in all channels | |
| } | |
| else if (message.Type == ActivityTypes.ContactRelationUpdate) | |
| { | |
| // Handle add/remove from contact lists | |
| // Activity.From + Activity.Action represent what happened | |
| } | |
| else if (message.Type == ActivityTypes.Typing) | |
| { | |
| // Handle knowing tha the user is typing | |
| } | |
| else if (message.Type == ActivityTypes.Ping) | |
| { | |
| } | |
| return null; | |
| } | |
| } | |
| class MessageHandler | |
| { | |
| private Activity activity; | |
| ConnectorClient connector; | |
| ApprovalsRepo repo; | |
| public MessageHandler(Activity activity) | |
| { | |
| this.activity = activity; | |
| connector = new ConnectorClient(new Uri(activity.ServiceUrl)); | |
| repo = new ApprovalsRepo(); | |
| } | |
| public async Task HandleAccept() | |
| { | |
| repo.SendApprovalDecisionAsync(GetDecisionData(activity.Text)); | |
| Activity reply = activity.CreateReply($"Great news (happy)! It's been accepted."); | |
| await connector.Conversations.ReplyToActivityAsync(reply); | |
| await AnyMoreApprovals(); | |
| } | |
| public async Task HandleReject() | |
| { | |
| repo.SendApprovalDecisionAsync(GetDecisionData(activity.Text)); | |
| Activity reply = activity.CreateReply($"Aww sorry to hear that (sad), it's been rejected."); | |
| await connector.Conversations.ReplyToActivityAsync(reply); | |
| await AnyMoreApprovals(); | |
| } | |
| public async Task HandleNothingToDo() | |
| { | |
| Activity noDataReply = activity.CreateReply($"Great news, there's nothing to do here (happy)!"); | |
| await connector.Conversations.ReplyToActivityAsync(noDataReply); | |
| } | |
| public async Task HandleNewConversation() | |
| { | |
| Activity noDataReply = activity.CreateReply($"Hi I'm epibot. You can ask me what Episerver has for you and I can let you know if you have any outstanding content approval requests."); | |
| await connector.Conversations.ReplyToActivityAsync(noDataReply); | |
| } | |
| public async Task HandleNextApproval(ApprovalDetail approval, bool isNext) | |
| { | |
| Activity reply; | |
| if (isNext) | |
| { | |
| reply = activity.CreateReply($"The next item that needs your sign off is this:"); | |
| } | |
| else | |
| { | |
| reply = activity.CreateReply($"The first item that needs your sign off is this:"); | |
| } | |
| reply.Type = "message"; | |
| reply.Attachments = new List<Attachment>(); | |
| List<CardImage> cardImages = new List<CardImage>(); | |
| cardImages.Add(new CardImage(url: approval.ThumbUrl)); | |
| List<CardAction> cardButtons = new List<CardAction>(); | |
| // View button | |
| cardButtons.Add(new CardAction() | |
| { | |
| Value = approval.ContentUrl, | |
| Type = "openUrl", | |
| Title = "View" | |
| }); | |
| // Approve button | |
| cardButtons.Add(new CardAction() | |
| { | |
| Value = GetDecisionPostBackData("Approve", approval), | |
| Type = "postBack", | |
| Title = "Approve" | |
| }); | |
| // Decline button | |
| cardButtons.Add(new CardAction | |
| { | |
| Value = GetDecisionPostBackData("Reject", approval), | |
| Type = "postBack", | |
| Title = "Reject" | |
| }); | |
| HeroCard plCard = new HeroCard() | |
| { | |
| Title = "Requested by: " + approval.StartedBy, | |
| Subtitle = "On " + approval.Started.ToString("dd/MM/yyyy HH:MM"), | |
| Images = cardImages, | |
| Buttons = cardButtons | |
| }; | |
| Attachment plAttachment = plCard.ToAttachment(); | |
| reply.Attachments.Add(plAttachment); | |
| await connector.Conversations.ReplyToActivityAsync(reply); | |
| } | |
| private async Task AnyMoreApprovals() | |
| { | |
| var allApprovals = await repo.GetAllApprovals(); | |
| if (allApprovals.Any()) | |
| { | |
| Activity moreToDoReply = activity.CreateReply($"Seems it's busy here today, getting the next thing for your attention."); | |
| await connector.Conversations.ReplyToActivityAsync(moreToDoReply); | |
| await HandleNextApproval(allApprovals.First(), true); | |
| } | |
| } | |
| private ApprovalDecision GetDecisionData(string postBackValue) | |
| { | |
| return new ApprovalDecision() | |
| { | |
| Decision = postBackValue.Split('_')[0], | |
| StepId = int.Parse(postBackValue.Split('_')[1]), | |
| ActiveStepIndex = int.Parse(postBackValue.Split('_')[2]) | |
| }; | |
| } | |
| private string GetDecisionPostBackData(string decision, ApprovalDetail approval) | |
| { | |
| return decision + "_" + approval.StepId + "_" + approval.ActiveStepIndex; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment