public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var groupEntity = context.GetInput <EmployeeResourceGroupEntity>(); var teamId = ParseTeamIdExtension.GetTeamIdFromDeepLink(groupEntity.GroupLink); try { if (!context.IsReplaying) { log.LogInformation("About to sync pair up members."); } // sync pair up recipients to Team user pair up mapping repository table. await context.CallActivityWithRetryAsync( FunctionNames.SyncPairUpMembersActivity, FunctionSettings.DefaultRetryOptions, groupEntity); if (!context.IsReplaying) { log.LogInformation("About to get all active pair up users."); } // get active pair-up mappings to be sent to service bus. var batchesToSend = await context.CallActivityWithRetryAsync <List <TeamUserMapping> >( FunctionNames.GetActivePairUpUsersActivity, FunctionSettings.DefaultRetryOptions, groupEntity); if (batchesToSend != null && batchesToSend.Any()) { log.LogInformation($"About to process {batchesToSend.Count()} users for team {groupEntity.TeamId}."); if (!context.IsReplaying) { log.LogInformation("About to send pair up batches to queue."); } // Send pair up user batches to queue. await context.CallActivityWithRetryAsync( FunctionNames.SendPairUpMatchesActivity, FunctionSettings.DefaultRetryOptions, (teamId, batchesToSend)); } log.LogInformation($"SyncRecipientsAndSendBatchesToQueueOrchestrator successfully completed for team: {groupEntity.GroupId}!"); } catch (Exception ex) { var errorMessage = $"SyncRecipientsAndSendBatchesToQueueOrchestrator failed for team: {groupEntity.TeamId}. Exception Message: {ex.Message}"; log.LogError(ex, errorMessage); throw; } }
/// <summary> /// Fills the AuthenticationOptions's properties with the correct values from the configuration. /// </summary> /// <param name="authenticationOptions">The AuthenticationOptions whose properties will be filled.</param> /// <param name="configuration">The configuration.</param> private static void FillAuthenticationOptionsProperties(AuthenticationOptions authenticationOptions, IConfiguration configuration) { // NOTE: This AzureAd:Instance configuration setting does not need to be // overridden by any deployment specific value. It can stay the default value // that is set in the project's configuration. authenticationOptions.AzureAdInstance = configuration.GetValue <string>("AzureAd:Instance"); authenticationOptions.AzureAdTenantId = configuration.GetValue <string>("AzureAd:TenantId"); authenticationOptions.AzureAdClientId = configuration.GetValue <string>("AzureAd:ClientId"); authenticationOptions.AzureAdApplicationIdUri = configuration.GetValue <string>("AzureAd:ApplicationIdUri"); // NOTE: This AzureAd:ValidIssuers configuration setting does not need to be // overridden by any deployment specific value. It can stay the default value // that is set in the project's configuration. authenticationOptions.AzureAdValidIssuers = configuration.GetValue <string>("AzureAd:ValidIssuers"); authenticationOptions.AdminTeamId = ParseTeamIdExtension.GetTeamIdFromDeepLink(configuration.GetValue <string>("AdminTeamLink")); }
public async Task <ActionResult <EmployeeResourceGroupEntity> > UpdateEmployeeResourceGroupAsync(string id, [FromBody] ResourceGroupRequest employeeResourceGroupEntity, [FromQuery] string groupId) { try { if (employeeResourceGroupEntity == null) { this.logger.LogError("Employee resource group entity is null."); return(this.BadRequest(this.localizer.GetString("ResourceGroupNullOrEmptyErrorMessage"))); } var updateEntity = await this.employeeResourceGroupRepository.GetAsync(Constants.ResourceGroupTablePartitionKey, id); if (updateEntity == null) { this.logger.LogError("The employee resource group entity that user is trying to update does not exist."); return(this.NotFound(this.localizer.GetString("ResourceGroupNotExistsErrorMessage"))); } else { var userId = this.HttpContext.User.FindFirstValue(Constants.ClaimTypeUserId); // Validating if resource group type is 'Teams', user must be member of that group and they should belongs to same tenant. if (employeeResourceGroupEntity.GroupType == (int)ResourceGroupType.Teams) { string tenantId = ParseTeamIdExtension.GetTenantIdFromDeepLink(updateEntity.GroupLink); if (!this.options.Value.AllowedTenants.Contains(tenantId)) { this.logger.LogError($"Tenant is not valid: {tenantId}"); return(this.BadRequest(this.localizer.GetString("InvalidTenantErrorMessage"))); } string teamId = ParseTeamIdExtension.GetTeamIdFromDeepLink(updateEntity.GroupLink); var groupMembersDetail = await this.groupMembersService.GetGroupMembersAsync(groupId); var groupMemberAadIds = groupMembersDetail.Select(row => row.Id).ToList(); if (!groupMemberAadIds.Contains(userId)) { this.logger.LogError($"User {userId} is not a member of the team {teamId}"); return(this.Forbid(this.localizer.GetString("InvalidGroupMemberErrorMessage"))); } updateEntity.TeamId = teamId; } else { updateEntity.TeamId = string.Empty; } updateEntity.GroupType = employeeResourceGroupEntity.GroupType; updateEntity.GroupName = employeeResourceGroupEntity.GroupName; updateEntity.GroupDescription = employeeResourceGroupEntity.GroupDescription; updateEntity.GroupLink = employeeResourceGroupEntity.GroupLink; updateEntity.ImageLink = employeeResourceGroupEntity.ImageLink; updateEntity.Tags = employeeResourceGroupEntity.Tags; updateEntity.Location = employeeResourceGroupEntity.Location; updateEntity.IncludeInSearchResults = employeeResourceGroupEntity.IncludeInSearchResults; updateEntity.IsProfileMatchingEnabled = employeeResourceGroupEntity.IsProfileMatchingEnabled; updateEntity.MatchingFrequency = employeeResourceGroupEntity.MatchingFrequency; updateEntity.UpdatedByObjectId = userId; updateEntity.UpdatedOn = DateTime.UtcNow; await this.employeeResourceGroupRepository.InsertOrMergeAsync(updateEntity); } return(this.Ok(updateEntity)); } catch (Exception ex) { this.logger.LogError(ex, "Error while updating employee resource group entity."); throw; } }
public async Task <ActionResult <EmployeeResourceGroupEntity> > CreateEmployeeResourceGroupAsync([FromBody] EmployeeResourceGroupEntity employeeResourceGroupEntity) { try { if (employeeResourceGroupEntity == null) { this.logger.LogWarning("Employee resource group entity is null."); return(this.BadRequest(this.localizer.GetString("ResourceGroupNullOrEmptyErrorMessage"))); } // Storage call to get employee resource group entity if present already. var groupEntity = await this.employeeResourceGroupRepository.GetFilterDataByGroupLinkOrGroupNameAsync( employeeResourceGroupEntity.GroupType, employeeResourceGroupEntity.GroupLink, employeeResourceGroupEntity.GroupName); if (groupEntity != null) { this.logger.LogInformation($"Resource group entity already present with same group name {groupEntity.GroupName} or link :{groupEntity.GroupLink}."); return(this.BadRequest(this.localizer.GetString("GroupAlreadyExistsErrorMessage"))); } this.logger.LogInformation("Initiated call to store employee resource group entity."); var userId = this.HttpContext.User.FindFirstValue(Constants.ClaimTypeUserId); // Validating if resource group type is 'Teams', user must be member of that group and they should belongs to same tenant. if (employeeResourceGroupEntity.GroupType == (int)ResourceGroupType.Teams) { string tenantId = ParseTeamIdExtension.GetTenantIdFromDeepLink(employeeResourceGroupEntity.GroupLink); if (!this.options.Value.AllowedTenants.Contains(tenantId)) { this.logger.LogError($"Tenant is not valid: {tenantId}"); return(this.BadRequest(this.localizer.GetString("InvalidTenantErrorMessage"))); } string teamId = ParseTeamIdExtension.GetTeamIdFromDeepLink(employeeResourceGroupEntity.GroupLink); string groupId = ParseTeamIdExtension.GetGroupIdFromDeepLink(employeeResourceGroupEntity.GroupLink); var groupMembersDetail = await this.groupMembersService.GetGroupMembersAsync(groupId); var groupMemberAadIds = groupMembersDetail.Select(row => row.Id).ToList(); if (!groupMemberAadIds.Contains(userId)) { this.logger.LogError($"User {userId} is not a member of the team {teamId}"); return(this.Forbid(this.localizer.GetString("InvalidGroupMemberErrorMessage"))); } employeeResourceGroupEntity.TeamId = teamId; employeeResourceGroupEntity.IsProfileMatchingEnabled = true; } else { employeeResourceGroupEntity.IsProfileMatchingEnabled = false; } employeeResourceGroupEntity.Group = Constants.ResourceGroupTablePartitionKey; employeeResourceGroupEntity.GroupId = this.tableRowKeyGenerator.CreateNewKeyOrderingOldestToMostRecent(); employeeResourceGroupEntity.ApprovalStatus = (int)ApprovalStatus.PendingForApproval; employeeResourceGroupEntity.CreatedOn = DateTime.UtcNow; employeeResourceGroupEntity.CreatedByObjectId = userId; employeeResourceGroupEntity.MatchingFrequency = (int)MatchingFrequency.Monthly; await this.employeeResourceGroupRepository.CreateOrUpdateAsync(employeeResourceGroupEntity); this.logger.LogInformation("Resource group - HTTP post call succeeded"); return(this.Created(this.Request.GetDisplayUrl(), employeeResourceGroupEntity)); } catch (Exception ex) { this.logger.LogError(ex, "Error while creating new employee resource group entity."); throw; } }
/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">IServiceCollection instance.</param> public void ConfigureServices(IServiceCollection services) { // Add all options set from configuration values. services.AddOptions <AuthenticationOptions>() .Configure <IConfiguration>((authenticationOptions, configuration) => { Startup.FillAuthenticationOptionsProperties(authenticationOptions, configuration); }); services.AddOptions <BotOptions>() .Configure <IConfiguration>((botOptions, configuration) => { botOptions.MicrosoftAppId = configuration.GetValue <string>("MicrosoftAppId"); botOptions.MicrosoftAppPassword = configuration.GetValue <string>("MicrosoftAppPassword"); botOptions.AppBaseUri = configuration.GetValue <string>("AppBaseUri"); botOptions.AdminTeamId = ParseTeamIdExtension.GetTeamIdFromDeepLink(configuration.GetValue <string>("AdminTeamLink")); botOptions.ManifestId = configuration.GetValue <string>("ManifestId"); }); services.AddOptions <BotFilterMiddlewareOptions>() .Configure <IConfiguration>((botFilterMiddlewareOptions, configuration) => { botFilterMiddlewareOptions.DisableTenantFilter = configuration.GetValue <bool>("DisableTenantFilter", false); botFilterMiddlewareOptions.AllowedTenants = configuration.GetValue <string>("AllowedTenants")?.ToString().Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) ?.Select(p => p.Trim()).ToArray(); }); services.AddOptions <RepositoryOptions>() .Configure <IConfiguration>((repositoryOptions, configuration) => { repositoryOptions.StorageAccountConnectionString = configuration.GetValue <string>("StorageAccountConnectionString"); // Setting this to true because the main application should ensure that all // tables exist. repositoryOptions.EnsureTableExists = true; }); services.AddOptions <MessageQueueOptions>() .Configure <IConfiguration>((messageQueueOptions, configuration) => { messageQueueOptions.ServiceBusConnection = configuration.GetValue <string>("ServiceBusConnection"); }); services.AddOptions <DataQueueMessageOptions>() .Configure <IConfiguration>((dataQueueMessageOptions, configuration) => { dataQueueMessageOptions.ForceCompleteMessageDelayInSeconds = configuration.GetValue <double>("ForceCompleteMessageDelayInSeconds", 86400); }); services.AddOptions <UserAppOptions>() .Configure <IConfiguration>((options, configuration) => { options.ProactivelyInstallUserApp = configuration.GetValue <bool>("ProactivelyInstallUserApp", true); options.UserAppExternalId = configuration.GetValue <string>("UserAppExternalId", "148a66bb-e83d-425a-927d-09f4299a9274"); }); services.AddOptions <QnAMakerSettings>() .Configure <IConfiguration>((options, configuration) => { options.ScoreThreshold = configuration.GetValue <double>("ScoreThreshold", 0.5); }); services.AddOptions(); // Add localization services. services.AddLocalizationSettings(this.Configuration); // Add authentication services. AuthenticationOptions authenticationOptionsParameter = new AuthenticationOptions(); Startup.FillAuthenticationOptionsProperties(authenticationOptionsParameter, this.Configuration); services.AddAuthentication(this.Configuration, authenticationOptionsParameter); services.AddControllersWithViews(); // Setup SPA static files. // In production, the React files will be served from this directory. services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/build"; }); // Add blob client. services.AddSingleton(sp => new BlobContainerClient( sp.GetService <IConfiguration>().GetValue <string>("StorageAccountConnectionString"), Common.Constants.BlobContainerName)); // The bot needs an HttpClient to download and upload files. services.AddHttpClient(); services.AddSingleton <BotFrameworkHttpAdapter>(); // Add bot services. services.AddSingleton <ICredentialProvider, ConfigurationCredentialProvider>(); services.AddTransient <DIConnectBotFilterMiddleware>(); services.AddSingleton <DIConnectBotAdapter>(); services.AddTransient <AdminTeamNotifier>(); services.AddTransient <TeamsDataCapture>(); services.AddTransient <TeamsFileUpload>(); services.AddTransient <KnowledgeBaseResponse>(); services.AddTransient <NotificationCardHelper>(); services.AddTransient <IBot, DIConnectBot>(); // Add repositories. services.AddSingleton <TeamDataRepository>(); services.AddSingleton <EmployeeResourceGroupRepository>(); services.AddSingleton <UserDataRepository>(); services.AddSingleton <SentNotificationDataRepository>(); services.AddSingleton <NotificationDataRepository>(); services.AddSingleton <ExportDataRepository>(); services.AddSingleton <AppConfigRepository>(); services.AddSingleton <FeedbackDataRepository>(); services.AddSingleton <TeamUserPairUpMappingRepository>(); // Add service bus message queues. services.AddSingleton <PrepareToSendQueue>(); services.AddSingleton <DataQueue>(); services.AddSingleton <ExportQueue>(); // Add draft notification preview services. services.AddTransient <DraftNotificationPreviewService>(); // Add Microsoft graph services. services.AddScoped <IAuthenticationProvider, GraphTokenProvider>(); services.AddScoped <IGraphServiceClient, GraphServiceClient>(); services.AddScoped <Beta.IGraphServiceClient, Beta.GraphServiceClient>(); services.AddScoped <IGraphServiceFactory, GraphServiceFactory>(); services.AddScoped <IGroupMembersService>(sp => sp.GetRequiredService <IGraphServiceFactory>().GetGroupMembersService()); services.AddScoped <IGroupsService>(sp => sp.GetRequiredService <IGraphServiceFactory>().GetGroupsService()); services.AddScoped <IAppCatalogService>(sp => sp.GetRequiredService <IGraphServiceFactory>().GetAppCatalogService()); IQnAMakerClient qnaMakerClient = new QnAMakerClient(new ApiKeyServiceClientCredentials(this.Configuration["QnAMakerSubscriptionKey"])) { Endpoint = this.Configuration["QnAMakerApiEndpointUrl"] }; string endpointKey = Task.Run(() => qnaMakerClient.EndpointKeys.GetKeysAsync()).Result.PrimaryEndpointKey; services.AddSingleton <IQnAService>((provider) => new QnAService( provider.GetRequiredService <AppConfigRepository>(), provider.GetRequiredService <IOptionsMonitor <QnAMakerSettings> >(), new QnAMakerRuntimeClient(new EndpointKeyServiceClientCredentials(endpointKey)) { RuntimeEndpoint = this.Configuration["QnAMakerHostUrl"] })); services.AddScoped <IGroupMembersService>(sp => sp.GetRequiredService <IGraphServiceFactory>().GetGroupMembersService()); // Add Application Insights telemetry. services.AddApplicationInsightsTelemetry(); // Add miscellaneous dependencies. services.AddTransient <TableRowKeyGenerator>(); services.AddTransient <AdaptiveCardCreator>(); services.AddSingleton <IAppSettingsService, AppSettingsService>(); services.AddSingleton <ITeamMembersService, TeamMembersService>(); services.AddSingleton <IMemberValidationHelper, MemberValidationHelper>(); // Add helper class. services.AddSingleton <UserTeamMappingsHelper>(); services.AddSingleton <CardHelper>(); services.Configure <MvcOptions>(options => { options.EnableEndpointRouting = false; }); }