Exemple #1
0
        public async Task SyncTeamMembers_NullResponseFromBotAPI_CatchExceptionAndLog()
        {
            // Arrange
            var activityContext = this.GetSyncTeamMembersActivity();
            var teamData        = new TeamDataEntity()
            {
                TenantId = "Tanant1", TeamId = "Team1", ServiceUrl = "serviceUrl"
            };
            IEnumerable <UserDataEntity> userDataEntities = null;

            this.teamDataRepository
            .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(teamData);
            this.membersService
            .Setup(x => x.GetUsersAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(userDataEntities);

            // Act
            Func <Task> task = async() => await activityContext.RunAsync((this.notificationId, this.teamId), this.logger.Object);

            // Assert
            await task.Should().NotThrowAsync();

            this.notificationDataRepository.Verify(x => x.SaveWarningInNotificationDataEntityAsync(It.Is <string>(x => x.Equals(this.notificationId)), It.IsAny <string>()), Times.Once);
        }
        public async Task <ActionResult> PreviewDraftNotificationAsync(
            [FromBody] DraftNotificationPreviewRequest draftNotificationPreviewRequest)
        {
            if (draftNotificationPreviewRequest == null ||
                string.IsNullOrWhiteSpace(draftNotificationPreviewRequest.DraftNotificationId) ||
                string.IsNullOrWhiteSpace(draftNotificationPreviewRequest.TeamsTeamId) ||
                string.IsNullOrWhiteSpace(draftNotificationPreviewRequest.TeamsChannelId))
            {
                return(this.BadRequest());
            }

            var notificationEntity = await this.notificationDataRepository.GetAsync(
                NotificationDataTableNames.DraftNotificationsPartition,
                draftNotificationPreviewRequest.DraftNotificationId);

            if (notificationEntity == null)
            {
                return(this.BadRequest($"Notification {draftNotificationPreviewRequest.DraftNotificationId} not found."));
            }

            var teamDataEntity = new TeamDataEntity();

            teamDataEntity.TenantId   = this.HttpContext.User.FindFirstValue(Common.Constants.ClaimTypeTenantId);
            teamDataEntity.ServiceUrl = await this.appSettingsService.GetServiceUrlAsync();

            var result = await this.draftNotificationPreviewService.SendPreview(
                notificationEntity,
                teamDataEntity,
                draftNotificationPreviewRequest.TeamsChannelId);

            return(this.StatusCode((int)result));
        }
        public async Task SyncTeamMembersActivitySuccessTest()
        {
            // Arrange
            var            activityContext = this.GetSyncTeamMembersActivity();
            TeamDataEntity teamData        = new TeamDataEntity()
            {
                TenantId = "Tanant1", TeamId = "Team1", ServiceUrl = "serviceUrl"
            };
            IEnumerable <UserDataEntity> userData = new List <UserDataEntity>()
            {
                new UserDataEntity()
            };

            teamDataRepository
            .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(teamData);
            membersService
            .Setup(x => x.GetUsersAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(userData);
            sentNotificationDataRepository
            .Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >()))
            .Returns(Task.CompletedTask);

            // Act
            Func <Task> task = async() => await activityContext.RunAsync((notificationId, teamId), logger.Object);

            // Assert
            await task.Should().NotThrowAsync();

            teamDataRepository.Verify(x => x.GetAsync(It.IsAny <string>(), It.Is <string>(x => x.Equals(teamId))));
            membersService.Verify(x => x.GetUsersAsync(It.Is <string>(x => x.Equals(teamData.TeamId)), It.Is <string>(x => x.Equals(teamData.TenantId)), It.Is <string>(x => x.Equals(teamData.ServiceUrl))));
        }
        /// <summary>
        /// Run the activity.
        /// Gets recipient data list (team rosters).
        /// </summary>
        /// <param name="context">Durable orchestration context.</param>
        /// <param name="notificationDataEntityId">Notification data entity id.</param>
        /// <param name="teamDataEntity">Team data entity.</param>
        /// <param name="log">Logging service.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task RunAsync(
            IDurableOrchestrationContext context,
            string notificationDataEntityId,
            TeamDataEntity teamDataEntity,
            ILogger log)
        {
            try
            {
                await context.CallActivityWithRetryAsync <IEnumerable <UserDataEntity> >(
                    nameof(GetRecipientDataListForRosterActivity.GetRecipientDataListForRosterAsync),
                    ActivitySettings.CommonActivityRetryOptions,
                    new GetRecipientDataListForRosterActivityDTO
                {
                    NotificationDataEntityId = notificationDataEntityId,
                    TeamDataEntity           = teamDataEntity,
                });
            }
            catch (Exception ex)
            {
                var format       = this.localizer.GetString("FailedToGetMembersForTeamFormat");
                var errorMessage = string.Format(format, teamDataEntity.TeamId, ex.Message);

                log.LogError(ex, errorMessage);
                await this.handleWarningActivity.RunAsync(context, notificationDataEntityId, errorMessage);
            }
        }
Exemple #5
0
 /// <summary>
 /// The main point of this is to set the recipient Id, service URL, and conversation Id for the send parameters.
 /// </summary>
 /// <param name="getSendNotificationParamsResponse">The send notification parameters to be updated.</param>
 /// <param name="incomingTeamDataEntity">The incoming team data entity.</param>
 private void SetParamsForTeamRecipient(
     GetSendNotificationParamsResponse getSendNotificationParamsResponse,
     TeamDataEntity incomingTeamDataEntity)
 {
     // All necessary parameters will always be set in the incoming team data.
     getSendNotificationParamsResponse.RecipientId    = incomingTeamDataEntity.TeamId;
     getSendNotificationParamsResponse.ServiceUrl     = incomingTeamDataEntity.ServiceUrl;
     getSendNotificationParamsResponse.ConversationId = incomingTeamDataEntity.TeamId;
 }
 /// <summary>
 /// Creates recipient from TeamDataEntity.
 /// </summary>
 /// <param name="notificationId">Notification Id.</param>
 /// <param name="team">Team entity.</param>
 /// <returns><see cref="SentNotificationDataEntity"/> object.</returns>
 private SentNotificationDataEntity ConvertToRecipient(string notificationId, TeamDataEntity team)
 {
     return(new SentNotificationDataEntity
     {
         PartitionKey = notificationId,
         RowKey = team.TeamId,
         RecipientType = SentNotificationDataEntity.TeamRecipientType,
         RecipientId = team.TeamId,
         StatusCode = SentNotificationDataEntity.InitializationStatusCode,
         ConversationId = team.TeamId,
         TenantId = team.TenantId,
         ServiceUrl = team.ServiceUrl,
     });
 }
Exemple #7
0
 /// <summary>
 /// Creates a SentNotificationDataEntity in an initialized state from the given TeamDataEntity
 /// and partition key.
 /// Makes sure to set the correct recipient type for having been created from a TeamDataEntity.
 /// </summary>
 /// <param name="teamDataEntity">The team data entity.</param>
 /// <param name="partitionKey">The partition key.</param>
 /// <returns>The sent notification data entity.</returns>
 public static SentNotificationDataEntity CreateInitialSentNotificationDataEntity(
     this TeamDataEntity teamDataEntity,
     string partitionKey)
 {
     return(new SentNotificationDataEntity
     {
         PartitionKey = partitionKey,
         RowKey = teamDataEntity.TeamId,
         RecipientType = SentNotificationDataEntity.TeamRecipientType,
         RecipientId = teamDataEntity.TeamId,
         StatusCode = SentNotificationDataEntity.InitializationStatusCode,
         ConversationId = teamDataEntity.TeamId,
         TenantId = teamDataEntity.TenantId,
         ServiceUrl = teamDataEntity.ServiceUrl,
     });
 }
Exemple #8
0
        public async Task SyncTeamMembers_OnlyExistingMemberUser_StoreInSentNotificationTable()
        {
            // Arrange
            var activityContext = this.GetSyncTeamMembersActivity();
            var teamData        = new TeamDataEntity()
            {
                TenantId = "Tanant1", TeamId = "Team1", ServiceUrl = "serviceUrl"
            };
            var userDataList = new List <UserDataEntity>()
            {
                new UserDataEntity()
                {
                    UserId = "userId", UserType = UserType.Member
                },
                new UserDataEntity()
                {
                    UserId = "userId", UserType = UserType.Member
                },
            };
            var userData = new UserDataEntity()
            {
                UserId = "userId"
            };

            this.teamDataRepository
            .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(teamData);
            this.membersService
            .Setup(x => x.GetUsersAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(userDataList);
            this.userDataRepository
            .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>()))
            .ReturnsAsync(userData);

            this.sentNotificationDataRepository
            .Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >()))
            .Returns(Task.CompletedTask);

            // Act
            await activityContext.RunAsync((this.notificationId, this.teamId), this.logger.Object);

            // Assert
            this.sentNotificationDataRepository.Verify(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >()), Times.Once);
        }
        public async Task Get_TeamDataSevice_ShouldNeverBeInvokedForEmptysentNotificationData()
        {
            // Arrange
            var activityInstance = this.GetDataStreamFacadeInstance();
            var teamData         = new TeamDataEntity();

            this.sentNotificationDataRepository
            .Setup(x => x.GetStreamsAsync(this.notificationId, null))
            .Returns(this.sentNotificationDataEmptyList.ToAsyncEnumerable());

            this.teamDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(teamData);

            // Act
            var teamDataStream = activityInstance.GetTeamDataStreamAsync(this.notificationId);
            await teamDataStream.ForEachAsync(x => x.ToList());

            // Assert
            this.teamDataRepository.Verify(x => x.GetAsync(It.Is <string>(x => x.Equals(TeamDataTableNames.TeamDataPartition)), It.IsAny <string>()), Times.Never);
        }
        private static TeamDataEntity ParseTeamData(IConversationUpdateActivity activity)
        {
            var channelData = activity.GetChannelData <TeamsChannelData>();

            if (channelData != null)
            {
                var teamsDataEntity = new TeamDataEntity
                {
                    PartitionKey = PartitionKeyNames.TeamDataTable.TeamDataPartition,
                    RowKey       = channelData.Team.Id,
                    TeamId       = channelData.Team.Id,
                    Name         = channelData.Team.Name,
                    ServiceUrl   = activity.ServiceUrl,
                    TenantId     = channelData.Tenant.Id,
                };

                return(teamsDataEntity);
            }

            return(null);
        }
        public async Task GetTeamDataStreamAsyncSuccesTest()
        {
            // Arrange
            var activityInstance = GetDataStreamFacade();
            var teamData = new TeamDataEntity();
            sentNotificationDataRepository
                .Setup(x => x.GetStreamsAsync(notificationId, null))
                .Returns(data.ToAsyncEnumerable());

            teamDataRepository.Setup(x => x.GetAsync(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(teamData);

            // Act
            var userDataStream = activityInstance.GetTeamDataStreamAsync(notificationId);

            Func<Task> task = async () => await userDataStream.ForEachAsync(x => x.ToList());

            // Assert
            await task.Should().NotThrowAsync();
            sentNotificationDataRepository.Verify(x => x.GetStreamsAsync(It.Is<string>(x => x.Equals(notificationId)), null), Times.Once);
            teamDataRepository.Verify(x => x.GetAsync(It.Is<string>(x=>x.Equals(TeamDataTableNames.TeamDataPartition)),It.IsAny<string>()), Times.AtLeastOnce);
        }
        /// <summary>
        /// Prepare conversation.
        /// </summary>
        /// <param name="teamDataEntity">Teams's data.</param>
        /// <param name="channelId">Teams's channel ID.</param>
        /// <returns>conversation Reference of chat/conversation.</returns>
        private ConversationReference PrepareConversationReferenceAsync(TeamDataEntity teamDataEntity, string channelId)
        {
            var channelAccount = new ChannelAccount
            {
                Id = $"28:{this.botAppId}",
            };

            var conversationAccount = new ConversationAccount
            {
                ConversationType = DraftNotificationPreviewService.ChannelConversationType,
                Id       = channelId,
                TenantId = teamDataEntity.TenantId,
            };

            var conversationReference = new ConversationReference
            {
                Bot          = channelAccount,
                ChannelId    = DraftNotificationPreviewService.MsTeamsChannelId,
                Conversation = conversationAccount,
                ServiceUrl   = teamDataEntity.ServiceUrl,
            };

            return(conversationReference);
        }
        /// <summary>
        /// Send a preview of a draft notification.
        /// </summary>
        /// <param name="draftNotificationEntity">Draft notification entity.</param>
        /// <param name="teamDataEntity">The team data entity.</param>
        /// <param name="teamsChannelId">The Teams channel id.</param>
        /// <returns>It returns HttpStatusCode.OK, if this method triggers the bot service to send the adaptive card successfully.
        /// It returns HttpStatusCode.TooManyRequests, if the bot service throttled the request to send the adaptive card.</returns>
        public async Task <HttpStatusCode> SendPreview(NotificationDataEntity draftNotificationEntity, TeamDataEntity teamDataEntity, string teamsChannelId)
        {
            if (draftNotificationEntity == null)
            {
                throw new ArgumentException("Null draft notification entity.");
            }

            if (teamDataEntity == null)
            {
                throw new ArgumentException("Null team data entity.");
            }

            if (string.IsNullOrWhiteSpace(teamsChannelId))
            {
                throw new ArgumentException("Null channel id.");
            }

            // Create bot conversation reference.
            var conversationReference = this.PrepareConversationReferenceAsync(teamDataEntity, teamsChannelId);

            // Ensure the bot service URL is trusted.
            if (!MicrosoftAppCredentials.IsTrustedServiceUrl(conversationReference.ServiceUrl))
            {
                MicrosoftAppCredentials.TrustServiceUrl(conversationReference.ServiceUrl);
            }

            // Trigger bot to send the adaptive card.
            try
            {
                await this.diConnectBotAdapter.ContinueConversationAsync(
                    this.botAppId,
                    conversationReference,
                    async (turnContext, cancellationToken) => await this.SendAdaptiveCardAsync(turnContext, draftNotificationEntity),
                    CancellationToken.None);

                return(HttpStatusCode.OK);
            }
            catch (ErrorResponseException e)
            {
                var errorResponse = (ErrorResponse)e.Body;
                if (errorResponse != null &&
                    errorResponse.Error.Code.Equals(DraftNotificationPreviewService.ThrottledErrorResponse, StringComparison.OrdinalIgnoreCase))
                {
                    return(HttpStatusCode.TooManyRequests);
                }

                throw;
            }
        }
        /// <summary>
        /// Send a preview of a draft notification.
        /// </summary>
        /// <param name="draftNotificationEntity">Draft notification entity.</param>
        /// <param name="teamDataEntity">The team data entity.</param>
        /// <param name="teamsChannelId">The Teams channel id.</param>
        /// <returns>It returns HttpStatusCode.OK, if this method triggers the bot service to send the adaptive card successfully.
        /// It returns HttpStatusCode.TooManyRequests, if the bot service throttled the request to send the adaptive card.</returns>
        public async Task <HttpStatusCode> SendPreview(NotificationDataEntity draftNotificationEntity, TeamDataEntity teamDataEntity, string teamsChannelId)
        {
            if (draftNotificationEntity == null)
            {
                throw new ArgumentException("Null draft notification entity.");
            }

            if (teamDataEntity == null)
            {
                throw new ArgumentException("Null team data entity.");
            }

            if (string.IsNullOrWhiteSpace(teamsChannelId))
            {
                throw new ArgumentException("Null channel id.");
            }

            // Create bot conversation reference.
            var conversationReference = this.PrepareConversationReferenceAsync(teamDataEntity, teamsChannelId);

            // Ensure the bot service URL is trusted.
            if (!MicrosoftAppCredentials.IsTrustedServiceUrl(conversationReference.ServiceUrl))
            {
                MicrosoftAppCredentials.TrustServiceUrl(conversationReference.ServiceUrl);
            }

            // Trigger bot to send the adaptive card.
            try
            {
                var previewQueueMessageContent = new SendQueueMessageContent
                {
                    NotificationId = draftNotificationEntity.Id,
                    ActivtiyId     = null,
                    RecipientData  = null,
                    NotificationUpdatePreviewEntity = new NotificationUpdatePreviewEntity
                    {
                        ActionType             = "PreviewNotification",
                        NotificationDataEntity = null,
                        ConversationReferance  = conversationReference,
                        MessageActivity        = await this.GetPreviewMessageActivity(draftNotificationEntity),
                        ServiceUrl             = conversationReference.ServiceUrl,
                        AppID = this.botAppId,
                    },
                };
                await this.sendQueue.SendAsync(previewQueueMessageContent);

                return(HttpStatusCode.OK);
            }
            catch (ErrorResponseException e)
            {
                var errorResponse = (ErrorResponse)e.Body;
                if (errorResponse != null &&
                    errorResponse.Error.Code.Equals(DraftNotificationPreviewService.ThrottledErrorResponse, StringComparison.OrdinalIgnoreCase))
                {
                    return(HttpStatusCode.TooManyRequests);
                }

                throw;
            }
        }