private async Task <IEnumerable <UserDataEntity> > GetMembersAsync(string teamId, string tenantId, string serviceUrl, string appId) { var conversationReference = new ConversationReference { ServiceUrl = serviceUrl, Conversation = new ConversationAccount { Id = teamId, }, }; IEnumerable <UserDataEntity> userDataEntitiesResult = null; await this.botAdapter.ContinueConversationAsync( appId, conversationReference, async (turnContext, cancellationToken) => { var members = await this.GetMembersAsync(turnContext, cancellationToken); userDataEntitiesResult = members.Select(member => { var userDataEntity = new UserDataEntity { UserId = member.Id, // Set the conversation ID to null because it is not known at this time and // may not have been created yet. ConversationId = null, ServiceUrl = serviceUrl, AadId = member.AadObjectId, TenantId = tenantId, UserType = member.UserPrincipalName.GetUserType(), }; return(userDataEntity); }); }, CancellationToken.None); return(userDataEntitiesResult); }
/// <summary> /// Get a team's roster. /// </summary> /// <param name="serviceUrl">The service URL.</param> /// <param name="teamId">Team id, e.g. "19:[email protected]".</param> /// <returns>Roster of the team with the passed in id.</returns> public async Task <IEnumerable <UserDataEntity> > GetTeamRosterAsync(string serviceUrl, string teamId) { try { MicrosoftAppCredentials.TrustServiceUrl(serviceUrl); var botAppId = this.configuration.GetValue <string>("MicrosoftAppId"); var botAppPassword = this.configuration.GetValue <string>("MicrosoftAppPassword"); var connectorClient = new ConnectorClient( new Uri(serviceUrl), botAppId, botAppPassword); var members = await connectorClient.Conversations.GetConversationMembersAsync(teamId); return(members.Select(member => { var userDataEntity = new UserDataEntity { UserId = member.Id, Name = member.Name, }; if (member.Properties is JObject jObject) { userDataEntity.Email = jObject["email"]?.ToString(); userDataEntity.Upn = jObject["userPrincipalName"]?.ToString(); userDataEntity.AadId = jObject["objectId"].ToString(); userDataEntity.TenantId = jObject["tenantId"].ToString(); userDataEntity.ConversationId = null; userDataEntity.ServiceUrl = serviceUrl; } return userDataEntity; })); } catch { throw new ApplicationException("The app is not authorized to access the bot service. Please send a message to the bot, then it will work."); } }
/// <inheritdoc/> public async Task UpdateUserTypeForExistingUserAsync(UserDataEntity userDataEntity, string userType) { if (userDataEntity == null) { return; } if (!string.IsNullOrEmpty(userDataEntity.UserType)) { return; } if (string.IsNullOrEmpty(userType)) { throw new ArgumentNullException(nameof(userType)); } userDataEntity.UserType = userType; await this.userDataRepository.InsertOrMergeAsync(userDataEntity); }
private void CheckUpdatedUserData(UserDataEntity updatedUserData, UpdateUserDataParams data) { switch (data.UpdateType) { case UpdateType.Value: Assert.Equal(data.Value, updatedUserData.Value); break; case UpdateType.Type: Assert.Equal(data.Type, updatedUserData.UserDataType.DataTypeValue); break; case UpdateType.LevelOfAssurance: Assert.Equal(data.LevelOfAssurance, updatedUserData.LevelOfAssurance.Name); break; default: throw new ArgumentOutOfRangeException(); } }
private void SetUserData(UserDataEntity loadedUserData, UpdateUserDataParams data) { switch (data.UpdateType) { case UpdateType.Value: loadedUserData.Value = data.Value; break; case UpdateType.Type: loadedUserData.UserDataType = CreateTestDataType(data.Type); break; case UpdateType.LevelOfAssurance: loadedUserData.LevelOfAssurance = CreateTestLoa(data.LevelOfAssurance); break; default: throw new ArgumentOutOfRangeException(); } }
public async Task SyncGroupMembers_BothUserTypeForNewUser_StoreOnlyMemberUserType() { // Arrange var groupId = "Group1"; var notificationId = "notificaionId"; var activityContext = this.GetSyncGroupMembersActivity(); var users = new List <User>() { new User() { Id = "userId1", UserPrincipalName = "userPrincipalName1" }, new User() { Id = "userId2", UserPrincipalName = "#ext#" }, }; UserDataEntity userDataEntity = null; this.groupMembersService .Setup(x => x.GetGroupMembersAsync(It.IsAny <string>())) .ReturnsAsync(users); this.userDataRepository .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())) .ReturnsAsync(userDataEntity); this.userTypeService .Setup(x => x.UpdateUserTypeForExistingUserAsync(It.IsAny <UserDataEntity>(), It.IsAny <string>())); this.sentNotificationDataRepository .Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >())) .Returns(Task.CompletedTask); // Act Func <Task> task = async() => await activityContext.RunAsync((notificationId, groupId), this.logger.Object); // Assert await task.Should().NotThrowAsync(); this.sentNotificationDataRepository.Verify(x => x.BatchInsertOrMergeAsync(It.Is <IEnumerable <SentNotificationDataEntity> >(l => l.Count() == 1)), Times.Once); }
public async Task SyncTeamMembers_BothUserTypeForNewUser_StoreOnlyMemberUserType() { // Arrange var activityContext = this.GetSyncTeamMembersActivity(); var teamData = new TeamDataEntity() { TenantId = "Tanant1", TeamId = "Team1", ServiceUrl = "serviceUrl" }; var userDataList = new List <UserDataEntity>() { new UserDataEntity() { UserId = "userId1", UserType = UserType.Guest }, new UserDataEntity() { UserId = "userId2", UserType = UserType.Member }, }; UserDataEntity userData = 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(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.Is <IEnumerable <SentNotificationDataEntity> >(l => l.Count() == 1)), Times.Once); }
private IQueryOver <UserEntity, UserEntity> AddOrderingByLastNameAndFirstNameToQuery(IQueryOver <UserEntity, UserEntity> query, UserEntity userAlias) { UserDataEntity userDataAlias = null; UserDataTypeEntity userDataTypeAlias = null; var lastNameUserData = QueryOver.Of(() => userDataAlias) .JoinAlias(x => x.UserDataType, () => userDataTypeAlias) .Where(x => userDataAlias.ActiveTo == null && userDataAlias.User.Id == userAlias.Id && userDataTypeAlias.DataTypeValue == UserDataTypes.LastName) .Select(x => x.Value); var firstNameUserData = QueryOver.Of(() => userDataAlias) .JoinAlias(x => x.UserDataType, () => userDataTypeAlias) .Where(x => userDataAlias.ActiveTo == null && userDataAlias.User.Id == userAlias.Id && userDataTypeAlias.DataTypeValue == UserDataTypes.FirstName) .Select(x => x.Value); query = query .OrderBy(Projections.SubQuery(lastNameUserData)).Asc .ThenBy(Projections.SubQuery(firstNameUserData)).Asc; return(query); }
public async Task SyncGroupMembers_OnlyMemberExistingUserType_StoreInSentNotificationTable() { // Arrange var groupId = "Group1"; var notificationId = "notificaionId"; var activityContext = this.GetSyncGroupMembersActivity(); var users = new List <User>() { new User() { Id = "userId", UserPrincipalName = "userPrincipalName" }, }; var userDataEntity = new UserDataEntity() { UserId = "userId", }; this.groupMembersService .Setup(x => x.GetGroupMembersAsync(It.IsAny <string>())) .ReturnsAsync(users); this.userDataRepository .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())) .ReturnsAsync(userDataEntity); this.userTypeService .Setup(x => x.UpdateUserTypeForExistingUserAsync(It.IsAny <UserDataEntity>(), It.IsAny <string>())); this.sentNotificationDataRepository .Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >())) .Returns(Task.CompletedTask); // Act Func <Task> task = async() => await activityContext.RunAsync((notificationId, groupId), this.logger.Object); // Assert await task.Should().NotThrowAsync(); this.sentNotificationDataRepository.Verify(x => x.BatchInsertOrMergeAsync(It.Is <IEnumerable <SentNotificationDataEntity> >(x => x.FirstOrDefault().PartitionKey == notificationId))); }
public async Task ExportNotification_validInput_ReturnsStatusCodeOk() { // Arrange var controller = this.GetControllerInstance(); var userDataEntity = new UserDataEntity(); var exportRequest = new ExportRequest() { Id = "Id" }; var statusCodeOk = 200; var exportDataEntity = new ExportDataEntity() { RowKey = exportRequest.Id, SentDate = DateTime.UtcNow, Status = ExportStatus.New.ToString(), }; var userDataList = new List <UserDataEntity>() { new UserDataEntity() { AadId = null } }; this.userDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(userDataEntity); this.sentNotificationDataRepository.Setup(x => x.EnsureSentNotificationDataTableExistsAsync()).Returns(Task.CompletedTask); this.exportDataRepository.Setup(x => x.EnsureExportDataTableExistsAsync()).Returns(Task.CompletedTask); this.exportDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).Returns(Task.FromResult(default(ExportDataEntity))); this.exportDataRepository.Setup(x => x.CreateOrUpdateAsync(It.IsAny <ExportDataEntity>())).Returns(Task.CompletedTask); this.exportQueue.Setup(x => x.SendAsync(It.IsAny <ExportQueueMessageContent>())).Returns(Task.CompletedTask); // Act var result = await controller.ExportNotificationAsync(exportRequest); var statusCode = ((StatusCodeResult)result).StatusCode; // Assert Assert.Equal(statusCode, statusCodeOk); }
private static UserDataEntity ParseUserData(IConversationUpdateActivity activity) { var rowKey = activity?.From?.AadObjectId; if (rowKey != null) { var userDataEntity = new UserDataEntity { PartitionKey = UserDataTableNames.UserDataPartition, RowKey = activity?.From?.AadObjectId, AadId = activity?.From?.AadObjectId, UserId = activity?.From?.Id, ConversationId = activity?.Conversation?.Id, ServiceUrl = activity?.ServiceUrl, TenantId = activity?.Conversation?.TenantId, }; return(userDataEntity); } return(null); }
/// <summary> /// Sets active to property of current user data and creates new version from updated current version /// </summary> /// <param name="updatedUserData">Current version with modified properties</param> /// <param name="currentUserData">Current version of user data</param> /// <param name="parent">Parent for new version</param> /// <param name="now">Time of update</param> /// <returns>Newly created version of user data</returns> private UserDataEntity HandleNewVersion(UserDataEntity updatedUserData, UserDataEntity currentUserData, UserDataEntity parent, DateTime now) { var newActiveTo = updatedUserData.ActiveTo; if (currentUserData.ActiveTo == null || currentUserData.ActiveTo > now) { currentUserData.ActiveTo = now; m_userDataRepository.Update(currentUserData); } if (newActiveTo <= now) { throw new InvalidOperationException("ActiveTo property of new UserData version must be null or greater than UtcNow"); } var newVersion = CreateNewVersion(updatedUserData, now, newActiveTo, parent); var newVersionId = (int)m_userDataRepository.Create(newVersion); return(m_userDataRepository.FindById <UserDataEntity>(newVersionId)); }
public async Task ExportNotification_NotificationExistsInAzureStorage_ReturnsStatusCodeConflict() { // Arrange var controller = this.GetControllerInstance(); var userDataEntity = new UserDataEntity(); var exportRequest = new ExportRequest(); var exportDataEntity = new ExportDataEntity(); var statusCodeConfict = 409; this.userDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(userDataEntity); this.sentNotificationDataRepository.Setup(x => x.EnsureSentNotificationDataTableExistsAsync()).Returns(Task.CompletedTask); this.exportDataRepository.Setup(x => x.EnsureExportDataTableExistsAsync()).Returns(Task.CompletedTask); this.exportDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(exportDataEntity); // Act var result = await controller.ExportNotificationAsync(exportRequest); var statusCode = ((StatusCodeResult)result).StatusCode; // Assert Assert.Equal(statusCode, statusCodeConfict); }
public virtual bool Equals(UserDataEntity x, UserDataEntity y) { if (ReferenceEquals(x, y)) { return(true); } if (ReferenceEquals(null, y)) { return(false); } if (ReferenceEquals(x, null)) { return(false); } return(Equals(x.User?.Id, y.User?.Id) && //User has to be same Equals(x.UserDataType?.Id, y.UserDataType?.Id) && //DataType has to be same Equals(x.ActiveTo, y.ActiveTo) && // Active to date has to be the same Equals(x.VerifiedBy?.Id, y.VerifiedBy?.Id) && //Verifier has to be same string.Equals(x.Value, y.Value) && //Value has to be same Equals(x.LevelOfAssurance?.Id, y.LevelOfAssurance?.Id) && //Level of assurance has to be same Equals(x.DataSource?.Id, y.DataSource?.Id)); //Data source has to be same }
public async Task Delete_ValidFile_DeleteIfExistsAsyncShouldNeveOnce() { // Arrange var activityInstance = this.GetHandleExportFailureActivity(); var exportDataEntity = new ExportDataEntity() { FileName = "fileName", PartitionKey = "partitionKey" }; var userDataEntity = new UserDataEntity() { ServiceUrl = "serviceUrl", ConversationId = "conversationId" }; var blobContainerClientmock = GetBlobContainerClientMock(); this.storageClientFactory.Setup(x => x.CreateBlobContainerClient()).Returns(blobContainerClientmock.Object); this.userDataRepository.Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(userDataEntity); // Act await activityInstance.HandleFailureActivityAsync(exportDataEntity); // Assert blobContainerClientmock.Verify(x => x.GetBlobClient(It.IsAny <string>()).DeleteIfExistsAsync(It.IsAny <DeleteSnapshotsOption>(), It.IsAny <BlobRequestConditions>(), It.IsAny <CancellationToken>()), Times.Once); }
public async Task SyncGroupMembers_NullResponseFromGraph_CatchExceptionAndLog() { // Arrange var groupId = "Group1"; var notificationId = "notificaionId"; var activityContext = this.GetSyncGroupMembersActivity(); List <User> users = null; var userDataEntity = new UserDataEntity() { UserId = "userId", }; this.groupMembersService .Setup(x => x.GetGroupMembersAsync(It.IsAny <string>())) .ReturnsAsync(users); // Act Func <Task> task = async() => await activityContext.RunAsync((notificationId, groupId), this.logger.Object); // Assert await task.Should().NotThrowAsync(); this.notificationDataRepository.Verify(x => x.SaveWarningInNotificationDataEntityAsync(It.IsAny <string>(), It.IsAny <string>()), Times.Once); }
/// <summary> /// Creates a user conversation. /// </summary> /// <param name="userDataEntity">The data entity for the user for whom the conversation should be created.</param> /// <param name="maxNumberOfAttempts">The maximum number of request attempts to create the conversation.</param> /// <param name="log">The logger.</param> /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns> public async Task <CreateUserConversationResponse> CreateConversationAsync( UserDataEntity userDataEntity, int maxNumberOfAttempts, ILogger log) { var createConversationResponse = new CreateUserConversationResponse(); // Set the service URL in the trusted list to ensure the SDK includes the token in the request. MicrosoftAppCredentials.TrustServiceUrl(userDataEntity.ServiceUrl); // Create the conversation parameters that will be used when // creating the conversation for that user. var conversationParameters = new ConversationParameters { TenantId = userDataEntity.TenantId, Members = new ChannelAccount[] { new ChannelAccount { Id = userDataEntity.UserId, }, }, }; // Loop through attempts to try and create the conversation for the user. var conversationCreatedSuccessfully = false; for (int i = 1; i <= maxNumberOfAttempts && !conversationCreatedSuccessfully; i++) { try { await this.botAdapter.CreateConversationAsync( channelId : CreateUserConversationService.MicrosoftTeamsChannelId, serviceUrl : userDataEntity.ServiceUrl, credentials : this.appCredentials, conversationParameters : conversationParameters, callback : (turnContext, cancellationToken) => { // If this callback is used, that means the conversation was // created successfully and the information will be in the Activity of // the turnContext. // Set the status code to indicate it was created, set that it was // successfully created, and place that conversationId in the response for // use when sending the notification to the user. createConversationResponse.ResultType = CreateUserConversationResultType.Succeeded; createConversationResponse.StatusCode = (int)HttpStatusCode.Created; createConversationResponse.ConversationId = turnContext.Activity.Conversation.Id; // This is used to signal the conversation was created successfully and to // "break" out of the loop in order to not make multiple attempts. conversationCreatedSuccessfully = true; return(Task.CompletedTask); }, cancellationToken : CancellationToken.None); } catch (ErrorResponseException e) { var errorMessage = $"{e.GetType()}: {e.Message}"; log.LogError(e, $"ERROR: {errorMessage}"); // This exception is thrown when a failure response is received when making the request // to create the conversation. var responseStatusCode = e.Response.StatusCode; createConversationResponse.StatusCode = (int)responseStatusCode; // If the response was a throttled status code or a 5xx status code, // then delay and retry the request. if (responseStatusCode == HttpStatusCode.TooManyRequests || ((int)responseStatusCode >= 500 && (int)responseStatusCode < 600)) { if (responseStatusCode == HttpStatusCode.TooManyRequests) { // If the request was throttled, set the flag for indicating the throttled state. createConversationResponse.ResultType = CreateUserConversationResultType.Throttled; } else { // If the request failed with a 5xx status code, set the flag for indicating the failure // and store the content of the error message. createConversationResponse.ResultType = CreateUserConversationResultType.Failed; createConversationResponse.ErrorMessage = e.Response.Content; } // If the maximum number of attempts has not been reached, delay // for a bit of time to attempt the request again. // Do not delay if already attempted the maximum number of attempts. if (i < maxNumberOfAttempts) { var random = new Random(); await Task.Delay(random.Next(500, 1500)); } } else { // If in this block, then an error has occurred with the service. // Return the failure and do not attempt the request again. createConversationResponse.ResultType = CreateUserConversationResultType.Failed; createConversationResponse.ErrorMessage = e.Response.Content; break; } } } return(createConversationResponse); }
/// <summary> /// Send a notification to target users. /// </summary> /// <param name="draftNotificationEntity">The draft notification to be sent.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task SendAsync(NotificationDataEntity draftNotificationEntity) { if (draftNotificationEntity == null || !draftNotificationEntity.IsDraft) { return; } // If message is scheduled or recurrence if (draftNotificationEntity.IsScheduled || draftNotificationEntity.IsRecurrence) { DateTime notificationDate; bool isValidToProceed = true; // Calculate next schedule if (draftNotificationEntity.IsScheduled) { notificationDate = draftNotificationEntity.ScheduleDate; } else { DateTime repeatStartDate = draftNotificationEntity.RepeatStartDate; DateTime currentDate = DateTime.UtcNow.AddDays(-1); // If Recurring start date is older than today date, setting to today date if (repeatStartDate < currentDate) { repeatStartDate = currentDate; } notificationDate = repeatStartDate; if (notificationDate > draftNotificationEntity.RepeatEndDate) { isValidToProceed = false; } } if (isValidToProceed) { var newSentNotificationId = await this.notificationDataRepository.MoveDraftToSentPartitionAsync(draftNotificationEntity, true); var scheduleNotificationEntity = new ScheduleNotificationDataEntity { PartitionKey = PartitionKeyNames.ScheduleNotificationDataTable.ScheduleNotificationsPartition, RowKey = newSentNotificationId, NotificationId = newSentNotificationId, NotificationDate = notificationDate, CreatedDate = DateTime.UtcNow, }; await this.scheduleNotificationDataRepository.CreateScheduleNotification(scheduleNotificationEntity); } } else // If message is onetime sending { List <UserDataEntity> deDuplicatedReceiverEntities = new List <UserDataEntity>(); if (draftNotificationEntity.AllUsers) { // Get all users var usersUserDataEntityDictionary = await this.metadataProvider.GetUserDataDictionaryAsync(); deDuplicatedReceiverEntities.AddRange(usersUserDataEntityDictionary.Select(kvp => kvp.Value)); } else { if (draftNotificationEntity.Rosters.Count() != 0) { var rosterUserDataEntityDictionary = await this.metadataProvider.GetTeamsRostersAsync(draftNotificationEntity.Rosters); deDuplicatedReceiverEntities.AddRange(rosterUserDataEntityDictionary.Select(kvp => kvp.Value)); } if (draftNotificationEntity.Teams.Count() != 0) { var teamsReceiverEntities = await this.metadataProvider.GetTeamsReceiverEntities(draftNotificationEntity.Teams); deDuplicatedReceiverEntities.AddRange(teamsReceiverEntities); } if (draftNotificationEntity.ADGroups.Count() != 0) { // Get AD Groups members. var adGroupMemberEntities = await this.metadataProvider.GetADGroupReceiverEntities(draftNotificationEntity.ADGroups); List <UserDataEntity> adGroupMembers = new List <UserDataEntity>(); adGroupMembers.AddRange(adGroupMemberEntities); adGroupMembers = adGroupMembers.ToList(); // Get all users details from database. var usersUserDataEntityDictionary = await this.metadataProvider.GetUserDataDictionaryAsync(); List <UserDataEntity> deAllEntities = new List <UserDataEntity>(); deAllEntities.AddRange(usersUserDataEntityDictionary.Select(kvp => kvp.Value)); deAllEntities = deAllEntities.ToList(); // To get conversation id, mapping all users and ad groups members. for (int i = 0; i < adGroupMembers.Count(); i++) { UserDataEntity userDataEntity = deAllEntities.Find(item => item.AadId == adGroupMembers[i].Id); if (userDataEntity != null && userDataEntity.AadId != null) { deDuplicatedReceiverEntities.Add(userDataEntity); } } deDuplicatedReceiverEntities = deDuplicatedReceiverEntities.Distinct().ToList(); } } var totalMessageCount = deDuplicatedReceiverEntities.Count; draftNotificationEntity.TotalMessageCount = totalMessageCount; var newSentNotificationId = await this.notificationDataRepository.MoveDraftToSentPartitionAsync(draftNotificationEntity, false); // Set in SendingNotification data await this.sendingNotificationCreator.CreateAsync(newSentNotificationId, draftNotificationEntity); var allServiceBusMessages = deDuplicatedReceiverEntities .Select(userDataEntity => { var queueMessageContent = new ServiceBusSendQueueMessageContent { NotificationId = newSentNotificationId, UserDataEntity = userDataEntity, }; var messageBody = JsonConvert.SerializeObject(queueMessageContent); return(new Message(Encoding.UTF8.GetBytes(messageBody))); }) .ToList(); // Create batches to send to the service bus var serviceBusBatches = new List <List <Message> >(); var totalNumberMessages = allServiceBusMessages.Count; var batchSize = 100; var numberOfCompleteBatches = totalNumberMessages / batchSize; var numberMessagesInIncompleteBatch = totalNumberMessages % batchSize; for (var i = 0; i < numberOfCompleteBatches; i++) { var startingIndex = i * batchSize; var batch = allServiceBusMessages.GetRange(startingIndex, batchSize); serviceBusBatches.Add(batch); } if (numberMessagesInIncompleteBatch != 0) { var incompleteBatchStartingIndex = numberOfCompleteBatches * batchSize; var incompleteBatch = allServiceBusMessages.GetRange( incompleteBatchStartingIndex, numberMessagesInIncompleteBatch); serviceBusBatches.Add(incompleteBatch); } string serviceBusConnectionString = this.configuration["ServiceBusConnection"]; string queueName = "company-communicator-send"; var messageSender = new MessageSender(serviceBusConnectionString, queueName); // Send batches of messages to the service bus foreach (var batch in serviceBusBatches) { await messageSender.SendAsync(batch); } await this.SendTriggerToDataFunction( this.configuration, newSentNotificationId, totalMessageCount); } }
public IActionResult AddUserDataSql([FromBody] UserDataEntity userData) { addEntityToSql(userData); return(new OkObjectResult("Saved successfully")); }
public async Task SyncAllUser_RemovedUsers_DeleteUserFromTable() { // Arrange var activityContext = this.GetSyncAllUsersActivity(); string deltaLink = "deltaLink"; IEnumerable <UserDataEntity> userDataResponse = new List <UserDataEntity>() { new UserDataEntity() { Name = string.Empty, UserType = UserType.Member }, }; NotificationDataEntity notification = new NotificationDataEntity() { Id = "notificationId1", }; var userData = new UserDataEntity() { AadId = "101" }; (IEnumerable <User>, string)tuple = (new List <User>() { new User() { Id = "101", AdditionalData = new Dictionary <string, object>() { { "@removed", null } } } }, deltaLink); this.userDataRepository .Setup(x => x.GetDeltaLinkAsync()) .ReturnsAsync(deltaLink); this.userService .Setup(x => x.GetAllUsersAsync(It.IsAny <string>())) .ReturnsAsync(tuple); this.userDataRepository .Setup(x => x.SetDeltaLinkAsync(It.IsAny <string>())) .Returns(Task.CompletedTask); this.userDataRepository .Setup(x => x.GetAllAsync(It.IsAny <string>(), null)) .ReturnsAsync(userDataResponse); this.userDataRepository .Setup(x => x.GetAsync(It.IsAny <string>(), It.IsAny <string>())) .ReturnsAsync(userData); this.userDataRepository .Setup(x => x.DeleteAsync(It.IsAny <UserDataEntity>())) .Returns(Task.CompletedTask); // store user data this.userDataRepository .Setup(x => x.InsertOrMergeAsync(It.IsAny <UserDataEntity>())) .Returns(Task.CompletedTask); this.sentNotificationDataRepository.Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >())); // Act await activityContext.RunAsync(notification, this.logger.Object); // Assert this.userDataRepository.Verify(x => x.InsertOrMergeAsync(It.IsAny <UserDataEntity>()), Times.Never); this.userDataRepository.Verify(x => x.DeleteAsync(It.IsAny <UserDataEntity>()), Times.Once); }
private void HydrateUserData( DateTime now, UserEntity userEntity, IList <UserDataLoAModel> userData, IList <UserDataEntity> userDataToUpdate, IDictionary <string, UserDataEntity> userDataDict, IDictionary <string, UserDataTypeEntity> userDataTypesDict, string externalProviderName, UserDataEntity parentEntity = null ) { if (userData == null) { return; } var levelOfAssuranceCache = new LevelOfAssuranceCache(m_levelOfAssuranceRepository); var dataSource = Lazy.Of(() => { if (string.IsNullOrEmpty(externalProviderName)) { return(m_dataSourceRepository.GetDataSourceByDataSource( DataSourceEnum.User )); } var externalLoginProviderEntity = m_externalLoginProviderRepository.GetExternalLoginProviderByName( externalProviderName ); return(m_dataSourceRepository.GetDataSourceByDataSource( DataSourceEnum.ExternalLoginProvider, externalLoginProviderEntity.Id )); } ); foreach (var dataEntityModel in userData) { var dataEntity = dataEntityModel.UserData; if (userDataDict != null && userDataDict.ContainsKey(dataEntity.UserDataType.DataTypeValue)) { var userDataEntity = userDataDict[dataEntity.UserDataType.DataTypeValue]; if (dataEntity.Value != userDataEntity.Value) { userDataEntity.LevelOfAssurance = levelOfAssuranceCache.GetByEnum(dataEntityModel.LevelOfAssuranceEnum); userDataEntity.DataSource = dataEntityModel.UserData.DataSource ?? dataSource.Value; //UserData generated by system, e.g. MasterUserId, has DataSource already set } userDataEntity.Value = dataEntity.Value; if (dataEntity.ActiveTo == null || dataEntity.ActiveTo > now) { userDataEntity.ActiveTo = dataEntity.ActiveTo; } else { throw new InvalidOperationException("ActiveTo property of new UserData version must be null or greater than UtcNow"); } userDataEntity.ParentUserData = parentEntity; userDataToUpdate.Add(userDataEntity); HydrateUserData(now, userEntity, dataEntity.ChildrenUserData?.Select(x => new UserDataLoAModel { UserData = x, LevelOfAssuranceEnum = dataEntityModel.LevelOfAssuranceEnum }).ToList(), userDataToUpdate, userDataDict, userDataTypesDict, externalProviderName, userDataEntity ); } else { // expect this mean it is new "row" dataEntity.User = userEntity; dataEntity.UserDataType = userDataTypesDict[dataEntity.UserDataType.DataTypeValue]; dataEntity.ParentUserData = parentEntity; dataEntity.LevelOfAssurance = levelOfAssuranceCache.GetByEnum(dataEntityModel.LevelOfAssuranceEnum); dataEntity.DataSource = dataEntityModel.UserData.DataSource ?? dataSource.Value; userDataToUpdate.Add(dataEntity); HydrateUserData(now, userEntity, dataEntity.ChildrenUserData?.Select(x => new UserDataLoAModel { UserData = x, LevelOfAssuranceEnum = dataEntityModel.LevelOfAssuranceEnum }).ToList(), userDataToUpdate, userDataDict, userDataTypesDict, externalProviderName, dataEntity ); } } }
public virtual int CreateUserData(UserDataEntity userData) { var result = (int)m_userDataRepository.Create(userData); return(result); }
public Dictionary <string, UserDataEntity> GenerageProjectRelativeUsers(string token, string hospitalid, string q) { ProjectRelativePIResponse projectRelativePIResponse = new ProjectRelativePIResponse(); ProjectRelativeDoctorResponse projectRelativeDoctorResponse = new ProjectRelativeDoctorResponse(); ProjectRelativePatientResponse projectRelativePatientResponse = new ProjectRelativePatientResponse(); string apiPI = ProjectRelativePI(token, hospitalid, q); string apiDoctor = ProjectRelativeDoctor(token, hospitalid, q); string apiPatient = ProjectRelativePatient(token, hospitalid, q); projectRelativePIResponse = JsonHelper.DeserializeJsonToObject <ProjectRelativePIResponse>(apiPI); projectRelativeDoctorResponse = JsonHelper.DeserializeJsonToObject <ProjectRelativeDoctorResponse>(apiDoctor); if (!apiPatient.Contains("[]")) { projectRelativePatientResponse = JsonHelper.DeserializeJsonToObject <ProjectRelativePatientResponse>(apiPatient); } Dictionary <string, UserDataEntity> messageUserList = new Dictionary <string, UserDataEntity>(); if (projectRelativePIResponse.data != null) { foreach (ProjectRelativePIInfo pi in projectRelativePIResponse.data) { if (messageUserList.ContainsKey(pi.piid) == false) { UserDataEntity userDataEntity = new UserDataEntity(); userDataEntity.dataId = pi.piid; userDataEntity.role = pi.role; userDataEntity.username = pi.username; messageUserList.Add(pi.piid, userDataEntity); } } } if (projectRelativeDoctorResponse.data != null) { foreach (ProjectRelativeDoctorInfo doc in projectRelativeDoctorResponse.data) { if (messageUserList.ContainsKey(doc.doctorid) == false) { UserDataEntity userDataEntity = new UserDataEntity(); userDataEntity.dataId = doc.doctorid; userDataEntity.role = doc.role; userDataEntity.username = doc.username; messageUserList.Add(doc.doctorid, userDataEntity); } } } if (projectRelativePatientResponse.data != null) { foreach (ProjectRelativePatientInfo pat in projectRelativePatientResponse.data) { if (messageUserList.ContainsKey(pat.patientid) == false) { UserDataEntity userDataEntity = new UserDataEntity(); userDataEntity.dataId = pat.patientid; userDataEntity.role = pat.role; userDataEntity.username = pat.username; messageUserList.Add(pat.patientid, userDataEntity); } } } return(messageUserList); }
/// <summary> /// Send a scheduled notification to target users. /// </summary> /// <param name="notificationEntity">The notification to be sent.</param> /// <returns>A task that represents the work queued to execute.</returns> public async Task SendScheduledNotificationAsync(NotificationDataEntity notificationEntity) { List <UserDataEntity> deDuplicatedReceiverEntities = new List <UserDataEntity>(); if (notificationEntity.AllUsers) { // Get all users var usersUserDataEntityDictionary = await this.metadataProvider.GetUserDataDictionaryAsync(); deDuplicatedReceiverEntities.AddRange(usersUserDataEntityDictionary.Select(kvp => kvp.Value)); } else { if (notificationEntity.Rosters.Count() != 0) { var rosterUserDataEntityDictionary = await this.metadataProvider.GetTeamsRostersAsync(notificationEntity.Rosters); deDuplicatedReceiverEntities.AddRange(rosterUserDataEntityDictionary.Select(kvp => kvp.Value)); } if (notificationEntity.Teams.Count() != 0) { var teamsReceiverEntities = await this.metadataProvider.GetTeamsReceiverEntities(notificationEntity.Teams); deDuplicatedReceiverEntities.AddRange(teamsReceiverEntities); } if (notificationEntity.ADGroups.Count() != 0) { // Get AD Groups members. var adGroupMemberEntities = await this.metadataProvider.GetADGroupReceiverEntities(notificationEntity.ADGroups); List <UserDataEntity> adGroupMembers = new List <UserDataEntity>(); adGroupMembers.AddRange(adGroupMemberEntities); adGroupMembers = adGroupMembers.ToList(); // Get all users details from database. var usersUserDataEntityDictionary = await this.metadataProvider.GetUserDataDictionaryAsync(); List <UserDataEntity> deAllEntities = new List <UserDataEntity>(); deAllEntities.AddRange(usersUserDataEntityDictionary.Select(kvp => kvp.Value)); deAllEntities = deAllEntities.ToList(); // To get conversation id, mapping all users and ad groups members. for (int i = 0; i < adGroupMembers.Count(); i++) { UserDataEntity userDataEntity = deAllEntities.Find(item => item.AadId == adGroupMembers[i].Id); if (userDataEntity != null && userDataEntity.AadId != null) { deDuplicatedReceiverEntities.Add(userDataEntity); } } deDuplicatedReceiverEntities = deDuplicatedReceiverEntities.Distinct().ToList(); } } var totalMessageCount = deDuplicatedReceiverEntities.Count; notificationEntity.TotalMessageCount = totalMessageCount; // Creates record in Sent notifications. var newSentNotificationId = await this.notificationDataRepository.CopyToSentPartitionAsync(notificationEntity); // Set in SendingNotification data await this.sendingNotificationCreator.CreateAsync(newSentNotificationId, notificationEntity); var allServiceBusMessages = deDuplicatedReceiverEntities .Select(userDataEntity => { var queueMessageContent = new ServiceBusSendQueueMessageContent { NotificationId = newSentNotificationId, UserDataEntity = userDataEntity, }; var messageBody = JsonConvert.SerializeObject(queueMessageContent); return(new Message(Encoding.UTF8.GetBytes(messageBody))); }) .ToList(); // Create batches to send to the service bus var serviceBusBatches = new List <List <Message> >(); var totalNumberMessages = allServiceBusMessages.Count; var batchSize = 100; var numberOfCompleteBatches = totalNumberMessages / batchSize; var numberMessagesInIncompleteBatch = totalNumberMessages % batchSize; for (var i = 0; i < numberOfCompleteBatches; i++) { var startingIndex = i * batchSize; var batch = allServiceBusMessages.GetRange(startingIndex, batchSize); serviceBusBatches.Add(batch); } if (numberMessagesInIncompleteBatch != 0) { var incompleteBatchStartingIndex = numberOfCompleteBatches * batchSize; var incompleteBatch = allServiceBusMessages.GetRange( incompleteBatchStartingIndex, numberMessagesInIncompleteBatch); serviceBusBatches.Add(incompleteBatch); } string serviceBusConnectionString = this.configuration["ServiceBusConnection"]; string queueName = "company-communicator-send"; var messageSender = new MessageSender(serviceBusConnectionString, queueName); // Send batches of messages to the service bus foreach (var batch in serviceBusBatches) { await messageSender.SendAsync(batch); } await this.SendTriggerToDataFunction( this.configuration, newSentNotificationId, totalMessageCount); }
/// <summary> /// When parent of current user data version is different than parent, update it /// </summary> /// <param name="currentUserData">Current version of user data</param> /// <param name="parent">Possible new parent of current version</param> private void UpdateParentOfUserData(UserDataEntity currentUserData, UserDataEntity parent) { currentUserData.ParentUserData = parent; m_userDataRepository.Update(currentUserData); }
/// <summary> /// When the two user data are different, i.e. has one property of User, UserDataType, Verifier, Value, LoA, DataSource different, returns true /// </summary> /// <param name="updatedUserData">User data to compare</param> /// <param name="loadedUserData">User data to compare</param> /// <returns>True if the two provided user data are different, otherwise false</returns> private bool IsNewVersionNeeded(UserDataEntity updatedUserData, UserDataEntity loadedUserData) { return(!m_userDataEqualityComparer.Equals(updatedUserData, loadedUserData)); }
// GET: F8YLMessage public ActionResult MessageIndex(string pageType, string projectId, string hospitalId, string patientId) { //patientId = "93"; //ViewBag.patientId = patientId; var token = Session["token"] == null ? "XXXXXXX" : Session["token"].ToString(); // Session["role"] ViewBag.Token = token; var currentUserId = Session["CurrentUserID"] == null ? "-1" : Session["CurrentUserID"].ToString(); var currentUserHospitalID = Session["CurrentUserHospitalID"] == null ? "-1" : Session["CurrentUserHospitalID"].ToString(); var currentUserRole = Session["role"] == null ? "XXXXXXX" : Session["role"].ToString(); string dateParam = Convert.ToString(DateTime.Today.AddMonths(-1).ToString("yyyy-MM-01")); ViewBag.currentUserId = currentUserId; ViewBag.pageType = pageType; ViewBag.projectId = projectId == null ? "-1" : projectId; ViewBag.hospitalId = hospitalId == null ? "-1" : hospitalId; ViewBag.patientId = string.IsNullOrEmpty(patientId) ? currentUserId : patientId; ViewBag.currentUserRole = currentUserRole; List <JoinedProjectEntity> projectList = new List <JoinedProjectEntity>(); //if (currentUserRole != "90") //{ // // 生成项目列表,传递到页面; // ProjectJoined projectJoined = projectRequest.Joined(token); // if (projectJoined.data != null) // { // projectList = projectJoined.data; // } //} // 生成项目列表,传递到页面; ProjectJoined projectJoined = projectRequest.Joined(token, "0"); if (projectJoined.data != null) { projectList = projectJoined.data; } ViewBag.ProjectList = projectList; // 生成用户列表,传递到页面; //HospitalUserProfileResponse hospitalUsers = new HospitalUserProfileResponse(); //hospitalUsers = userRequest.SearchUsers(token, currentUserHospitalID, ""); //ProjectRelativeUserResponse projectRelativeUserResponse = new ProjectRelativeUserResponse(); //projectRelativeUserResponse = projectRequest.ProjectRelativeUsers(token, "", ""); List <UserDataEntity> userList = new List <UserDataEntity>(); string userHospitalID = currentUserHospitalID; if (currentUserRole == "90" || currentUserRole == "80") { if (currentUserRole == "90") { userHospitalID = ""; } HospitalUserProfileResponse hospitalUsers = new HospitalUserProfileResponse(); hospitalUsers = userRequest.SearchUsers(token, userHospitalID, ""); if (hospitalUsers.data != null && hospitalUsers.data.data != null) { foreach (HospitalUserProfileInfo u in hospitalUsers.data.data) { UserDataEntity user = new UserDataEntity(); user.dataId = u.id; user.role = u.role; user.username = u.username; userList.Add(user); } } } else { Dictionary <string, UserDataEntity> messageUserList = projectRequest.GenerageProjectRelativeUsers(token, "", ""); userList = FilterBusersByCurrentUserRole(messageUserList, currentUserRole, currentUserId); } ViewBag.ProjectUsers = userList; // 调用接口,获取发送给自己的消息列表和公告列表 //RecvResponse recvResponseMessage = messageRequest.Recv(token, "0", dateParam, ""); ChatResponse recvResponseMessage = messageRequest.Chat(token, "0"); // 生成消息列表,传递到页面; List <PageMessageEntity> pageMessageList = new List <PageMessageEntity>(); if (recvResponseMessage.data != null) { Dictionary <string, string> usersInfo = new Dictionary <string, string>(); foreach (ChatResponseDataChatEntity item in recvResponseMessage.data.data) { PageMessageEntity pageMessageEntity = new PageMessageEntity(); pageMessageEntity.id = item.id; pageMessageEntity.userid = item.userid; pageMessageEntity.ctime = item.ctime; pageMessageEntity.msg = item.msg; pageMessageEntity.label = ""; pageMessageEntity.username = item.user.username; //if (usersInfo.ContainsKey(item.userid) == true) //{ // pageMessageEntity.username = usersInfo[item.userid]; //} //else //{ // UserProfileResponse user = userRequest.profile(token, item.userid); // if (user.data != null) // { // pageMessageEntity.username = user.data.username; // } // else // { // pageMessageEntity.username = "******"; // } // usersInfo.Add(item.userid, pageMessageEntity.username); //} //bool isExists = false; // foreach (PageMessageEntity msg in pageMessageList) //{ // if (msg.userid == pageMessageEntity.userid) // { // if (Convert.ToDateTime(pageMessageEntity.ctime) > Convert.ToDateTime(msg.ctime)) // { // pageMessageList.Remove(msg); // pageMessageList.Add(pageMessageEntity); // } // isExists = true; // } //} //if (isExists == false) //{ pageMessageList.Add(pageMessageEntity); //} } } //foreach (PageMessageEntity msg in pageMessageList) //{ // ChatResponse chatResponse = messageRequest.Chat(token, msg.userid); // if (chatResponse.data != null) // { // msg.msg = chatResponse.data.data.First<ChatResponseDataChatEntity>().msg; // msg.ctime = chatResponse.data.data.First<ChatResponseDataChatEntity>().ctime; // } //} ViewBag.MessageList = pageMessageList; // 生成公告列表,传递到页面; List <PageMessageEntity> pageBroadcastList = new List <PageMessageEntity>(); if (currentUserRole == "90" || currentUserRole == "80") { RecvResponse recvResponseBroadcast = messageRequest.Recv(token, "10", dateParam, ""); if (recvResponseBroadcast.data != null) { foreach (RecvResponseDataMessageEntity item in recvResponseBroadcast.data.data) { PageMessageEntity pageBroadcastEntity = new PageMessageEntity(); pageBroadcastEntity.id = item.id; pageBroadcastEntity.userid = item.userid; pageBroadcastEntity.ctime = item.ctime; pageBroadcastEntity.msg = item.content; pageBroadcastEntity.url = item.url; //add by jack if (item.label == string.Empty) { pageBroadcastEntity.label = "公告标题"; } else { pageBroadcastEntity.label = item.label; } UserProfileResponse user = userRequest.profile(token, item.userid); pageBroadcastEntity.username = user.data == null ? "OOO" : user.data.username; pageBroadcastList.Add(pageBroadcastEntity); } } } else { foreach (JoinedProjectEntity projectItem in projectList) { RecvResponse recvResponseBroadcast = messageRequest.Recv(token, "10", dateParam, projectItem.id); if (recvResponseBroadcast.data != null) { foreach (RecvResponseDataMessageEntity item in recvResponseBroadcast.data.data) { PageMessageEntity pageBroadcastEntity = new PageMessageEntity(); pageBroadcastEntity.id = item.id; pageBroadcastEntity.userid = item.userid; pageBroadcastEntity.ctime = item.ctime; pageBroadcastEntity.msg = item.content; pageBroadcastEntity.url = item.url; //add by jack if (item.label == string.Empty) { pageBroadcastEntity.label = "公告标题"; } else { pageBroadcastEntity.label = item.label; } UserProfileResponse user = userRequest.profile(token, item.userid); pageBroadcastEntity.username = user.data == null ? "OOO" : user.data.username; pageBroadcastList.Add(pageBroadcastEntity); } } } } ViewBag.BroadcastList = pageBroadcastList; //取模板类型列表 TplKindListResponse tplkindList = tplRequest.TplKindList(token, "1"); ViewBag.tplkindList = tplkindList; //取第一个分类下的所有模板 TplListResponse tpllistDefault = tplRequest.TplList(token, tplkindList.data[0].id, ""); ViewBag.tpllistDefault = tpllistDefault; return(View()); }
/// <summary> /// When new version of parent was created relation is need to be refreshed /// </summary> /// <param name="currentUserData">Current version of user data</param> /// <param name="parent">Current version of parent user data</param> /// <returns>Returns true when relation between currentUserData and parentUserData needs to be refreshed</returns> private bool IsRefreshRelationWithParentNeeded(UserDataEntity currentUserData, UserDataEntity parent) { return(parent != null && currentUserData.ParentUserData != null && !currentUserData.ParentUserData.Equals(parent)); }
protected override void Seed(CampBookingDbContext context) { var camps = new List <CampDataEntity> { new CampDataEntity { Name = "Blue Camp", Capacity = 2, Description = "blue camps with lightning all around", Price = 1500, ImageURL = "camp3.jpg" }, new CampDataEntity { Name = "Hut Camp", Capacity = 8, Description = "Colorful Big Camps aith greenry all around", Price = 2000, ImageURL = "camp1.jpg" }, new CampDataEntity { Name = "Hill Side Camp", Capacity = 4, Description = "Colorfull Hill side camps with a great vie at hill peek", Price = 2500, ImageURL = "camp10.jpg" }, new CampDataEntity { Name = "Kid Camps", Capacity = 2, Description = "Funny small kids camp with toys and lot of funny things", Price = 2000, ImageURL = "camp5.png" }, new CampDataEntity { Name = "Big Yellow Camp", Capacity = 4, Description = "Spacious camp specially for couples at the place where nobody comes ", Price = 3000, ImageURL = "camp8.jpg" } }; camps.ForEach(s => context.Camps.Add(s)); context.SaveChanges(); var bookings = new List <BookingDataEntity> { new BookingDataEntity { CampId = 1, BillingAddress = "Yamuna Vihar", State = "Delhi", Country = "India", ZipCode = 110053, CellPhone = 8585910889, ReferenceId = "abcd1234", StartDate = DateTime.Parse("04-05-2020 00:00:00"), EndDate = DateTime.Parse("06-05-2020 00:00:00"), TotalAmount = 3000 }, new BookingDataEntity { CampId = 1, BillingAddress = "Shankar Nagar", State = "Delhi", Country = "India", ZipCode = 110051, CellPhone = 8585910889, ReferenceId = "efgh5678", StartDate = DateTime.Parse("01-05-2020 00:00:00"), EndDate = DateTime.Parse("03-05-2020 00:00:00"), TotalAmount = 3400 }, new BookingDataEntity { CampId = 2, BillingAddress = "Muzzafarnagar", State = "Uttar Pradesh", Country = "India", ZipCode = 210101, CellPhone = 8585910889, ReferenceId = "wxyz9100", StartDate = DateTime.Parse("15-05-2020 00:00:00"), EndDate = DateTime.Parse("18-05-2020 00:00:00"), TotalAmount = 3600 } }; bookings.ForEach(s => context.Bookings.Add(s)); context.SaveChanges(); var rating = new List <CampRatingDataEntity> { new CampRatingDataEntity { CampId = 1, Rating = 3 }, new CampRatingDataEntity { CampId = 2, Rating = 3 }, new CampRatingDataEntity { CampId = 3, Rating = 3 }, new CampRatingDataEntity { CampId = 4, Rating = 3 }, new CampRatingDataEntity { CampId = 5, Rating = 3 } }; rating.ForEach(s => context.CampRatings.Add(s)); context.SaveChanges(); var users = new UserDataEntity { Username = "******", Password = "******", IsAdmin = true }; context.Users.Add(users); context.SaveChanges(); }
/// <summary> /// The main point of this is to set the recipient Id, service URL, and conversation Id for the send parameters. /// The recipient Id and service URL is always set in the incoming user data. /// /// For the conversation Id there are three possibilities: /// Sending to all users - the conversationId is present in the incoming user data. /// Sending to a team's members - the conversation Id was already stored for that user in the User Data table. /// For this scenario, the incoming user data is stored back into the User Data table /// because it may hold more information that was not present in the User Data table originally, /// such as name /// Sending to a team's members - the conversation Id was not stored for that user in the User Data table. /// </summary> /// <param name="getSendNotificationParamsResponse">The send notification parameters to be updated.</param> /// <param name="incomingUserDataEntity">The incoming user data entity.</param> /// <param name="messageContent">The queue message content.</param> /// <param name="log">The logger.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> private async Task SetParamsForUserRecipientAsync( GetSendNotificationParamsResponse getSendNotificationParamsResponse, UserDataEntity incomingUserDataEntity, SendQueueMessageContent messageContent, ILogger log) { try { // The AAD Id and service URL will always be set in the incoming user data. getSendNotificationParamsResponse.RecipientId = incomingUserDataEntity.AadId; getSendNotificationParamsResponse.ServiceUrl = incomingUserDataEntity.ServiceUrl; /* * The rest of the logic in this method is primarily for fetching/generating the conversation Id. * */ // Case where the conversation Id is included in the incoming user data. if (!string.IsNullOrWhiteSpace(incomingUserDataEntity.ConversationId)) { getSendNotificationParamsResponse.ConversationId = incomingUserDataEntity.ConversationId; return; } // Case where the conversation Id is not included in the incoming user data (the conversation Id may or // may not be stored in the User Data table). // Fetch the data for that user from the User Data table to see if they are present. // It is possible that that user's data has not been stored in the User Data table. // If this is the case, then the conversation will need to be created for that user. var storedUserDataEntity = await this.userDataRepository.GetAsync( UserDataTableNames.UserDataPartition, incomingUserDataEntity.AadId); // These blocks are used to determine the conversation Id to be used when sending the notification. string conversationId = null; if (storedUserDataEntity != null) { /* * Case where the user's data was stored in the User Data table so their conversation Id is * known. Update the user's entry in the User Data table, though, with the incoming user data * because the incoming user data may hold more information than what is already stored for * that user, such as their name. */ // Set the conversation Id to be used when sending the notification. conversationId = storedUserDataEntity.ConversationId; // Set the conversation Id to ensure it is not removed from the User Data table on the update. incomingUserDataEntity.ConversationId = storedUserDataEntity.ConversationId; incomingUserDataEntity.PartitionKey = UserDataTableNames.UserDataPartition; incomingUserDataEntity.RowKey = incomingUserDataEntity.AadId; await this.userDataRepository.InsertOrMergeAsync(incomingUserDataEntity); } else { /* * Falling into this block means that the user data and the conversation Id for this user * has not been stored. Because of this, the conversation needs to be created and that * conversation Id needs to be stored for that user for later use. */ var createConversationResponse = await this.createUserConversationService.CreateConversationAsync( userDataEntity : incomingUserDataEntity, maxNumberOfAttempts : this.maxNumberOfAttempts, log : log); if (createConversationResponse.ResultType == CreateUserConversationResultType.Succeeded) { // Set the conversation Id to be used when sending the notification. conversationId = createConversationResponse.ConversationId; // Store the newly created conversation Id so the create conversation // request will not need to be made again for the user for future notifications. incomingUserDataEntity.ConversationId = createConversationResponse.ConversationId; incomingUserDataEntity.PartitionKey = UserDataTableNames.UserDataPartition; incomingUserDataEntity.RowKey = incomingUserDataEntity.AadId; await this.userDataRepository.InsertOrMergeAsync(incomingUserDataEntity); } else if (createConversationResponse.ResultType == CreateUserConversationResultType.Throttled) { // If the request was attempted the maximum number of allowed attempts and received // all throttling responses, then set the overall delay time for the system so all // other calls will be delayed and add the message back to the queue with a delay to be // attempted later. await this.delaySendingNotificationService.DelaySendingNotificationAsync( sendRetryDelayNumberOfSeconds : this.sendRetryDelayNumberOfSeconds, sendQueueMessageContent : messageContent, log : log); // Signal that the Azure Function should be completed to be attempted later. getSendNotificationParamsResponse.ForceCloseAzureFunction = true; return; } else if (createConversationResponse.ResultType == CreateUserConversationResultType.Failed) { // If the create conversation call failed, save the results, do not attempt the // request again, and end the function. await this.manageResultDataService.ProcessResultDataAsync( notificationId : messageContent.NotificationId, recipientId : incomingUserDataEntity.AadId, totalNumberOfSendThrottles : 0, isStatusCodeFromCreateConversation : true, statusCode : createConversationResponse.StatusCode, allSendStatusCodes : string.Empty, errorMessage : createConversationResponse.ErrorMessage, log : log); // Signal that the Azure Function should be completed. getSendNotificationParamsResponse.ForceCloseAzureFunction = true; return; } } // Set the conversation Id to be used when sending the notification. getSendNotificationParamsResponse.ConversationId = conversationId; } catch (Exception e) { var errorMessage = $"{e.GetType()}: {e.Message}"; log.LogError(e, $"ERROR: {errorMessage}"); throw; } }