/// <summary> /// Stores or update scrum status data in Microsoft Azure Table storage. /// </summary> /// <param name="scrumStatusData">Holds scrum status entity data.</param> /// <returns>A task that represents scrum status entity data is saved or updated.</returns> public async Task <bool> CreateOrUpdateScrumStatusAsync(ScrumStatus scrumStatusData) { try { ScrumStatus scrumStatusDataEntity = new ScrumStatus() { PartitionKey = scrumStatusData?.SummaryCardId.Trim() + "_" + scrumStatusData.Username, TodayTaskDescription = scrumStatusData.TodayTaskDescription, YesterdayTaskDescription = scrumStatusData.YesterdayTaskDescription, BlockerDescription = scrumStatusData.BlockerDescription, SummaryCardId = scrumStatusData.SummaryCardId.Trim(), Username = scrumStatusData.Username, AadObjectId = scrumStatusData.AadObjectId, MembersActivityIdMap = scrumStatusData.MembersActivityIdMap, RowKey = scrumStatusData.SummaryCardId.Trim(), CreatedOn = scrumStatusData.CreatedOn, }; await this.EnsureInitializedAsync(); TableOperation operation = TableOperation.InsertOrReplace(scrumStatusDataEntity); var result = await this.CloudTable.ExecuteAsync(operation); return(result.HttpStatusCode == (int)HttpStatusCode.NoContent); } catch (Exception ex) { this.logger.LogError(ex, $"An error occurred in CreateOrUpdateScrumStatusAsync: {JsonConvert.SerializeObject(scrumStatusData)}. {ex.Message}", SeverityLevel.Error); throw; } }
/// <summary> /// Resume the scrum meeting /// </summary> /// <param name="scrum"></param> /// <param name="groupName"></param> /// <param name="accessToken"></param> /// <returns>scrum resume message along with the next question</returns> private string ScrumResume(Scrum scrum, string groupName, string accessToken) { ScrumStatus status = FetchScrumStatus(groupName, accessToken, null, null, null).Result; var returnMsg = string.Empty; //keyword encountered is "scrum resume" if (status == (ScrumStatus.Halted)) { //scrum resumed scrum.IsHalted = false; _scrumRepository.Update(scrum); //when the scrum is resumed then, the next question is to be asked returnMsg += _stringConstant.ScrumResumed + GetQuestion(scrum.Id, groupName, null, null, scrum.ProjectId, accessToken).Result; return(returnMsg); } else if (status == (ScrumStatus.OnGoing)) { returnMsg += _stringConstant.ScrumNotHalted + GetQuestion(scrum.Id, groupName, null, null, scrum.ProjectId, accessToken).Result; return(returnMsg); } else { return(ReplyToClient(status) + _stringConstant.ScrumCannotBeResumed); } }
/// <summary> /// This method will be called when the keyword "leave @username" or "later @username" or "scrum @username" is received as reply from a group member. - JJ /// </summary> /// <param name="groupName"></param> /// <param name="userName"></param> /// <param name="leaveApplicant"></param> /// <param name="parameter"></param> /// <returns>Question to the next person or other scrum status</returns> private async Task <string> Leave(string groupName, string userName, string applicant) { var returnMsg = string.Empty; List <Scrum> scrumList = _scrumRepository.Fetch(x => String.Compare(x.GroupName, groupName, true) == 0 && x.ScrumDate.Date == DateTime.UtcNow.Date).ToList(); if (scrumList.Count > 0) { if (scrumList.FirstOrDefault().IsOngoing) { if (!scrumList.FirstOrDefault().IsHalted) { // getting user name from user's slack name var applicationUser = _applicationUser.FirstOrDefault(x => x.SlackUserName == userName); // getting access token for that user if (applicationUser != null) { // get access token of user for promact oauth server var accessToken = await _attachmentRepository.AccessToken(applicationUser.UserName); List <Question> questions = _questionRepository.Fetch(x => x.Type == 1).OrderBy(x => x.OrderNumber).ToList(); List <User> employees = await _projectUser.GetUsersByGroupName(groupName, accessToken); ScrumStatus scrumStatus = FetchScrumStatus(groupName, accessToken, null, employees, questions).Result; if (scrumStatus == ScrumStatus.OnGoing) { var scrum = _scrumRepository.Fetch(x => String.Compare(x.GroupName, groupName, true) == 0 && x.ScrumDate.Date == DateTime.UtcNow.Date).FirstOrDefault(); List <ScrumAnswer> scrumAnswer = _scrumAnswerRepository.Fetch(x => x.ScrumId == scrum.Id).ToList(); //keyword "leave @username" returnMsg = LeaveLater(scrumAnswer, employees, scrum.Id, applicant, questions, groupName, scrum.ProjectId, userName, accessToken); } else { returnMsg = ReplyToClient(scrumStatus); } } else { // if user doesn't exist then this message will be shown to user returnMsg = _stringConstant.YouAreNotInExistInOAuthServer; } } else { returnMsg = _stringConstant.ScrumIsHalted; } } else { returnMsg = _stringConstant.ScrumAlreadyConducted; } } else { returnMsg = _stringConstant.ScrumNotStarted; } return(returnMsg); }
/// <summary> /// Delete scrum status entity from Microsoft Azure Table storage. /// </summary> /// <param name="scrumStatus">Holds scrum status entity data.</param> /// <returns>Delete operation response.</returns> public async Task <TableResult> DeleteEntityAsync(ScrumStatus scrumStatus) { await this.EnsureInitializedAsync(); TableOperation deleteOperation = TableOperation.Delete(scrumStatus); return(await this.CloudTable.ExecuteAsync(deleteOperation)); }
/// <summary> /// Select the appropriate reply to the client /// </summary> /// <param name="scrumStatus"></param> /// <returns>appropriate message indicating the status of scrum</returns> private string ReplyToClient(ScrumStatus scrumStatus) { string returnMessage = string.Empty; switch (scrumStatus) { case ScrumStatus.Completed: returnMessage = _stringConstant.ScrumAlreadyConducted; break; case ScrumStatus.Halted: returnMessage = _stringConstant.ScrumIsHalted; break; case ScrumStatus.NoEmployee: returnMessage = _stringConstant.NoEmployeeFound; break; case ScrumStatus.NoProject: returnMessage = _stringConstant.NoProjectFound; break; case ScrumStatus.InActiveProject: returnMessage = _stringConstant.ProjectInActive; break; case ScrumStatus.NoQuestion: returnMessage = _stringConstant.NoQuestion; break; case ScrumStatus.NotStarted: returnMessage = _stringConstant.ScrumNotStarted; break; case ScrumStatus.OnGoing: returnMessage = _stringConstant.ScrumInProgress; break; default: return(null); } return(returnMessage); }
/// <summary> /// Halt the scrum meeting /// </summary> /// <param name="scrum"></param> /// <param name="groupName"></param> /// <param name="accessToken"></param> /// <returns>scrum halted message</returns> private string ScrumHalt(Scrum scrum, string groupName, string accessToken) { ScrumStatus status = FetchScrumStatus(groupName, accessToken, null, null, null).Result; //keyword encountered is "scrum halt" if (status == (ScrumStatus.OnGoing)) { //scrum halted scrum.IsHalted = true; _scrumRepository.Update(scrum); return(_stringConstant.ScrumHalted); } else if (status == (ScrumStatus.Halted)) { return(_stringConstant.ScrumAlreadyHalted); } else { return(ReplyToClient(status) + _stringConstant.ScrumCannotBeHalted); } }
/// <summary> /// This method will be called when the keyword "scrum time" is encountered /// </summary> /// <param name="groupName"></param> /// <param name="userName"></param> /// <param name="accessToken"></param> /// <returns>The next question or the scrum complete message</returns> private async Task <string> StartScrum(string groupName, string userName, string accessToken) { string replyMessage = string.Empty; ProjectAc project = await _projectUser.GetProjectDetails(groupName, accessToken); List <User> employees = await _projectUser.GetUsersByGroupName(groupName, accessToken); List <Question> questionList = _questionRepository.Fetch(x => x.Type == 1).OrderBy(x => x.OrderNumber).ToList(); ScrumStatus scrumStatus = FetchScrumStatus(groupName, accessToken, project, employees, questionList).Result; if (scrumStatus == ScrumStatus.NotStarted) { Question question = questionList.FirstOrDefault(); Scrum scrum = new Scrum(); scrum.CreatedOn = DateTime.UtcNow; scrum.GroupName = groupName; scrum.ScrumDate = DateTime.UtcNow.Date; scrum.ProjectId = project.Id; scrum.TeamLeaderId = project.TeamLeaderId; scrum.IsHalted = false; scrum.IsOngoing = true; _scrumRepository.Insert(scrum); User firstEmployee = employees.FirstOrDefault(); //first employee is asked questions along with the previous day status (if any) replyMessage = _stringConstant.GoodDay + "<@" + firstEmployee.SlackUserName + ">!\n" + FetchPreviousDayStatus(firstEmployee.Id, project.Id) + question.QuestionStatement; } else if (scrumStatus == ScrumStatus.OnGoing) { //if scrum meeting was interrupted. "scrum time" is written to resume scrum meeting. So next question is fetched. var scrumList = _scrumRepository.Fetch(x => String.Compare(x.GroupName, groupName, true) == 0 && x.ScrumDate.Date == DateTime.UtcNow.Date).ToList(); replyMessage = await GetQuestion(scrumList.FirstOrDefault().Id, groupName, null, null, project.Id, accessToken); } else { return(ReplyToClient(scrumStatus)); } return(replyMessage); }
/// <summary> /// When OnTurn method receives a submit invoke activity on bot turn, it calls this method. /// </summary> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="taskModuleRequest">Task module invoke request value payload.</param> /// <param name="cancellationToken">Propagates notification that operations should be canceled.</param> /// <returns>A task that represents a task module response.</returns> /// <remarks> /// Reference link: https://docs.microsoft.com/en-us/dotnet/api/microsoft.bot.builder.teams.teamsactivityhandler.onteamstaskmodulesubmitasync?view=botbuilder-dotnet-stable. /// </remarks> protected override async Task <TaskModuleResponse> OnTeamsTaskModuleSubmitAsync( ITurnContext <IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken) { try { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); this.RecordEvent(nameof(this.OnTeamsTaskModuleSubmitAsync), turnContext); var activity = turnContext.Activity; var activityValue = JObject.Parse(activity.Value?.ToString())["data"].ToString(); ScrumStatus scrumStatus = JsonConvert.DeserializeObject <ScrumStatus>(activityValue); AdaptiveSubmitActionData adaptiveSubmitActionData = JsonConvert.DeserializeObject <AdaptiveSubmitActionData>(activityValue); if (scrumStatus == null || adaptiveSubmitActionData == null) { this.logger.LogInformation("Value obtained from task module submit action is null"); return(this.cardHelper.GetTaskModuleErrorResponse(this.localizer.GetString("ErrorMessage"), this.localizer.GetString("BotFailureTitle"))); } this.logger.LogInformation($"OnTeamsTaskModuleSubmitAsync: {JObject.Parse(activity.Value.ToString())["data"]}"); switch (adaptiveSubmitActionData.AdaptiveActionType.ToUpperInvariant()) { case Constants.UpdateStatusTaskModuleCommand: string scrumStartActivityId = adaptiveSubmitActionData.ScrumStartActivityId; string scrumMembers = adaptiveSubmitActionData.ScrumMembers; string scrumMasterId = adaptiveSubmitActionData.ScrumMasterId; if (string.IsNullOrWhiteSpace(scrumStatus.YesterdayTaskDescription) || string.IsNullOrWhiteSpace(scrumStatus.TodayTaskDescription)) { return(this.cardHelper.GetScrumStatusValidationCardResponse(scrumMembers, scrumMasterId, scrumStartActivityId, scrumStatus)); } this.logger.LogInformation($"Getting scrum master details which are active. ScrumMasterId: {scrumMasterId}"); var scrumMasterDetails = await this.scrumMasterStorageProvider.GetScrumMasterDetailsByScrumMasterIdAsync(scrumMasterId); if (scrumMasterDetails == null || !scrumMasterDetails.IsActive) { this.logger.LogInformation($"Scrum master details for the scrum master id: {scrumMasterId} could not be found or scrum is inactive"); return(this.cardHelper.GetTaskModuleErrorResponse(string.Format(CultureInfo.CurrentCulture, this.localizer.GetString("ErrorScrumMasterDetailsNullOrInactive"), activity.From.Name), this.localizer.GetString("UpdateStatusTitle"))); } var scrum = (await this.scrumStorageProvider.GetScrumByScrumStartActivityIdAsync(scrumStartActivityId)).FirstOrDefault(); await this.scrumHelper.SaveScrumStatusDetailsAsync(turnContext, scrumStatus, adaptiveSubmitActionData, scrum?.ScrumStartCardResponseId); var membersActivityIdMap = JsonConvert.DeserializeObject <Dictionary <string, string> >(scrumMembers); var updatedScrumSummary = await this.scrumHelper.GetScrumSummaryAsync(scrumMasterId, scrum?.ScrumStartCardResponseId, membersActivityIdMap); await this.cardHelper.UpdateSummaryCardAsync(updatedScrumSummary, scrum?.ScrumStartCardResponseId, scrumMasterId, scrumStartActivityId, membersActivityIdMap, scrumMasterDetails.TimeZone, turnContext, cancellationToken); return(null); default: return(null); } } catch (Exception ex) { this.logger.LogError(ex, "Error while submitting task module.", SeverityLevel.Error); return(this.cardHelper.GetTaskModuleErrorResponse(this.localizer.GetString("ErrorMessage"), this.localizer.GetString("BotFailureTitle"))); } }
/// <summary> /// Get scrum status update card when user clicks on update status button. /// </summary> /// <param name="membersId">Members id to verify the user.</param> /// <param name="scrumMasterId">Scrum master id to show updated status.</param> /// <param name="scrumStartActivityId">Activity id of scrum start card.</param> /// <param name="scrumStatus">Scrum status information.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="isYesterdayValidationFailure">Determines whether to show yesterday validation error.</param> /// <param name="isTodayValidationFailure">Determines whether to show today validation error.</param> /// <returns>Scrum status update card attachment.</returns> public static Attachment GetScrumStatusUpdateCard(string membersId, string scrumMasterId, string scrumStartActivityId, ScrumStatus scrumStatus, IStringLocalizer <Strings> localizer, bool isYesterdayValidationFailure = false, bool isTodayValidationFailure = false) { AdaptiveCard scrumStatusUpdateCard = new AdaptiveCard(Constants.AdaptiveCardVersion) { Body = new List <AdaptiveElement> { new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Size = AdaptiveTextSize.Medium, Wrap = true, Text = localizer.GetString("UpdateStatusYesterdayDescriptionTitle"), Spacing = AdaptiveSpacing.None, }, }, }, new AdaptiveColumn { Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Size = AdaptiveTextSize.Medium, Wrap = true, Text = localizer.GetString("UpdateStatusYesterdayDescriptionErrorMessage"), HorizontalAlignment = AdaptiveHorizontalAlignment.Right, Color = AdaptiveTextColor.Attention, IsVisible = isYesterdayValidationFailure, }, }, }, }, }, new AdaptiveTextInput { Spacing = AdaptiveSpacing.Small, Placeholder = localizer.GetString("UpdateStatusYesterdayDescriptionPlaceholder"), IsMultiline = true, Style = AdaptiveTextInputStyle.Text, Id = "yesterdaytaskdescription", MaxLength = InputFieldMaximumLength, Value = scrumStatus?.YesterdayTaskDescription, }, new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Size = AdaptiveTextSize.Medium, Wrap = true, Text = localizer.GetString("UpdateStatusTodayDescriptionTitle"), Spacing = AdaptiveSpacing.None, }, }, }, new AdaptiveColumn { Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Size = AdaptiveTextSize.Medium, Wrap = true, Text = localizer.GetString("UpdateStatusTodayDescriptionErrorMessage"), HorizontalAlignment = AdaptiveHorizontalAlignment.Right, Color = AdaptiveTextColor.Attention, IsVisible = isTodayValidationFailure, }, }, }, }, }, new AdaptiveTextInput { Spacing = AdaptiveSpacing.Small, Placeholder = localizer.GetString("UpdateStatusTodayDescriptionPlaceholder"), IsMultiline = true, Style = AdaptiveTextInputStyle.Text, Id = "todaytaskdescription", MaxLength = InputFieldMaximumLength, Value = scrumStatus.TodayTaskDescription, }, new AdaptiveTextBlock { Size = AdaptiveTextSize.Medium, Wrap = true, Text = localizer.GetString("UpdateStatusAnyBlockersTitle"), Color = AdaptiveTextColor.Attention, }, new AdaptiveTextInput { Spacing = AdaptiveSpacing.Small, Placeholder = localizer.GetString("UpdateStatusAnyBlockersPlaceholder"), IsMultiline = true, Style = AdaptiveTextInputStyle.Text, Id = "blockerdescription", MaxLength = InputFieldMaximumLength, Value = scrumStatus.BlockerDescription, }, new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { // Represents empty column required for alignment. }, }, }, }, new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { // Represents empty column required for alignment. }, }, }, }, new AdaptiveColumnSet { Columns = new List <AdaptiveColumn> { new AdaptiveColumn { Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { // Represents empty column required for alignment. }, }, }, }, }, }; scrumStatusUpdateCard.Actions.Add( new AdaptiveSubmitAction() { Title = localizer.GetString("UpdateStatusSubmitButtonText"), Data = new AdaptiveSubmitActionData { MsTeams = new CardAction { Type = Constants.TaskModuleSubmitType, }, ScrumMembers = membersId, ScrumMasterId = scrumMasterId, ScrumStartActivityId = scrumStartActivityId, AdaptiveActionType = Constants.UpdateStatusTaskModuleCommand, }, }); var adaptiveCardAttachment = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = scrumStatusUpdateCard, }; return(adaptiveCardAttachment); }
/// <summary> /// Get user scrum status details card for viewing all user status details. /// </summary> /// <param name="scrumStatus">Scrum status details filled by a member.</param> /// <param name="member">Member information whose scrum status is to be showed.</param> /// <param name="applicationBasePath">Application base URL.</param> /// <param name="localizer">The current cultures' string localizer.</param> /// <param name="id">Unique id for each row.</param> /// <param name="userScrumStatus">Individual user scrum status i.e. Not started or completed.</param> /// <param name="isBlocked">Determine whether user is blocked.</param> /// <returns>Returns scrum details card attachment.</returns> public static List <AdaptiveElement> GetUserScrumStatusCard(ScrumStatus scrumStatus, TeamsChannelAccount member, string applicationBasePath, IStringLocalizer <Strings> localizer, int id, string userScrumStatus, bool isBlocked = false) { string cardContent = $"CardContent{id}"; string chevronUp = $"ChevronUp{id}"; string chevronDown = $"ChevronDown{id}"; List <AdaptiveElement> userScrumStatusDetails = new List <AdaptiveElement> { new AdaptiveColumnSet { Separator = true, Spacing = AdaptiveSpacing.Medium, Columns = new List <AdaptiveColumn> { new AdaptiveColumn { VerticalContentAlignment = AdaptiveVerticalContentAlignment.Center, Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Text = member?.Name, Wrap = true, }, }, }, new AdaptiveColumn { VerticalContentAlignment = AdaptiveVerticalContentAlignment.Center, Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = string.Equals(userScrumStatus, localizer.GetString("ScrumStatusNotStarted"), StringComparison.OrdinalIgnoreCase) ? AdaptiveSpacing.Small : AdaptiveSpacing.None, Text = userScrumStatus, Wrap = true, }, }, }, new AdaptiveColumn { VerticalContentAlignment = AdaptiveVerticalContentAlignment.Center, Width = AdaptiveColumnWidth.Stretch, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.None, Text = localizer.GetString("ScrumDetailsUserIsBlocked"), Wrap = true, Color = AdaptiveTextColor.Attention, IsVisible = isBlocked, }, }, }, new AdaptiveColumn { Id = chevronDown, VerticalContentAlignment = AdaptiveVerticalContentAlignment.Center, Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveImage { AltText = "collapse", PixelWidth = 16, PixelHeight = 8, SelectAction = new AdaptiveToggleVisibilityAction { Title = "collapse", Type = "Action.ToggleVisibility", TargetElements = new List <AdaptiveTargetElement> { cardContent, chevronUp, chevronDown, }, }, Style = AdaptiveImageStyle.Default, Url = new Uri(applicationBasePath + "/Artifacts/chevronDown.png"), }, }, }, new AdaptiveColumn { Id = chevronUp, IsVisible = false, VerticalContentAlignment = AdaptiveVerticalContentAlignment.Center, Width = AdaptiveColumnWidth.Auto, Items = new List <AdaptiveElement> { new AdaptiveImage { AltText = "expand", PixelWidth = 16, PixelHeight = 8, SelectAction = new AdaptiveToggleVisibilityAction { Title = "expand", Type = "Action.ToggleVisibility", TargetElements = new List <AdaptiveTargetElement> { cardContent, chevronUp, chevronDown, }, }, Style = AdaptiveImageStyle.Default, Url = new Uri(applicationBasePath + "/Artifacts/chevronUp.png"), }, }, }, }, }, new AdaptiveContainer { Id = cardContent, IsVisible = false, Items = new List <AdaptiveElement> { new AdaptiveContainer { Items = new List <AdaptiveElement> { new AdaptiveTextBlock { IsSubtle = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Text = localizer.GetString("UpdateStatusYesterdayDescriptionTitle"), Wrap = true, }, new AdaptiveContainer { Spacing = AdaptiveSpacing.Small, Style = AdaptiveContainerStyle.Emphasis, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Small, Text = string.IsNullOrEmpty(scrumStatus?.YesterdayTaskDescription) ? string.Empty : scrumStatus?.YesterdayTaskDescription, Wrap = true, }, }, }, new AdaptiveTextBlock { IsSubtle = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Text = localizer.GetString("UpdateStatusTodayDescriptionTitle"), Wrap = true, }, new AdaptiveContainer { Spacing = AdaptiveSpacing.Small, Style = AdaptiveContainerStyle.Emphasis, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Small, Text = string.IsNullOrEmpty(scrumStatus?.TodayTaskDescription) ? string.Empty : scrumStatus?.TodayTaskDescription, Wrap = true, }, }, }, new AdaptiveTextBlock { Color = AdaptiveTextColor.Attention, IsSubtle = true, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Text = localizer.GetString("UpdateStatusAnyBlockersTitle"), Weight = AdaptiveTextWeight.Bolder, Wrap = true, }, new AdaptiveContainer { Spacing = AdaptiveSpacing.Small, Style = AdaptiveContainerStyle.Emphasis, Items = new List <AdaptiveElement> { new AdaptiveTextBlock { Color = AdaptiveTextColor.Attention, HorizontalAlignment = AdaptiveHorizontalAlignment.Left, Spacing = AdaptiveSpacing.Small, Text = string.IsNullOrEmpty(scrumStatus?.BlockerDescription) ? string.Empty : scrumStatus?.BlockerDescription, Wrap = true, }, }, }, }, }, }, }, }; return(userScrumStatusDetails); }
/// <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"), }, }, }); }
/// <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"), }, }, }); }
/// <summary> /// Stores scrum status details in storage. /// </summary> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="scrumStatus">Scrum status entity to be stored in table storage.</param> /// <param name="adaptiveSubmitActionData">Data submitted in task module.</param> /// <param name="scrumStartCardResponseId">Scrum start card response id.</param> /// <param name="aadGroupId">Azure Active Directory group Id.</param> /// <returns>Returns success or failure on whether data is stored in storage.</returns> public async Task <bool> SaveScrumStatusDetailsAsync(ITurnContext <IInvokeActivity> turnContext, ScrumStatus scrumStatus, AdaptiveSubmitActionData adaptiveSubmitActionData, string scrumStartCardResponseId, string aadGroupId) { scrumStatus = scrumStatus ?? throw new ArgumentNullException(nameof(scrumStatus)); turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); scrumStatus.MembersActivityIdMap = adaptiveSubmitActionData?.ScrumMembers; scrumStatus.ScrumStartCardResponseId = scrumStartCardResponseId; scrumStatus.CreatedOn = DateTime.UtcNow.ToString(Constants.Rfc3339DateTimeFormat, CultureInfo.CurrentCulture); scrumStatus.Username = turnContext.Activity.From.Name; scrumStatus.AadGroupId = aadGroupId; scrumStatus.UserAadObjectId = turnContext.Activity.From.AadObjectId; return(await this.scrumStatusStorageProvider.CreateOrUpdateScrumStatusAsync(scrumStatus)); }
/// <summary> /// Stores scrum status details in storage. /// </summary> /// <param name="turnContext">Context object containing information cached for a single turn of conversation with a user.</param> /// <param name="scrumStatus">Scrum status entity to be stored in table storage.</param> /// <param name="adaptiveSubmitActionData">Data submitted in task module.</param> /// <param name="summaryCardId">Scrum summary card id.</param> /// <returns>Returns success or failure on whether data is stored in storage.</returns> public async Task <bool> SaveScrumStatusDetailsAsync(ITurnContext <IInvokeActivity> turnContext, ScrumStatus scrumStatus, AdaptiveSubmitActionData adaptiveSubmitActionData, string summaryCardId) { scrumStatus = scrumStatus ?? throw new ArgumentNullException(nameof(scrumStatus)); scrumStatus.MembersActivityIdMap = adaptiveSubmitActionData?.ScrumMembers; scrumStatus.SummaryCardId = summaryCardId; scrumStatus.CreatedOn = DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", CultureInfo.CurrentCulture); scrumStatus.Username = turnContext?.Activity.From.Name; scrumStatus.AadObjectId = turnContext.Activity.From.AadObjectId; return(await this.scrumStatusStorageProvider.CreateOrUpdateScrumStatusAsync(scrumStatus)); }