Пример #1
0
        /// <summary>
        /// Update the first trail card with user details.
        /// </summary>
        /// <param name="scrumSummary">Scrum summary information to be shown on card.</param>
        /// <param name="scrum">Scrum details.</param>
        /// <param name="scrumMaster">Scrum master details.</param>
        /// <param name="membersActivityIdMap">Members id who are part of the scrum.</param>
        /// <param name="timeZone">Used to convert scrum start time as per specified time zone.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>A task of type bool where true represents summary card updated successfully while false indicates failure in updating the summary card.</returns>
        public async Task <bool> UpdateSummaryCardWithEndScrumAsync(ScrumSummary scrumSummary, Scrum scrum, ScrumMaster scrumMaster, Dictionary <string, string> membersActivityIdMap, string timeZone, ITurnContext turnContext, CancellationToken cancellationToken)
        {
            if (scrumSummary != null)
            {
                var activitySummary  = MessageFactory.Attachment(ScrumCard.GetScrumStartCard(scrumSummary, membersActivityIdMap, scrumMaster?.ScrumMasterId, scrum?.ScrumStartActivityId, this.localizer, timeZone));
                var teamsChannelInfo = await TeamsInfo.GetTeamChannelsAsync(turnContext, scrumMaster.TeamId, CancellationToken.None);

                var channelInfo = teamsChannelInfo.Where(channel => channel.Id.Equals(scrumMaster.ChannelId, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

                if (channelInfo != null)
                {
                    activitySummary.Id           = scrum.ScrumStartCardResponseId;
                    activitySummary.Conversation = new ConversationAccount
                    {
                        Id = $"{scrumMaster.ChannelId};messageid={scrum.ScrumStartCardResponseId}",
                    };
                    this.logger.LogInformation($"Trail card updated for: {scrum.ThreadConversationId} summaryCardActivityId: {scrum.ScrumStartCardResponseId}");
                    await turnContext?.UpdateActivityAsync(activitySummary, cancellationToken);
                }

                return(true);
            }
            else
            {
                this.logger.LogInformation($"No data obtained from storage to update summary card for summaryCardActivityId : {scrum?.ScrumStartCardResponseId}");
                return(false);
            }
        }
Пример #2
0
        /// <summary>
        /// Get scrum details adaptive card response.
        /// </summary>
        /// <param name="scrumMembers">Members who are part of the scrum.</param>
        /// <param name="scrumTeamConfigId">Unique identifier for scrum team configuration details.</param>
        /// <param name="scrumStartActivityId">Scrum start card activity Id.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>Returns scrum details card to be displayed in task module.</returns>
        public async Task <TaskModuleResponse> GetScrumDetailsCardResponseAsync(string scrumMembers, string scrumTeamConfigId, string scrumStartActivityId, ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken)
        {
            turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            var activity = turnContext.Activity;

            this.logger.LogInformation($"Getting information about scrum with summaryCardId: {scrumStartActivityId}");
            string aadGroupId = await this.activityHelper.GetTeamAadGroupIdAsync(turnContext, cancellationToken);

            var scrumSummary = (await this.scrumStorageProvider.GetScrumsByScrumStartActivityIdAsync(scrumStartActivityId, aadGroupId)).FirstOrDefault();

            if (scrumSummary == null)
            {
                this.logger.LogInformation($"Value obtained from storage for scrum summary is null.");
                return(this.GetTaskModuleErrorResponse(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDoesNotExist"), activity.From.Name), this.localizer.GetString("ScrumDetailsTitle")));
            }

            this.logger.LogInformation($"Received information about scrum with scrumId: {scrumSummary.ScrumId}");

            var scrumStatusDetails = await this.scrumStatusStorageProvider.GetScrumStatusBySummaryCardIdAsync(scrumSummary.ScrumStartCardResponseId, aadGroupId);

            var membersActivityIdMap = JsonConvert.DeserializeObject <Dictionary <string, string> >(scrumMembers);

            var updatedScrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrumTeamConfigId, aadGroupId, scrumSummary.ScrumStartCardResponseId, membersActivityIdMap);

            if (scrumStatusDetails == null || updatedScrumSummary == null)
            {
                this.logger.LogInformation($"Value obtained from storage for scrum is null.");
                return(this.GetTaskModuleErrorResponse(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDoesNotExist"), activity.From.Name), this.localizer.GetString("ScrumDetailsTitle")));
            }

            var scrumConfigurationDetails = await this.scrumConfigurationStorageProvider.GetScrumConfigurationDetailByScrumTeamConfigIdAsync(scrumSummary.ScrumTeamConfigId, scrumSummary.AadGroupId);

            activity.Conversation.Id = scrumConfigurationDetails.TeamId;
            var    validScrumMembers = new List <TeamsChannelAccount>();
            string continuationToken = null;

            do
            {
                var currentPage = await TeamsInfo.GetPagedMembersAsync(turnContext, 100, continuationToken, cancellationToken);

                continuationToken = currentPage.ContinuationToken;
                validScrumMembers.AddRange(currentPage.Members.Where(member => membersActivityIdMap.ContainsKey(member.Id)));
            }while (continuationToken != null);

            return(new TaskModuleResponse
            {
                Task = new TaskModuleContinueResponse
                {
                    Value = new TaskModuleTaskInfo()
                    {
                        Card = ScrumCard.GetScrumDetailsCard(scrumStatusDetails, updatedScrumSummary, validScrumMembers, this.appBaseUri, this.localizer, scrumConfigurationDetails.TimeZone),
                        Height = TaskModuleHeight,
                        Width = TaskModuleWidth,
                        Title = this.localizer.GetString("ScrumDetailsTitle"),
                    },
                },
            });
        }
Пример #3
0
        /// <summary>
        /// Method that sends the start scrum card to the channel.
        /// </summary>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="scrumMaster">Scrum master details obtained from storage.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>A task that sends the start scrum card.</returns>
        private async Task SendScrumStartCardAsync(ITurnContext turnContext, ScrumMaster scrumMaster, CancellationToken cancellationToken)
        {
            try
            {
                string scrumMasterId = scrumMaster.ScrumMasterId;
                if (scrumMasterId != null)
                {
                    this.logger.LogInformation($"Scrum start for ID: {scrumMasterId}");
                    var scrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrumMasterId);

                    if (scrumSummary == null)
                    {
                        this.logger.LogInformation($"Scrum master details are deleted from storage.");
                        await turnContext.SendActivityAsync(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDeleted"), scrumMaster.TeamName), cancellationToken : cancellationToken);

                        return;
                    }

                    // scrumSummary.ScrumStartTime = scrumMaster.StartTime;
                    var scrumStartActivityId = Guid.NewGuid().ToString();

                    // Fetching the members list based on the teams id:
                    turnContext.Activity.Conversation.Id = scrumMaster.TeamId;
                    var membersActivityIdMap = await this.GetActivityIdOfMembersInScrumAsync(turnContext, scrumMaster, cancellationToken);

                    string membersList = JsonConvert.SerializeObject(membersActivityIdMap);

                    // Mentioning the participants involved in the scrum
                    var mentionActivity = await this.GetMentionsActivityAsync(turnContext, scrumMaster, cancellationToken);

                    // Check if channel exists. If channel doesn't exist then scrum card will be sent in General channel.
                    scrumMaster.ChannelId = await this.GetValidChannelIdAsync(turnContext, scrumMaster);

                    // Send the start scrum card
                    turnContext.Activity.Conversation.Id = scrumMaster.ChannelId;
                    var attachment                 = ScrumCard.GetScrumStartCard(scrumSummary, membersActivityIdMap, scrumMasterId, scrumStartActivityId, this.localizer, scrumMaster.TimeZone);
                    var scrumStartActivity         = MessageFactory.Attachment(attachment);
                    var scrumStartActivityResponse = await turnContext.SendActivityAsync(scrumStartActivity, cancellationToken);

                    // Update the conversation id to send mentioned participants as reply to scrum start card.
                    turnContext.Activity.Conversation = new ConversationAccount
                    {
                        Id = $"{scrumMaster.ChannelId};messageid={scrumStartActivityResponse.Id}",
                    };
                    await turnContext.SendActivityAsync(mentionActivity, cancellationToken);

                    await this.CreateScrumAsync(scrumStartActivityResponse.Id, scrumStartActivityId, membersList, scrumMaster, turnContext, cancellationToken);

                    this.logger.LogInformation($"Scrum start details saved to table storage for: {turnContext.Activity.Conversation.Id}");
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, $"Start scrum failed for {turnContext.Activity.Conversation.Id}: {ex.Message}", SeverityLevel.Error);
                throw;
            }
        }
Пример #4
0
        /// <summary>
        /// Get end scrum summary card activity.
        /// </summary>
        /// <param name="scrum">Scrum details of the running scrum.</param>
        /// <param name="conversationId">Conversation id for updating the conversation.</param>
        /// <param name="scrumMembers">Members who are part of the scrum.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>Returns end scrum summary card activity to be updated in team.</returns>
        public async Task <IActivity> GetEndScrumSummaryActivityAsync(Scrum scrum, string conversationId, string scrumMembers, ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var activity = turnContext?.Activity;

            if (scrum == null || scrum.IsCompleted == true)
            {
                await turnContext.SendActivityAsync(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumDoesNotExist"), activity.From.Name), cancellationToken : cancellationToken);

                return(null);
            }

            var activityId = this.GetActivityIdToMatch(scrum.MembersActivityIdMap, activity.From.Id);

            if (string.IsNullOrEmpty(activityId))
            {
                await turnContext.SendActivityAsync(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorUserIsNotPartOfRunningScrumAndTryToEndScrum"), activity.From.Name), cancellationToken : cancellationToken);

                this.logger.LogInformation($"Member who is updating the scrum is not the part of scrum for: {conversationId}");
                return(null);
            }

            if (string.IsNullOrEmpty(scrumMembers))
            {
                this.logger.LogInformation("Scrum members detail could not be found");
                await turnContext.SendActivityAsync(this.localizer.GetString("ErrorMessage"), cancellationToken : cancellationToken);

                return(null);
            }

            var membersActivityIdMap = JsonConvert.DeserializeObject <Dictionary <string, string> >(scrumMembers);

            scrum.IsCompleted          = true;
            scrum.ThreadConversationId = conversationId;
            var savedData = await this.scrumStorageProvider.CreateOrUpdateScrumAsync(scrum);

            if (!savedData)
            {
                this.logger.LogError("Error in saving scrum information in storage.");
                await turnContext.SendActivityAsync(this.localizer.GetString("ErrorSavingScrumData"), cancellationToken : cancellationToken);

                return(null);
            }

            var scrumStartCardResponseId = scrum.ScrumStartCardResponseId;
            var scrumMaster = await this.scrumMasterStorageProvider.GetScrumMasterDetailsByScrumMasterIdAsync(scrum.ScrumMasterId);

            var updatedScrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrum.ScrumMasterId, scrumStartCardResponseId, membersActivityIdMap);

            var scrumStartCard  = ScrumCard.GetScrumStartCard(updatedScrumSummary, membersActivityIdMap, scrum.ScrumMasterId, scrum.ScrumStartActivityId, this.localizer, scrumMaster.TimeZone);
            var activitySummary = MessageFactory.Attachment(scrumStartCard);

            activitySummary.Id           = scrumStartCardResponseId;
            activitySummary.Conversation = activity.Conversation;
            return(activitySummary);
        }
Пример #5
0
        /// <summary>
        /// Update the scrum summary card with updated details.
        /// </summary>
        /// <param name="scrumSummary">Scrum summary information to be shown on card.</param>
        /// <param name="summaryCardActivityId">Summary card activity id.</param>
        /// <param name="scrumTeamConfigId">Unique identifier for scrum team configuration details.</param>
        /// <param name="scrumStartActivityId">Scrum start card activity id</param>
        /// <param name="membersActivityIdMap">Members id who are part of the scrum.</param>
        /// <param name="timeZone">Used to convert scrum start time as per specified time zone.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>A task of type boolean where true represents summary card updated successfully while false indicates failure in updating the summary card.</returns>
        public async Task <bool> UpdateSummaryCardAsync(ScrumSummary scrumSummary, string summaryCardActivityId, string scrumTeamConfigId, string scrumStartActivityId, Dictionary <string, string> membersActivityIdMap, string timeZone, ITurnContext turnContext, CancellationToken cancellationToken)
        {
            var activitySummary = MessageFactory.Attachment(ScrumCard.GetScrumStartCard(scrumSummary, membersActivityIdMap, scrumTeamConfigId, scrumStartActivityId, this.localizer, timeZone));

            activitySummary.Id           = summaryCardActivityId;
            activitySummary.Conversation = turnContext?.Activity.Conversation;
            this.logger.LogInformation($"Trail card updated for: {turnContext.Activity.Conversation.Id} summaryCardActivityId: {summaryCardActivityId}");
            await turnContext.UpdateActivityAsync(activitySummary, cancellationToken);

            return(true);
        }
Пример #6
0
 /// <summary>
 /// Get scrum status validation card with errors listed.
 /// </summary>
 /// <param name="membersActivityIdMap">Members id who are part of the scrum.</param>
 /// <param name="scrumMasterId">Unique identifier for scrum master details.</param>
 /// <param name="scrumStartActivityId">Scrum start card activity Id.</param>
 /// <param name="scrumStatus">Scrum status details filled by user.</param>
 /// <returns>Returns scrum status validation card to be sent in response.</returns>
 public TaskModuleResponse GetScrumStatusValidationCardResponse(string membersActivityIdMap, string scrumMasterId, string scrumStartActivityId, ScrumStatus scrumStatus)
 {
     return(new TaskModuleResponse
     {
         Task = new TaskModuleContinueResponse
         {
             Value = new TaskModuleTaskInfo()
             {
                 Card = ScrumCard.GetScrumStatusUpdateCard(membersActivityIdMap, scrumMasterId, scrumStartActivityId, scrumStatus, this.localizer, string.IsNullOrWhiteSpace(scrumStatus?.YesterdayTaskDescription), string.IsNullOrWhiteSpace(scrumStatus?.TodayTaskDescription)),
                 Height = TaskModuleHeight,
                 Width = TaskModuleWidth,
                 Title = this.localizer.GetString("UpdateStatusTitle"),
             },
         },
     });
 }
Пример #7
0
 /// <summary>
 /// Get scrum status update adaptive card in response to be filled by scrum member.
 /// </summary>
 /// <param name="membersActivityIdMap">Members id who are part of the scrum.</param>
 /// <param name="scrumMasterId">Unique identifier for scrum master details.</param>
 /// <param name="scrumStartActivityId">Scrum start card activity Id.</param>
 /// <param name="scrumStatus">Scrum status details.</param>
 /// <returns>Returns scrum status update card to be displayed in task module.</returns>
 public TaskModuleResponse GetScrumStatusUpdateCardResponse(string membersActivityIdMap, string scrumMasterId, string scrumStartActivityId, ScrumStatus scrumStatus)
 {
     return(new TaskModuleResponse
     {
         Task = new TaskModuleContinueResponse
         {
             Value = new TaskModuleTaskInfo()
             {
                 Card = ScrumCard.GetScrumStatusUpdateCard(membersActivityIdMap, scrumMasterId, scrumStartActivityId, scrumStatus, this.localizer),
                 Height = TaskModuleHeight,
                 Width = TaskModuleWidth,
                 Title = this.localizer.GetString("UpdateStatusTitle"),
             },
         },
     });
 }
Пример #8
0
        /// <summary>
        /// Get end scrum summary card activity.
        /// </summary>
        /// <param name="scrum">Scrum details of the running scrum.</param>
        /// <param name="conversationId">Conversation id for updating the conversation.</param>
        /// <param name="scrumMembers">Members who are part of the scrum.</param>
        /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param>
        /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
        /// <returns>Returns end scrum summary card activity to be updated in team.</returns>
        public async Task <IActivity> GetEndScrumSummaryActivityAsync(Scrum scrum, string conversationId, string scrumMembers, ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            var activity = turnContext.Activity;

            if (scrum == null)
            {
                return(null);
            }

            var activityId = this.CheckUserExistsInScrumMembers(scrum.MembersActivityIdMap, activity.From.Id);

            if (string.IsNullOrEmpty(activityId))
            {
                await turnContext.SendActivityAsync(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorUserIsNotPartOfRunningScrumAndTryToEndScrum"), activity.From.Name), cancellationToken : cancellationToken);

                this.logger.LogInformation($"Member who is updating the scrum is not the part of scrum for: {conversationId}");
                return(null);
            }

            if (string.IsNullOrEmpty(scrumMembers))
            {
                this.logger.LogInformation("Scrum members detail could not be found");
                await turnContext.SendActivityAsync(this.localizer.GetString("ErrorMessage"), cancellationToken : cancellationToken);

                return(null);
            }

            var    membersActivityIdMap     = JsonConvert.DeserializeObject <Dictionary <string, string> >(scrumMembers);
            var    scrumStartCardResponseId = scrum.ScrumStartCardResponseId;
            string aadGroupId = await this.GetTeamAadGroupIdAsync(turnContext, cancellationToken);

            var scrumConfiguration = await this.scrumConfigurationStorageProvider.GetScrumConfigurationDetailByScrumTeamConfigIdAsync(scrum.ScrumTeamConfigId, aadGroupId);

            var updatedScrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrum.ScrumTeamConfigId, scrumConfiguration.AadGroupId, scrumStartCardResponseId, membersActivityIdMap);

            var scrumStartCard  = ScrumCard.GetScrumStartCard(updatedScrumSummary, membersActivityIdMap, scrum.ScrumTeamConfigId, scrum.ScrumStartActivityId, this.localizer, scrumConfiguration.TimeZone);
            var activitySummary = MessageFactory.Attachment(scrumStartCard);

            activitySummary.Id           = scrumStartCardResponseId;
            activitySummary.Conversation = activity.Conversation;
            return(activitySummary);
        }