/// <summary> /// Gets validation message details card. /// </summary> /// <param name="message">Message to show in card as validation.</param> /// <returns>Envelope for Task Module Response.</returns> public TaskModuleResponse GetValidationErrorCard(string message) { return(new TaskModuleResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo() { Card = HiringManagerNotificationCard.GetValidationMessageCard(message), Height = ValidationMessageTaskModuleHeight, Width = ValidationMessageTaskModuleWidth, Title = this.localizer.GetString("AppTitle"), }, }, }); }
/// <summary> /// Get team confirmation adaptive card. /// </summary> /// <param name="teamChannelMapping">Teams/Channel mappings.</param> /// <param name="introductionEntity">New hire introduction details.</param> /// <param name="isTeamSelected">false if not team has selected.</param> /// <returns>Envelope for Task Module Response.</returns> public TaskModuleResponse GetApproveDetailCard(List <Models.TeamDetail> teamChannelMapping, IntroductionEntity introductionEntity, bool isTeamSelected = true) { return(new TaskModuleResponse { Task = new TaskModuleContinueResponse { Value = new TaskModuleTaskInfo() { Card = HiringManagerNotificationCard.GetTeamConfirmationCard(teamChannelMapping, this.localizer, introductionEntity, isTeamSelected), Height = ApproveDetailTaskModuleHeight, Width = ApproveDetailTaskModuleWidth, Title = this.localizer.GetString("AppTitle"), }, }, }); }
/// <summary> /// Handle when a message is addressed to the bot. /// </summary> /// <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 resolving to either a login card or the adaptive card of the Reddit post.</returns> /// <remarks> /// For more information on bot messaging in Teams, see the documentation /// https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/conversation-basics?tabs=dotnet#receive-a-message . /// </remarks> protected override async Task OnMessageActivityAsync(ITurnContext <IMessageActivity> turnContext, CancellationToken cancellationToken) { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); this.RecordEvent(nameof(this.OnMessageActivityAsync), turnContext); var activity = turnContext.Activity; var command = activity.Text.ToUpperInvariant().Trim(); await this.SendTypingIndicatorAsync(turnContext); if (activity.Conversation.ConversationType == CardConstants.PersonalConversationType) { var userGraphAccessToken = await this.tokenHelper.GetUserTokenAsync(activity.From.Id); if (userGraphAccessToken == null) { await this.dialog.RunAsync(turnContext, this.conversationState.CreateProperty <DialogState>(nameof(DialogState)), cancellationToken); return; } // Command to send feedback card. if (command.Equals(this.localizer.GetString("ShareFeedbackText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var shareFeedbackCardActivity = MessageFactory.Attachment(FeedbackCard.GetFeedbackCardAttachment(this.localizer)); await turnContext.SendActivityAsync(shareFeedbackCardActivity, cancellationToken); return; } // Command to save feedback. else if (command.Equals(this.localizer.GetString("SubmitFeedbackCommandText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { await this.activityHelper.SubmitFeedbackAsync(turnContext); return; } // Command to send on-boarding checklist card. else if (command.Equals(this.localizer.GetString("OnBoardingCheckListText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var userDetail = await this.userStorageProvider.GetUserDetailAsync(activity.From.AadObjectId); bool isNewHire = userDetail?.UserRole == (int)UserRole.NewHire; // Learning plan bot command supports only for new hire. if (!isNewHire) { await turnContext.SendActivityAsync(MessageFactory.Attachment(OnBoardingCheckListCard.GetCard(this.localizer, this.botOptions.Value.ManifestId))); return; } await this.learningPlanHelper.GetWeeklyLearningPlanCardAsync(turnContext, userDetail.BotInstalledOn); } // Bot sign-out command. else if (command.Equals(this.localizer.GetString("LogoutText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { await this.dialog.RunAsync(turnContext, this.conversationState.CreateProperty <DialogState>(nameof(DialogState)), cancellationToken); return; } // Command to send more info card to new hire employee. else if (command.Equals(this.localizer.GetString("RequestMoreInfoText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var valuesfromCard = ((JObject)activity.Value).ToObject <AdaptiveSubmitActionData>(); await this.activityHelper.RequestMoreInfoActionAsync(turnContext, valuesfromCard, cancellationToken); return; } // Command to send user tour based on his role. else if (command.Equals(this.localizer.GetString("HelpText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var userDetail = await this.userStorageProvider.GetUserDetailAsync(activity.From.AadObjectId); bool isManager = userDetail?.UserRole == (int)UserRole.HiringManager; // Send help cards based on their role. await turnContext.SendActivityAsync(MessageFactory.Carousel(CarouselCard.GetUserHelpCards( this.botOptions.Value.AppBaseUri, this.localizer, this.botOptions.Value.ManifestId, isManager))); return; } // Command to send pending review introduction list card. else if (command.Equals(this.localizer.GetString("ReviewIntroductionText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var user = await this.userStorageProvider.GetUserDetailAsync(activity.From.AadObjectId); if (user != null && user.UserRole != (int)UserRole.HiringManager) { await turnContext.SendActivityAsync(MessageFactory.Attachment(HelpCard.GetCard(this.localizer))); return; } var introductionEntities = await this.introductionStorageProvider.GetFilteredIntroductionsAsync(activity.From.AadObjectId); if (!introductionEntities.Any()) { await turnContext.SendActivityAsync(this.localizer.GetString("NoPendingIntroductionText")); return; } var batchCount = (int)Math.Ceiling((double)introductionEntities.Count() / ListCardItemsLimit); for (int batchIndex = 0; batchIndex < batchCount; batchIndex++) { var batchWiseIntroductionEntities = introductionEntities .Skip(batchIndex * ListCardItemsLimit) .Take(ListCardItemsLimit); var listCardAttachment = await this.introductionCardHelper.GetReviewIntroductionListCardAsync(batchWiseIntroductionEntities, userGraphAccessToken); await turnContext.SendActivityAsync(MessageFactory.Attachment(listCardAttachment)); } return; } // Command to send week wise learning plan cards. else if (command.Equals(this.localizer.GetString("ViewLearningText").ToString(), StringComparison.InvariantCultureIgnoreCase)) { var userDetail = await this.userStorageProvider.GetUserDetailAsync(activity.From.AadObjectId); await this.learningPlanHelper.GetWeeklyLearningPlanCardAsync(turnContext, userDetail.BotInstalledOn); } // Command to resume/pause all matches. else if (command.Equals(BotCommandConstants.ResumeAllMatches, StringComparison.InvariantCultureIgnoreCase) || command.Equals(BotCommandConstants.PauseAllMatches, StringComparison.InvariantCultureIgnoreCase)) { await this.activityHelper.GetUpdatedMatchesStatusAsync(turnContext, command, cancellationToken); } else { // If message is from complete learning plan list item tap event. if (command.StartsWith(this.localizer.GetString("ViewWeeklyLearningPlanCommandText"), StringComparison.InvariantCultureIgnoreCase)) { // Get learning plan card selected from complete learning plan list card. var learningCard = await this.learningPlanHelper.GetLearningPlanCardAsync(command); // Send learning plan data card. await turnContext.SendActivityAsync(MessageFactory.Attachment(learningCard)); } else if (command.StartsWith(this.localizer.GetString("ReviewIntroductionCommandText"), StringComparison.InvariantCultureIgnoreCase)) { // Get all Introductions for given Azure Active directory id. if (command.Split(":").Length != 2 || string.IsNullOrWhiteSpace(command.Split(":")[1])) { await turnContext.SendActivityAsync(this.localizer.GetString("ReviewIntroductionInvalidCommandText")); return; } var result = await this.introductionStorageProvider.GetAllIntroductionsAsync(activity.From.AadObjectId); var introductionEntity = result.Where(entity => entity.NewHireName.ToUpperInvariant() == command.Split(":")[1].ToUpperInvariant()).FirstOrDefault(); if (introductionEntity != null && (introductionEntity.ApprovalStatus == (int)IntroductionStatus.Approved)) { // Send already approved message to hiring manager. await turnContext.SendActivityAsync(this.localizer.GetString("ManagerApprovalValidationText")); } else { await turnContext.SendActivityAsync(MessageFactory.Attachment(HiringManagerNotificationCard.GetNewEmployeeIntroductionCard(this.botOptions.Value.AppBaseUri, this.localizer, introductionEntity))); } } else { // Send help card for un supported bot command. await turnContext.SendActivityAsync(MessageFactory.Attachment(HelpCard.GetCard(this.localizer))); } return; } } else { await turnContext.SendActivityAsync(this.localizer.GetString("UnSupportedBotCommand")); } }
/// <summary> /// Submit introduction card action. /// </summary> /// <param name="userGraphAccessToken">User access token.</param> /// <param name="turnContext">Provides context for a step in a bot dialog.</param> /// <param name="taskModuleRequest">Task module invoke request value payload.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> /// <returns>A task that returns submitted introduction card attachment as task module response.</returns> public async Task <TaskModuleResponse> SubmitIntroductionActionAsync( string userGraphAccessToken, ITurnContext <IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken) { turnContext = turnContext ?? throw new ArgumentNullException(nameof(turnContext)); taskModuleRequest = taskModuleRequest ?? throw new ArgumentNullException(nameof(taskModuleRequest)); var userDetails = await this.GetUserDetailAsync(turnContext, cancellationToken); IntroductionEntity introductionEntity = await this.GenerateIntroductionEntityAsync( turnContext, taskModuleRequest, userDetails); var questionnaire = JsonConvert.DeserializeObject <List <IntroductionDetail> >(introductionEntity.NewHireQuestionnaire); if (!questionnaire.Where(row => string.IsNullOrEmpty(row.Answer)).ToList().Any() && !string.IsNullOrWhiteSpace(introductionEntity.NewHireProfileNote)) { // Get Manager details from Microsoft Graph API. var myManager = await this.userProfileGraphApiHelper.GetMyManagerAsync(userGraphAccessToken); if (myManager == null) { this.logger.LogWarning($"Error in getting manager details from Microsoft Graph API for user {turnContext.Activity.From.Id}."); await turnContext.SendActivityAsync(this.localizer.GetString("UserNotMappedWithManagerMessageText")); return(null); } // Get Manager's conversation id from storage. var userConversationDetails = await this.userStorageProvider.GetUserDetailAsync(myManager.Id); if (userConversationDetails == null) { this.logger.LogWarning($"Error in getting user conversation details from storage for user {myManager.Id}."); await turnContext.SendActivityAsync(this.localizer.GetString("ManagerUnavailableText")); return(null); } introductionEntity.ManagerAadObjectId = myManager.Id; introductionEntity.ManagerConversationId = userConversationDetails.ConversationId; await this.introductionStorageProvider.StoreOrUpdateIntroductionDetailAsync(introductionEntity); await turnContext.SendActivityAsync(this.localizer.GetString("IntroSubmittedMessage")); this.logger.LogInformation($"Introduction submitted by: {turnContext.Activity.From.Id}."); var hiringMangerNotification = MessageFactory.Attachment(HiringManagerNotificationCard.GetNewEmployeeIntroductionCard(this.botOptions.Value.AppBaseUri, this.localizer, introductionEntity)); hiringMangerNotification.Conversation = new ConversationAccount { Id = introductionEntity.ManagerConversationId }; await turnContext.Adapter.SendActivitiesAsync(turnContext, new Activity[] { (Activity)hiringMangerNotification }, cancellationToken); return(null); } else { // send back introduction card with corresponding validation message. return(this.introductionCardHelper.GetNewHireIntroductionCard(introductionEntity, isAllQuestionAnswered: false)); } }