/// <summary> /// Gets a complete list of customers associated with the partner. /// </summary> /// <param name="client">Provides the ability to interact with Partner Center.</param> /// <param name="environment">The environment that owns the customers be requesteed.</param> /// <returns>A list of customers associated with the partner.</returns> private static async Task <List <CustomerDetail> > GetCustomersAsync( IPartnerServiceClient client, EnvironmentDetail environment) { List <CustomerDetail> customers; SeekBasedResourceCollection <Customer> seekCustomers; try { // Request a list of customers from Partner Center. seekCustomers = await client.Customers.GetAsync().ConfigureAwait(false); customers = new List <CustomerDetail>( seekCustomers.Items.Select(c => ResourceConverter.Convert <Customer, CustomerDetail>(c))); while (seekCustomers.Links.Next != null) { // Request the next page of customers from Partner Center. seekCustomers = await client.Customers.GetAsync(seekCustomers.Links.Next).ConfigureAwait(false); customers.AddRange(seekCustomers.Items.Select(c => ResourceConverter.Convert <Customer, CustomerDetail>(c))); } customers.ForEach(c => c.EnvironmentId = environment.Id); return(customers); } finally { seekCustomers = null; } }
private static async Task <List <AuditRecord> > GetAuditRecordsAsyc( IPartnerServiceClient client, DateTime startDate, DateTime endDate) { List <AuditRecord> auditRecords; SeekBasedResourceCollection <AuditRecord> seekAuditRecords; try { auditRecords = new List <AuditRecord>(); foreach (DateTime date in ChunkDate(startDate, endDate, 30)) { // Request the audit records for the previous day from Partner Center. seekAuditRecords = await client.AuditRecords.QueryAsync(date).ConfigureAwait(false); auditRecords.AddRange(seekAuditRecords.Items); while (seekAuditRecords.Links.Next != null) { // Request the next page of audit records from Partner Center. seekAuditRecords = await client.AuditRecords.QueryAsync(seekAuditRecords.Links.Next).ConfigureAwait(false); auditRecords.AddRange(seekAuditRecords.Items); } } return(auditRecords); } finally { seekAuditRecords = null; } }
/// <summary> /// Gets a complete list of customers associated with the partner. /// </summary> /// <param name="client">Provides the ability to interact with Partner Center.</param> /// <param name="environment">The environment that owns the customers be requesteed.</param> /// <returns>A list of customers associated with the partner.</returns> private static async Task <List <CustomerDetail> > GetCustomersAsync( IPartnerServiceClient client, EnvironmentDetail environment) { Customer customer; Customer justOne; List <CustomerDetail> customers; SeekBasedResourceCollection <Customer> seekCustomers; try { // Request a list of customers from Partner Center. //seekCustomers = await client.Customers.GetAsync().ConfigureAwait(false); // //customers = new List<CustomerDetail>( // seekCustomers.Items.Select(c => ResourceConverter.Convert<Customer, CustomerDetail>(c))); // //while (seekCustomers.Links.Next == null) //{ // Request the next page of customers from Partner Center. // seekCustomers = await client.Customers.GetAsync(seekCustomers.Links.Next).ConfigureAwait(false); // customers.AddRange(seekCustomers.Items.Select(c => ResourceConverter.Convert<Customer, CustomerDetail>(c))); //} //customers.ForEach(c => c.EnvironmentId = environment.Id); customers = new List <CustomerDetail>(); justOne = await client.Customers[environment.Id].GetAsync().ConfigureAwait(false); customers.Add(ResourceConverter.Convert <Customer, CustomerDetail>(justOne)); foreach (CustomerDetail c in customers) { try { customer = await client.Customers[c.Id].GetAsync().ConfigureAwait(false); c.BillingProfile = customer.BillingProfile; c.EnvironmentId = environment.Id; if (c.RemovedFromPartnerCenter == true) { c.LastProcessed = null; } c.RemovedFromPartnerCenter = false; } catch (ServiceClientException ex) { c.ProcessException = ex; } } return(customers); } finally { seekCustomers = null; } }
/// <summary> /// Gets a complete list of customers associated with the partner. /// </summary> /// <param name="client">Provides the ability to interact with Partner Center.</param> /// <returns>A list of customers associated with the partner.</returns> private static async Task <List <CustomerDetail> > GetCustomersAsync(IPartnerServiceClient client) { Customer customer; List <CustomerDetail> customers; SeekBasedResourceCollection <Customer> seekCustomers; try { // Request a list of customers from Partner Center. seekCustomers = await client.Customers.GetAsync().ConfigureAwait(false); customers = new List <CustomerDetail>( seekCustomers.Items.Select(c => ResourceConverter.Convert <Customer, CustomerDetail>(c))); while (seekCustomers.Links.Next != null) { // Request the next page of customers from Partner Center. seekCustomers = await client.Customers.GetAsync(seekCustomers.Links.Next).ConfigureAwait(false); customers.AddRange(seekCustomers.Items.Select(c => ResourceConverter.Convert <Customer, CustomerDetail>(c))); } foreach (CustomerDetail c in customers) { try { customer = await client.Customers[c.Id].GetAsync().ConfigureAwait(false); c.BillingProfile = customer.BillingProfile; } catch (ServiceClientException ex) { c.ProcessException = ex; } } return(customers); } finally { seekCustomers = null; } }
/// <summary> /// Gets a list of subscriptions for the specified customer. /// </summary> /// <param name="client">Provides the ability to interact with Partner Center.</param> /// <param name="customerId">Identifier for the customer.</param> /// <returns>A list of subscriptions for the specified customer.</returns> private static async Task <List <SubscriptionDetail> > GetSubscriptionsAsync(IPartnerServiceClient client, string customerId) { List <SubscriptionDetail> subscriptions; SeekBasedResourceCollection <Subscription> seekSubscriptions; try { // Request a list of subscriptions from the Partner Center API. seekSubscriptions = await client.Customers.ById(customerId).Subscriptions.GetAsync().ConfigureAwait(false); subscriptions = new List <SubscriptionDetail>( seekSubscriptions.Items .Select(s => ResourceConverter.Convert <Subscription, SubscriptionDetail>( s, new Dictionary <string, string> { { "TenantId", customerId } }))); while (seekSubscriptions.Links.Next != null) { // Request the next page of subscriptions from the Partner Center API. seekSubscriptions = await client.Customers .ById(customerId) .Subscriptions .GetAsync(seekSubscriptions.Links.Next).ConfigureAwait(false); subscriptions.AddRange(seekSubscriptions.Items .Select(s => ResourceConverter.Convert <Subscription, SubscriptionDetail>( s, new Dictionary <string, string> { { "TenantId", customerId } }))); } return(subscriptions); } finally { seekSubscriptions = null; } }
/// <summary> /// Converts the audit records to a list of customer details. /// </summary> /// <param name="client">Provides the ability to interface with Partner Center.</param> /// <param name="records">A list of audit records from Partner Center.</param> /// <param name="details">A list of existing customer details.</param> /// <param name="additionalInfo">Additional information to be added to the converted customer details.</param> /// <returns> /// A list of customer details that incorporates the changes reflected by the audit records. /// </returns> public async static Task <List <CustomerDetail> > ConvertAsync( IPartnerServiceClient client, List <AuditRecord> records, List <CustomerDetail> details, Dictionary <string, string> additionalInfo) { Customer resource; CustomerDetail control; IEnumerable <AuditRecord> filtered; List <CustomerDetail> results; try { // Filter the audit records, so that only records for successful operations are considered. filtered = records .Where(r => r.OperationStatus == OperationStatus.Succeeded && !string.IsNullOrEmpty(r.CustomerId)) .OrderBy(r => r.OperationDate); results = new List <CustomerDetail>(details); foreach (AuditRecord record in filtered) { control = results.SingleOrDefault(r => r.Id.Equals(record.CustomerId, StringComparison.InvariantCultureIgnoreCase)); /* * If the control variable is null and the operation type value is not equal * to AddCustomer, then that means we have a customer that accepted the reseller * relationship. Currently there is not an audit record for when a customer * accepts the reseller relationship. */ if (control == null && record.OperationType != OperationType.AddCustomer) { resource = await client.Customers[record.CustomerId].GetAsync().ConfigureAwait(false); results.Add( ResourceConverter.Convert <Customer, CustomerDetail>( resource, additionalInfo)); } else if (control != null) { control.RemovedFromPartnerCenter = false; } if (record.OperationType == OperationType.AddCustomer) { resource = Convert <Customer>(record); results.Add( ResourceConverter.Convert <Customer, CustomerDetail>( resource, additionalInfo)); } else if (record.OperationType == OperationType.RemovePartnerCustomerRelationship) { control.RemovedFromPartnerCenter = true; } else if (record.OperationType == OperationType.UpdateCustomerBillingProfile) { control.BillingProfile = Convert <CustomerBillingProfile>(record); } } return(results); } finally { control = null; filtered = null; resource = null; } }
private static async Task <List <SubscriptionDetail> > ConvertAsync( IPartnerServiceClient partner, CustomerDetail customer, Order order) { DateTime effectiveStartDate; DateTimeOffset creationDate; List <SubscriptionDetail> details; Offer offer; try { if (order.BillingCycle == BillingCycleType.OneTime) { return(null); } details = new List <SubscriptionDetail>(); foreach (OrderLineItem lineItem in order.LineItems) { creationDate = order.CreationDate.Value; effectiveStartDate = new DateTime( creationDate.UtcDateTime.Year, creationDate.UtcDateTime.Month, creationDate.UtcDateTime.Day); offer = await partner.Offers .ByCountry(customer.BillingProfile.DefaultAddress.Country).ById(lineItem.OfferId) .GetAsync().ConfigureAwait(false); details.Add(new SubscriptionDetail { AutoRenewEnabled = offer.IsAutoRenewable, BillingCycle = order.BillingCycle, BillingType = offer.Billing, CommitmentEndDate = (offer.Billing == BillingType.License) ? effectiveStartDate.AddYears(1) : DateTime.Parse("9999-12-14T00:00:00Z", CultureInfo.CurrentCulture), CreationDate = creationDate.UtcDateTime, EffectiveStartDate = effectiveStartDate, FriendlyName = lineItem.FriendlyName, Id = lineItem.SubscriptionId, OfferId = lineItem.OfferId, OfferName = offer.Name, ParentSubscriptionId = lineItem.ParentSubscriptionId, PartnerId = lineItem.PartnerIdOnRecord, Quantity = lineItem.Quantity, Status = SubscriptionStatus.Active, SuspensionReasons = null, TenantId = customer.Id, UnitType = offer.UnitType }); } return(details); } finally { offer = null; } }
/// <summary> /// Converts the audit records to a list of subscription details. /// </summary> /// <param name="client">Provides the ability to interface with Partner Center.</param> /// <param name="records">A list of audit records from Partner Center.</param> /// <param name="details">A list of existing subscription details.</param> /// <param name="customer">The details for the customer that owns the subscription.</param> /// <returns> /// A list of subscription details that incorporates the changes reflected by the audit records. /// </returns> public static async Task <List <SubscriptionDetail> > ConvertAsync( IPartnerServiceClient client, IEnumerable <AuditRecord> auditRecords, List <SubscriptionDetail> details, CustomerDetail customer) { IEnumerable <AuditRecord> filteredRecords; List <SubscriptionDetail> fromOrders; List <SubscriptionDetail> results; SubscriptionDetail control; Subscription resource; try { // Extract a list of audit records that are scope to the defined resource type and were successful. filteredRecords = auditRecords .Where(r => (r.ResourceType == ResourceType.Subscription || r.ResourceType == ResourceType.Order) && r.OperationStatus == OperationStatus.Succeeded) .OrderBy(r => r.OperationDate); results = new List <SubscriptionDetail>(details); foreach (AuditRecord record in filteredRecords) { if (record.ResourceType == ResourceType.Order) { fromOrders = await ConvertAsync( client, customer, Convert <Order>(record)).ConfigureAwait(false); if (fromOrders != null) { results.AddRange(fromOrders); } } else if (record.ResourceType == ResourceType.Subscription) { resource = Convert <Subscription>(record); control = results.SingleOrDefault(r => r.Id.Equals(resource.Id, StringComparison.InvariantCultureIgnoreCase)); if (control != null) { results.Remove(control); } results.Add( ResourceConverter.Convert <Subscription, SubscriptionDetail>( resource, new Dictionary <string, string> { { "TenantId", customer.Id } })); } } return(results); } finally { control = null; filteredRecords = null; fromOrders = null; resource = null; } }
/// <summary> /// Initializes a new instance of the <see cref="ResourceConverter{TInput, TOutput}" /> class. /// </summary> /// <param name="client">Provides the ability to interact with Partner Center.</param> public ResourceConverter(IPartnerServiceClient client) { this.client = client; }
public static async Task ProcessCustomerAsync( [QueueTrigger(OperationConstants.CustomersQueueName, Connection = "StorageConnectionString")] ProcessCustomerDetail customerDetail, [DataRepository(DataType = typeof(AuditRecord))] DocumentRepository <AuditRecord> auditRecordRepository, [DataRepository(DataType = typeof(CustomerDetail))] DocumentRepository <CustomerDetail> customerRepository, [DataRepository(DataType = typeof(SubscriptionDetail))] DocumentRepository <SubscriptionDetail> subscriptionRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", Resource = "https://graph.windows.net")] IPartnerServiceClient partner, [Queue(OperationConstants.SecurityQueueName, Connection = "StorageConnectionString")] ICollector <SecurityDetail> securityQueue, [Queue(OperationConstants.UtilizationQueueName, Connection = "StorageConnectionString")] ICollector <ProcessSubscriptionDetail> utilizationQueue, ILogger log) { IEnumerable <AuditRecord> auditRecords; List <SubscriptionDetail> subscriptions; int period; try { log.LogInformation($"Attempting to process information for {customerDetail.Customer.Id}."); if (customerDetail.Customer.RemovedFromPartnerCenter) { // The customer no longer has relationship with the partner. So, it should not be processed. return; } // Configure the value indicating the number of days of score results to retrieve starting from current date. period = (customerDetail.Customer.LastProcessed == null) ? 30 : (DateTimeOffset.UtcNow - customerDetail.Customer.LastProcessed).Value.Days; // Ensure that the period is at least 1 or greater. This ensure the request to retrieve data is succesfully. if (period < 1) { period = 1; } if (period >= 30) { period = 30; try { customerDetail.Customer.ProcessException = null; subscriptions = await GetSubscriptionsAsync( partner, customerDetail.Customer.Id).ConfigureAwait(false); } catch (ServiceClientException ex) { customerDetail.Customer.ProcessException = ex; subscriptions = null; log.LogWarning($"Encountered an exception when processing {customerDetail.Customer.Id}. Check the customer record for more information."); } } else { // Obtain a list of audit records for the specified customer that happened since the customer was last processed. auditRecords = await auditRecordRepository.GetAsync( r => r.CustomerId == customerDetail.Customer.Id && r.OperationDate >= customerDetail.Customer.LastProcessed, customerDetail.Customer.EnvironmentId).ConfigureAwait(false); subscriptions = await subscriptionRepository .GetAsync(s => s.TenantId == customerDetail.Customer.Id, customerDetail.Customer.Id) .ConfigureAwait(false); // Since the period is less than 30 we can utilize the audit logs to reconstruct any subscriptions that were created. subscriptions = await AuditRecordConverter.ConvertAsync( partner, auditRecords, subscriptions, customerDetail.Customer).ConfigureAwait(false); } if (subscriptions?.Count > 0) { await subscriptionRepository.AddOrUpdateAsync( subscriptions, customerDetail.Customer.Id).ConfigureAwait(false); } if (customerDetail.Customer.ProcessException == null) { securityQueue.Add(new SecurityDetail { AppEndpoint = customerDetail.AppEndpoint, Customer = customerDetail.Customer, Period = period.ToString(CultureInfo.InvariantCulture) }); if (customerDetail.ProcessAzureUsage) { foreach (SubscriptionDetail subscription in subscriptions.Where(s => s.BillingType == BillingType.Usage)) { utilizationQueue.Add(new ProcessSubscriptionDetail { PartnerCenterEndpoint = customerDetail.PartnerCenterEndpoint, Subscription = subscription }); } } customerDetail.Customer.LastProcessed = DateTimeOffset.UtcNow; } await customerRepository.AddOrUpdateAsync(customerDetail.Customer).ConfigureAwait(false); log.LogInformation($"Successfully processed customer {customerDetail.Customer.Id}. Exception(s): {(customerDetail.Customer.ProcessException != null ? "yes" : "no")}"); } finally { auditRecords = null; subscriptions = null; } }
public static async Task ProcessUsageAsync( [QueueTrigger(OperationConstants.UtilizationQueueName, Connection = "StorageConnectionString")] ProcessSubscriptionDetail subscriptionDetail, [DataRepository( DataType = typeof(UtilizationDetail))] DocumentRepository <UtilizationDetail> repository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", Resource = "https://graph.windows.net")] IPartnerServiceClient client, ILogger log) { // Subscriptions with a billing type of usage are the only ones that have utilization records. if (subscriptionDetail.Subscription.BillingType != BillingType.Usage) { return; } log.LogInformation($"Requesting utilization records for {subscriptionDetail.Subscription.Id}"); List <UtilizationDetail> records; ResourceCollection <AzureUtilizationRecord> utilizationRecords; try { utilizationRecords = await client .Customers[subscriptionDetail.Subscription.TenantId] .Subscriptions[subscriptionDetail.Subscription.Id] .Utilization .Azure .QueryAsync(DateTimeOffset.UtcNow.AddDays(-1), DateTimeOffset.UtcNow).ConfigureAwait(false); records = new List <UtilizationDetail>(); if (utilizationRecords.TotalCount > 0) { records.AddRange(utilizationRecords.Items .Select(r => ResourceConverter.Convert <AzureUtilizationRecord, UtilizationDetail>( r, new Dictionary <string, string> { { "Id", $"{r.Resource.Id}--{r.UsageStartTime}" }, { "SubscriptionId", subscriptionDetail.Subscription.Id }, { "TenantId", subscriptionDetail.Subscription.TenantId } }))); while (utilizationRecords.Links.Next != null) { utilizationRecords = await client .Customers[subscriptionDetail.Subscription.TenantId] .Subscriptions[subscriptionDetail.Subscription.Id] .Utilization .Azure .QueryAsync(utilizationRecords.Links.Next).ConfigureAwait(false); records.AddRange(utilizationRecords.Items .Select(r => ResourceConverter.Convert <AzureUtilizationRecord, UtilizationDetail>( r, new Dictionary <string, string> { { "Id", $"{r.Resource.Id}--{r.UsageStartTime}" }, { "SubscriptionId", subscriptionDetail.Subscription.Id }, { "TenantId", subscriptionDetail.Subscription.TenantId } }))); } } if (records.Count > 0) { log.LogInformation($"Writing {records.Count} utilization records to the repository."); await repository.AddOrUpdateAsync( records, subscriptionDetail.Subscription.Id).ConfigureAwait(false); } } finally { records = null; utilizationRecords = null; } }
public static async Task ProcessPartnerAsync( [QueueTrigger(OperationConstants.PartnersQueueName, Connection = "StorageConnectionString")] EnvironmentDetail environment, [DataRepository(DataType = typeof(AuditRecord))] DocumentRepository <AuditRecord> auditRecordRepository, [DataRepository(DataType = typeof(CustomerDetail))] DocumentRepository <CustomerDetail> customerRepository, [DataRepository( DataType = typeof(EnvironmentDetail))] DocumentRepository <EnvironmentDetail> environmentRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", Resource = "https://graph.windows.net")] IPartnerServiceClient client, [Queue(OperationConstants.CustomersQueueName, Connection = "StorageConnectionString")] ICollector <ProcessCustomerDetail> customerQueue, ILogger log) { List <AuditRecord> auditRecords; List <CustomerDetail> customers; int days; try { log.LogInformation($"Starting to process the {environment.FriendlyName} CSP environment."); // Calculate the number of days that have gone by, since the last successful synchronization. days = (environment.LastProcessed == null) ? 30 : (DateTimeOffset.UtcNow - environment.LastProcessed).Days; if (days >= 90) { // Only audit records for the past 90 days are available from Partner Center. days = 89; } else if (days <= 0) { // Ensure that in all circumstances at least one day of records will be returned. days = 1; } if (days >= 30) { customers = await GetCustomersAsync(client, environment).ConfigureAwait(false); } else { auditRecords = await GetAuditRecordsAsyc( client, DateTime.UtcNow.AddDays(-days), DateTime.UtcNow).ConfigureAwait(false); if (auditRecords.Count > 0) { log.LogInformation($"Importing {auditRecords.Count} audit records available between now and the previous day."); // Add, or update, each audit record to the database. await auditRecordRepository.AddOrUpdateAsync( auditRecords, environment.Id).ConfigureAwait(false); } customers = await customerRepository.GetAsync().ConfigureAwait(false); customers = await AuditRecordConverter.ConvertAsync( client, auditRecords, customers, new Dictionary <string, string> { { "EnvironmentId", environment.Id } }, log).ConfigureAwait(false); } // Add, or update, each customer to the database. await customerRepository.AddOrUpdateAsync(customers).ConfigureAwait(false); foreach (CustomerDetail customer in customers) { // Write the customer to the customers queue to start processing the customer. customerQueue.Add(new ProcessCustomerDetail { AppEndpoint = environment.AppEndpoint, Customer = customer, PartnerCenterEndpoint = environment.PartnerCenterEndpoint, ProcessAzureUsage = environment.ProcessAzureUsage }); } environment.LastProcessed = DateTimeOffset.UtcNow; await environmentRepository.AddOrUpdateAsync(environment).ConfigureAwait(false); log.LogInformation($"Successfully process the {environment.FriendlyName} CSP environment."); } finally { auditRecords = null; customers = null; } }
public static async Task ProcessCustomerAsync( [QueueTrigger(OperationConstants.CustomersQueueName, Connection = "StorageConnectionString")] XEvent data, [DataRepository( CosmosDbEndpoint = "CosmosDbEndpoint", DataType = typeof(CustomerDetail), KeyVaultEndpoint = "KeyVaultEndpoint")] IDocumentRepository <CustomerDetail> customerRepository, [DataRepository( CosmosDbEndpoint = "CosmosDbEndpoint", DataType = typeof(SubscriptionDetail), KeyVaultEndpoint = "KeyVaultEndpoint")] IDocumentRepository <SubscriptionDetail> subscriptionRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", KeyVaultEndpoint = "KeyVaultEndpoint", Resource = "https://graph.windows.net")] IPartnerServiceClient partner, [StorageService( ConnectionStringName = "StorageConnectionString", KeyVaultEndpoint = "KeyVaultEndpoint")] IStorageService storage, TraceWriter log) { List <SubscriptionDetail> subscriptions; try { log.Info($"Processing data for {data.Customer.Id}"); if (data.Customer.LastProcessed == null || (DateTimeOffset.UtcNow - data.Customer.LastProcessed).Value.TotalDays >= 30) { subscriptions = await GetSubscriptionsAsync(partner, data.Customer.Id).ConfigureAwait(false); } else { subscriptions = await BuildUsingAuditRecordsAsync( data.AuditRecords, subscriptionRepository, partner, data.Customer).ConfigureAwait(false); } if (subscriptions.Count > 0) { await subscriptionRepository.AddOrUpdateAsync(subscriptions).ConfigureAwait(false); } data.Customer.LastProcessed = DateTimeOffset.UtcNow; data.Customer.ProcessException = null; await customerRepository.AddOrUpdateAsync(data.Customer).ConfigureAwait(false); await storage.WriteToQueueAsync( OperationConstants.SecurityQueueName, new SecurityDetails { AppEndpoint = data.AppEndpoint, Customer = data.Customer }).ConfigureAwait(false); log.Info($"Successfully process data for {data.Customer.Id}"); } finally { subscriptions = null; } }
public static async Task ProcessPartnerAsync( [QueueTrigger(OperationConstants.PartnersQueueName, Connection = "StorageConnectionString")] EnvironmentDetail environment, [DataRepository( CosmosDbEndpoint = "CosmosDbEndpoint", DataType = typeof(AuditRecord), KeyVaultEndpoint = "KeyVaultEndpoint")] IDocumentRepository <AuditRecord> auditRecordRepository, [DataRepository( CosmosDbEndpoint = "CosmosDbEndpoint", DataType = typeof(CustomerDetail), KeyVaultEndpoint = "KeyVaultEndpoint")] IDocumentRepository <CustomerDetail> customerRepository, [DataRepository( CosmosDbEndpoint = "CosmosDbEndpoint", DataType = typeof(EnvironmentDetail), KeyVaultEndpoint = "KeyVaultEndpoint")] IDocumentRepository <EnvironmentDetail> environmentRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", KeyVaultEndpoint = "KeyVaultEndpoint", Resource = "https://graph.windows.net")] IPartnerServiceClient partner, [StorageService( ConnectionStringName = "StorageConnectionString", KeyVaultEndpoint = "KeyVaultEndpoint")] IStorageService storage, TraceWriter log) { List <AuditRecord> auditRecords; List <CustomerDetail> customers; SeekBasedResourceCollection <AuditRecord> seekAuditRecords; try { log.Info($"Starting to process the {environment.FriendlyName} CSP environment."); // Request the audit records for the previous day from the Partner Center API. seekAuditRecords = await partner.AuditRecords.QueryAsync(DateTime.Now.AddDays(-1)).ConfigureAwait(false); auditRecords = new List <AuditRecord>(seekAuditRecords.Items); while (seekAuditRecords.Links.Next != null) { // Request the next page of audit records from the Partner Center API. seekAuditRecords = await partner.AuditRecords.QueryAsync(seekAuditRecords.Links.Next).ConfigureAwait(false); auditRecords.AddRange(seekAuditRecords.Items); } if (auditRecords.Count > 0) { // Add, or update, each audit record to the database. await auditRecordRepository.AddOrUpdateAsync(auditRecords).ConfigureAwait(false); } if ((DateTimeOffset.UtcNow - environment?.LastProcessed).Value.TotalDays >= 30) { customers = await GetCustomersAsync(partner).ConfigureAwait(false); } else { customers = await BuildUsingAuditRecordsAsync( auditRecords, customerRepository).ConfigureAwait(false); } // Add, or update, each customer to the database. await customerRepository.AddOrUpdateAsync(customers).ConfigureAwait(false); foreach (CustomerDetail customer in customers) { // Write the customer to the customers queue to start processing the customer. await storage.WriteToQueueAsync( OperationConstants.CustomersQueueName, new XEvent { AppEndpoint = environment.AppEndpoint, AuditRecords = auditRecords .Where(r => r.CustomerId.Equals(customer.Id, StringComparison.InvariantCultureIgnoreCase)) .ToList(), Customer = customer, PartnerCenterEndpoint = environment.PartnerCenterEndpoint }).ConfigureAwait(false); } environment.LastProcessed = DateTimeOffset.UtcNow; await environmentRepository.AddOrUpdateAsync(environment).ConfigureAwait(false); log.Info($"Successfully process the {environment.FriendlyName} CSP environment."); } finally { auditRecords = null; customers = null; seekAuditRecords = null; } }