public static async Task <int?> GetResearchVsoIdFromVso(string channelId, string uniqueName)
        {
            var properties = new Dictionary <string, string>
            {
                { "class", "ConversationHelpers" },
                { "function", "GetResearchVsoIdFromVso" },
                { "channelId", channelId },
                { "from", uniqueName }
            };

            int?vsoId = null;

            try
            {
                var workItems = await VsoHelper.GetWorkItemsForUser(
                    VsoHelper.ResearchTaskType,
                    channelId,
                    //channelId == ActivityHelper.SmsChannelId ? PromptPhoneNumber.FormatPhoneNumber(uniqueName) : uniqueName);
                    uniqueName);

                if (workItems != null)
                {
                    vsoId = workItems.Select(wi => wi.Id).FirstOrDefault();
                }
            }
            catch (System.Exception e)
            {
                WebApiConfig.TelemetryClient.TrackException(e, properties);
            }
            properties.Add("vsoId", vsoId != null ? vsoId.ToString() : "not set");

            WebApiConfig.TelemetryClient.TrackEvent("GetResearchVsoIdFromVso", properties);

            return(vsoId);
        }
        public async Task StartAsync(IDialogContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var activity = (IMessageActivity)context.Activity;

            EndUserAndAgentConversationMappingState mappingState =
                await VsoHelper.GetStateFromVsoGivenAgentConversationId(activity.Conversation.Id);

            if (ActivityHelper.HasAttachment(activity))
            {
                await context.PostWithRetryAsync(
                    $"Sending file attachments to user is not supported. " +
                    $"Please send it via SharePoint > Share > Email. Email is in VSO ticket");
            }
            else
            {
                await ActivityHelper.SendMessageToUserEx((IMessageActivity)context.Activity,
                                                         mappingState.EndUserName,
                                                         mappingState.EndUserId,
                                                         activity.Text.Replace(DialogMatches.ReplyToUser + " ", ""),
                                                         mappingState.VsoId);
            }

            await OnlineStatus.SetMemberActive(
                context.Activity.From.Name,
                context.Activity.From.Id,
                OnlineStatus.AgentMemberType);

            context.Done <object>(null);
        }
Ejemplo n.º 3
0
        public bool Vote(string key, int item)
        {
            try
            {
                if (key != null && new[] { 1, 2 }.Contains(item))
                {
                    var itemNumber = item == 1 ? ItemNumber.Item1 : ItemNumber.Item2;
                    var submission = _submissionEntityService.IncrementVote(itemNumber, key);
                    // tell everyone the updated count
                    Clients.Group(key).UpdateVotes(submission.Item1Votes, submission.Item2Votes);

                    // is the updated count more than the threshold? If so, create a work item
                    if (!submission.WorkItemCreated &&
                        (submission.Item1Votes >= submission.Threshold || submission.Item2Votes >= submission.Threshold))
                    {
                        VsoHelper.CreateWorkItem(submission, submission.OAuthRefreshToken);
                        _submissionEntityService.SetCreatedWorkItemFlag(key);
                    }

                    return(true);
                }
                return(false);
            }
            catch (Exception)
            {
                return(false);
            }
        }
        public static async Task <int?> GetVsoIdFromConversation(IDialogContext endUserDialogContext)
        {
            int?vsoId = null;

            try
            {
                string status = "not set";
                if (endUserDialogContext.ConversationData.TryGetValue("VsoId", out string vsoIdFromConversation))
                {
                    int convertedVsoId = Convert.ToInt32(vsoIdFromConversation);
                    status = await VsoHelper.GetProjectStatus(convertedVsoId);

                    if (!status.ToLower().Contains("closed"))
                    {
                        vsoId = convertedVsoId;
                    }
                }
                WebApiConfig.TelemetryClient.TrackEvent("GetVsoIdFromConversation", new Dictionary <string, string>
                {
                    { "class", "HelloDialog" },
                    { "function", "GetVsoIdFromConversation" },
                    { "from", endUserDialogContext.Activity.From.Name },
                    { "vsoId", vsoId != null ? vsoId.ToString() : "not set" },
                    { "vsoIdStatus", status },
                });
            }
            catch (VssServiceException e)
            {
                if (e.Message.Contains("does not exist"))
                {
                    // we might have deleted this item.

                    WebApiConfig.TelemetryClient.TrackException(e, new Dictionary <string, string>
                    {
                        { "class", "HelloDialog" },
                        { "function", "GetVsoIdFromConversation" },
                        { "dialog", "HelloDialog" },
                        { "from", endUserDialogContext.Activity.From.Name }
                    });

                    return(null);
                }
            }
            catch (System.Exception e)
            {
                WebApiConfig.TelemetryClient.TrackException(e, new Dictionary <string, string>
                {
                    { "class", "HelloDialog" },
                    { "function", "GetVsoIdFromConversation" },
                    { "dialog", "HelloDialog" },
                    { "from", endUserDialogContext.Activity.From.Name }
                });
                throw;
            }
            return(vsoId);
        }
        public static async Task <bool> RelayMessageToAgentIfThereIsAnOpenResearchProject(IDialogContext context)
        {
            int?vsoId = await GetResearchVsoIdFromVso(context.Activity.ChannelId, context.Activity.From.Name);

            if (vsoId == null)
            {
                return(false);
            }

            var userProfile = await UserProfileHelper.GetUserProfile(context);

            context.UserData.SetValue(UserProfileHelper.UserProfileKey, userProfile);

            string agentConversationId = await VsoHelper.GetAgentConversationIdForVso((int)vsoId);

            if (string.IsNullOrEmpty(agentConversationId))
            {
                return(false);
            }

            await context.PostWithRetryAsync("OK, I'll add that to the project.");

            //await SendAutoReplyIfNeeded(context, vsoId);

            IMessageActivity messageActivity = (IMessageActivity)context.Activity;

            if (ActivityHelper.HasAttachment(messageActivity))
            {
                await context.PostWithRetryAsync(
                    $"Sending file attachments is not supported. " +
                    $"Please send it via an accessible link within Microsoft");
            }
            else
            {
                await ActivityHelper.SendMessageToAgentAsReplyToConversationInAgentsChannel(
                    messageActivity,
                    messageActivity.Text,
                    agentConversationId,
                    (int)vsoId);
            }

            await OnlineStatus.SetMemberActive(context.Activity.From.Name,
                                               context.Activity.From.Id,
                                               OnlineStatus.EndUserMemberType);

            return(true);
        }
Ejemplo n.º 6
0
        private async Task CloseProject(IDialogContext context, IMessageActivity message)
        {
            if (TryParseVsoId(message.Text, out int vsoId))
            {
                await context.PostWithRetryAsync($"Sure I can help close project #{vsoId}");

                await VsoHelper.CloseProject(vsoId);

                await context.PostWithRetryAsync($"{vsoId} project is now closed.");
                await PromptForCreatingNewProjectAfterClosingExistingOne(context);
            }
            else
            {
                await context.PostWithRetryAsync("Sorry, I ran into an error");

                context.Call(new UserHelpDialog(), EndDialog);
            }
        }
Ejemplo n.º 7
0
        public AuthModule()
        {
            // callback URL from the VSO OAuth page
            Get["/oauth"] = _ =>
            {
                var        oauthData  = this.Bind <OAuthPostData>();
                TokenModel tokenModel = VsoHelper.DoAuthenticationPost(oauthData.Code, false);
                return(View["TokenView", tokenModel]);
            };

            // URL to renew or initialize OAuth
            Get["/oauth/init"] = _ =>
            {
                TokenModel token = null;
                if (Request.Cookies.ContainsKey("VsoToken"))
                {
                    var code = Request.Cookies["VsoToken"];
                    token = JsonConvert.DeserializeObject <TokenModel>(code);
                }
                else
                {
                    Response.AsRedirect("/oauth/request");
                }

                TokenModel tokenModel = VsoHelper.DoAuthenticationPost(token.refreshToken, true);

                if (!string.IsNullOrEmpty(tokenModel.Error))
                {
                    return(View["TokenView"]);
                }

                if (HttpContext.Current.Request.UrlReferrer != null)
                {
                    return(Response.AsRedirect(HttpContext.Current.Request.UrlReferrer.ToString()));
                }
                else
                {
                    return(Response.AsRedirect("/"));
                }
            };

            // Start the OAuth request process
            Get["/oauth/request"] = _ => Response.AsRedirect(VsoHelper.GenerateAuthorizeUrl());
        }
        public IndexModule()
        {
            // Root
            Get["/"] = _ =>
            {
                // todo: redirect to init if we already have a cookie - refresh the token??
                var newModel = new SubmissionModel {
                    Threshold = 5
                };
                return(View["Index.cshtml", newModel]);
            };

            // About
            Get["/about"] = _ => View["About"];

            Post["/submit"] = _ =>
            {
                var saveData = this.Bind <SubmissionModel>();

                var service = new SubmissionEntityService();
                var urlKey  = GetRandomString(4); // some random key
                if (VsoHelper.GetActiveUser() != null)
                {
                    var savedObject = service.Add(urlKey, VsoHelper.GetActiveUser().refreshToken, saveData);
                }
                else
                {
                    var savedObject = service.Add(urlKey, "", saveData);
                }

                return(Response.AsRedirect("/v/" + urlKey));
            };

            Post["/refresh"] = _ =>
            {
                var saveData = this.Bind <SubmissionModel>();
                return(View["Index", saveData]);
            };
        }
Ejemplo n.º 9
0
        private async Task GetProject(IDialogContext context, IMessageActivity message)
        {
            if (TryParseVsoId(message.Text, out int vsoId))
            {
                await context.PostWithRetryAsync($"Let me get the status of {vsoId}");

                try
                {
                    string projectDetails = await VsoHelper.GetProjectSummary(vsoId);

                    await context.PostWithRetryAsync(projectDetails);
                    await PromptForConnectToAgentAfterGettingProjectDetails(context);
                }
                catch (System.Exception e)
                {
                    Trace.TraceInformation($"Sorry, I ran into an error closing project #{vsoId}. Exception = {e.Message}");
                    context.Call(new UserHelpDialog(), EndDialog);
                }
            }
            else
            {
                await LetUserKnowWeRanIntoAnIssueAndSendToAgentDialog(context);
            }
        }
Ejemplo n.º 10
0
        public VsoModule()
        {
            var token = VsoHelper.GetActiveUser();

            // get accounts
            Get["/vso/accounts/"] = _ =>
            {
                if (token != null)
                {
                    var accounts = VsoHelper.GetAccounts(token.accessToken);
                    if (accounts != null)
                    {
                        return(Response.AsJson(accounts.value.Select(a => new { a.accountName })));
                    }
                }
                return(Response.AsJson(new { }));
            };

            // get projects for an account
            Get["/vso/projects/{account}"] = _ =>
            {
                if (token != null)
                {
                    var account  = (string)_.account;
                    var projects = VsoHelper.GetProjects(account, token.accessToken);
                    if (projects != null)
                    {
                        return(Response.AsJson(projects.value.Select(p => new { p.name })));
                    }
                }
                return(Response.AsJson(new { }));
            };

            // get work item types for an account and project
            Get["/vso/workitemtypes/{account}/{project}"] = _ =>
            {
                if (token != null)
                {
                    var account = (string)_.account;
                    var project = (string)_.project;
                    var witypes = VsoHelper.GetWorkItemTypes(account, project, token.accessToken);
                    if (witypes != null)
                    {
                        return(Response.AsJson(
                                   witypes.value.Select(t => new
                        {
                            t.name,
                            state = GetState(t.name)
                        })));
                    }
                }
                return(Response.AsJson(new { }));
            };



            Get["/vso/test/{account}/{project}"] = _ =>
            {
                if (token != null)
                {
                    var account = (string)_.account;
                    var project = (string)_.project;
                    var witypes = VsoHelper.GetWorkItemTypes(account, project, token.accessToken);
                    if (witypes != null)
                    {
                        return(View["VsoTest", witypes]);
                    }
                }
                return(View["VsoTest", new { error = "Hmm, something bad happened :(" }]);
            };
        }
Ejemplo n.º 11
0
        private async Task OnDeadlineSelected(IDialogContext context, IAwaitable<IEnumerable<DateTime>> result)
        {
            try
            {
                // "result" contains the date (or array of dates) returned from the prompt
                IEnumerable<DateTime> momentOrRange = await result;
                var deadline = momentOrRange.First(); // DeadlinePrompt.MomentOrRangeToString(momentOrRange);

                // Store date
                context.ConversationData.SetValue("deadline", deadline);

                var description = context.ConversationData.GetValue<string>("description");

                string mobilePhone = string.Empty;
                string alias = string.Empty;

                if (!context.UserData.TryGetValue(UserProfileHelper.UserProfileKey, out UserProfile userProfile))
                {
                    mobilePhone = userProfile.MobilePhone;
                    alias = userProfile.Alias;
                }

                var vsoTicketNumber = await VsoHelper.CreateTaskInVso(VsoHelper.VirtualAssistanceTaskType,
                    context.Activity.From.Name,
                    description,
                    ConfigurationManager.AppSettings["AgentToAssignVsoTasksTo"],
                    deadline,
                    "",
                    null,
                    context.Activity.ChannelId);

                MicrosoftAppCredentials.TrustServiceUrl(ActivityHelper.TeamsServiceEndpoint);

                AdaptiveCard card = new AdaptiveCard();
                card.Body.Add(new AdaptiveTextBlock()
                {
                    Text = $"New Virtual Assistance request from {context.Activity.From.Name}. VSO:{vsoTicketNumber}",
                    Size = AdaptiveTextSize.Large,
                    Wrap = true,
                    Separator = true
                });
                var summary = new AdaptiveFactSet
                {
                    Facts = new List<AdaptiveFact>
                    {
                        new AdaptiveFact("Who", context.Activity.From.Name),
                        new AdaptiveFact("What", description),
                        new AdaptiveFact("When", deadline.ToString()),
                        new AdaptiveFact("Vso", vsoTicketNumber.ToString()),
                    }
                };
                card.Body.Add(summary);

                using (var connectorClient = await BotConnectorUtility.BuildConnectorClientAsync(ActivityHelper.TeamsServiceEndpoint))
                {
                    var channelInfo = GetHardcodedChannelId();
                    context.ConversationData.SetValue("VsoId", vsoTicketNumber);
                    context.ConversationData.SetValue("EndUserConversationId", context.Activity.Conversation.Id);

                    var conversationResourceResponse = await ConversationHelpers.CreateAgentConversation(channelInfo,
                        card,
                        $"New research request from {context.Activity.Recipient.Name}",
                        connectorClient,
                        vsoTicketNumber,
                        context.Activity as IMessageActivity);

                    EndUserAndAgentConversationMappingState state =
                        new EndUserAndAgentConversationMappingState(vsoTicketNumber.ToString(),
                            context.Activity.From.Name,
                            context.Activity.From.Id,
                            context.Activity.Conversation.Id,
                            conversationResourceResponse.Id);

                    await state.SaveInVso(vsoTicketNumber.ToString());
                }

                await context.PostWithRetryAsync("Thank you! I have posted following to internal agents. " +
                                                 "I will be in touch with you shortly. " +
                                                 $"Please use reference #{vsoTicketNumber} for this request in future. " +
                                                 $"What: {description}. When: {deadline}.");

                context.Done<object>(null);
            }
            catch (TooManyAttemptsException)
            {
                await context.PostWithRetryAsync("TooManyAttemptsException. Restarting now...");
            }
            catch (System.Exception e)
            {
                WebApiConfig.TelemetryClient.TrackException(e, new Dictionary<string, string>
                {
                    {"dialog", "InternetResearchDialog" },
                    {"function", "OnDeadlineSelected" }
                });
                throw;
            }
        }
        private async Task OnConfirmResearchDialog(IDialogContext context, IAwaitable <bool> result)
        {
            if (result == null)
            {
                throw new InvalidOperationException((nameof(result)) + Strings.NullException);
            }

            var sendIt = await result;

            if (sendIt)
            {
                var additionalInfoFromUser = context.ConversationData.GetValue <string>(AdditionalInfoKey);
                var description            = context.ConversationData.GetValue <string>(DescriptionKey);
                var deadline = DateTime.Parse(context.ConversationData.GetValue <string>(DeadlineKey));

                var vsoTicketNumber = await VsoHelper.CreateTaskInVso(VsoHelper.ResearchTaskType,
                                                                      context.Activity.From.Name,
                                                                      description + Environment.NewLine + additionalInfoFromUser,
                                                                      ConfigurationManager.AppSettings["AgentToAssignVsoTasksTo"],
                                                                      deadline,
                                                                      "",
                                                                      userProfile,
                                                                      context.Activity.ChannelId);

                context.ConversationData.SetValue(VsoIdKey, vsoTicketNumber);
                context.ConversationData.SetValue(EndUserConversationIdKey, context.Activity.Conversation.Id);

                try
                {
                    var    conversationTitle   = $"Web research request from {userProfile} via {context.Activity.ChannelId} due {deadline}";
                    string agentConversationId = await ConversationHelpers.CreateAgentConversationEx(context,
                                                                                                     conversationTitle,
                                                                                                     CreateCardForAgent(context,
                                                                                                                        additionalInfoFromUser,
                                                                                                                        description,
                                                                                                                        deadline,
                                                                                                                        vsoTicketNumber),
                                                                                                     userProfile);

                    EndUserAndAgentConversationMappingState state =
                        new EndUserAndAgentConversationMappingState(vsoTicketNumber.ToString(),
                                                                    context.Activity.From.Name,
                                                                    context.Activity.From.Id,
                                                                    context.Activity.Conversation.Id,
                                                                    agentConversationId);

                    await state.SaveInVso(vsoTicketNumber.ToString());

                    await context.PostWithRetryAsync("Sure. I have sent your request to a freelancer. " +
                                                     $"Please use #{vsoTicketNumber} for referencing this request in future. " +
                                                     "At this point, any message you send will be sent directly to the freelancer. They may take time to respond, " +
                                                     "or may have clarifying questions which I will relay back to you.");

                    context.Done <object>(true);
                }
                catch (System.Exception e)
                {
                    await context.PostWithRetryAsync("Sorry, I ran into an issue while connecting with agent. Please try again later.");

                    WebApiConfig.TelemetryClient.TrackException(e, new Dictionary <string, string> {
                        { "function", "OnConfirmResearchDialog.CreateAgentConversation" }
                    });
                    context.Done <object>(false);
                }
            }
            else
            {
                await context.PostWithRetryAsync("Okay, I have cancelled this request.");

                context.Done <object>(false);
            }
        }
        private static async Task SendAutoReplyIfNeeded(IDialogContext context, int?vsoId)
        {
            // Check when was the last time we sent message to agent
            var timeStampWhenLastMessageWasSentByAgent =
                await OnlineStatus.GetTimeWhenMemberWasLastActive(OnlineStatus.AgentMemberType);

            var  timeSinceLastMessageWasSentByAgent = DateTime.UtcNow.Subtract((DateTime)timeStampWhenLastMessageWasSentByAgent);
            bool autoReplyWasSentAWhileBack         = DateTime.UtcNow.Subtract(GetAutoReplySentOnTimeStamp(context))
                                                      .TotalMinutes > MinutesToWaitBeforeSendingAutoReply;

            if (timeSinceLastMessageWasSentByAgent.TotalMinutes >= MinutesToWaitForAgentOnlineBeforeSendingAutoReply && autoReplyWasSentAWhileBack)
            {
                await context.PostWithRetryAsync($"Hi {UserProfileHelper.GetFriendlyName(context)}, " +
                                                 $"My experts are working on Project #{vsoId}. " +
                                                 $"Current status of this project is {await VsoHelper.GetProjectStatus((int)vsoId)}. " +
                                                 "Either experts are busy or offline at the moment. " +
                                                 $"They were online {timeSinceLastMessageWasSentByAgent.TimeAgo()}. Please wait. ");

                SetAutoReplySentOnTimeStamp(context);
            }
        }
Ejemplo n.º 14
0
        private async Task CreateProject(IDialogContext context)
        {
            try
            {
                var description = context.ConversationData.GetValue <string>(DescriptionKey);
                var userProfile = context.UserData.GetValue <UserProfile>(UserProfileHelper.UserProfileKey);
                var deadline    = DateTime.UtcNow.AddHours(_minHoursToCompleteResearch);

                var vsoTicketNumber = await VsoHelper.CreateTaskInVso(VsoHelper.ResearchTaskType,
                                                                      context.Activity.From.Name,
                                                                      description,
                                                                      ConfigurationManager.AppSettings["AgentToAssignVsoTasksTo"],
                                                                      deadline,
                                                                      "",
                                                                      userProfile,
                                                                      context.Activity.ChannelId);

                context.ConversationData.SetValue(VsoIdKey, vsoTicketNumber);
                context.ConversationData.SetValue(EndUserConversationIdKey, context.Activity.Conversation.Id);

                var    conversationTitle   = $"Web research request from {userProfile} via {context.Activity.ChannelId} due {deadline}";
                string agentConversationId = await ConversationHelpers.CreateAgentConversationEx(context,
                                                                                                 conversationTitle,
                                                                                                 CreateCardForAgent(context,
                                                                                                                    description,
                                                                                                                    deadline,
                                                                                                                    vsoTicketNumber,
                                                                                                                    userProfile),
                                                                                                 userProfile);

                EndUserAndAgentConversationMappingState state =
                    new EndUserAndAgentConversationMappingState(vsoTicketNumber.ToString(),
                                                                context.Activity.From.Name,
                                                                context.Activity.From.Id,
                                                                context.Activity.Conversation.Id,
                                                                agentConversationId);

                await state.SaveInVso(vsoTicketNumber.ToString());

                WebApiConfig.TelemetryClient.TrackEvent("CreateProject", new Dictionary <string, string>()
                {
                    { "from", context.Activity.From.Name },
                    { UserProfileHelper.UserProfileKey, userProfile.ToString() },
                    { DescriptionKey, description },
                    { "deadline", deadline.ToString() },
                    { VsoIdKey, vsoTicketNumber.ToString() },
                });

                await context.PostWithRetryAsync($"OK, your research project is #{vsoTicketNumber}. " +
                                                 $"We'll get to work on this shortly and send you a confirmation email.\n\n\n\n" +
                                                 $"In the meantime, feel free to tell me more, like: " +
                                                 $"what do you want to do with this info?");

                context.Done <object>(true);
            }
            catch (System.Exception e)
            {
                try
                {
                    if (context.ConversationData.TryGetValue(VsoIdKey, out string vsoTicketNumber))
                    {
                        // close this ticket
                        await VsoHelper.CloseProject(Convert.ToInt32(vsoTicketNumber));
                    }
                }
                catch (System.Exception exception)
                {
                    WebApiConfig.TelemetryClient.TrackException(exception, new Dictionary <string, string>
                    {
                        { "debugNote", "Error closing project during exception received in CreateProject" },
                        { "CreateProjectException", e.ToString() },
                    });
                }
                await context.PostWithRetryAsync("Sorry, I ran into an issue while connecting with agent. Please try again later.");

                WebApiConfig.TelemetryClient.TrackException(e, new Dictionary <string, string> {
                    { "function", "OnConfirmResearchDialog.CreateAgentConversation" }
                });
                context.Done <object>(false);
            }
        }