private static async Task GenerateFECourseReport(
            IConfiguration configuration,
            ICourseCollectionService courseCollectionService,
            IMigrationReportCollectionService migrationReportCollectionService,
            Provider provider,
            IReadOnlyList <RecordStatus> migratedStatusList,
            IDocumentClient cosmosClient)
        {
            var ukprn             = int.Parse(provider.UnitedKingdomProviderReferenceNumber);
            var courseReportEntry = await migrationReportCollectionService.GetReportForCoursesByUkprn(ukprn) ??
                                    new MigrationReportEntry();

            var courses = await courseCollectionService.GetAllCoursesByUkprnAsync(ukprn);

            courseReportEntry.CreatedOn            = DateTime.Now;
            courseReportEntry.CreatedBy            = AppName;
            courseReportEntry.id                   = provider.UnitedKingdomProviderReferenceNumber;
            courseReportEntry.MigrationDate        = provider.DateUpdated;
            courseReportEntry.ProviderType         = (int)provider.ProviderType;
            courseReportEntry.ProviderName         = provider.ProviderName;
            courseReportEntry.FailedMigrationCount = 0;
            courseReportEntry.MigrationRate        = FeCourseMigrationRate(courses, migratedStatusList);

            courseReportEntry.MigrationPendingCount = courses
                                                      .SelectMany(x => x.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.MigrationPending)).Count();

            courseReportEntry.MigrationReadyToGoLive = courses
                                                       .SelectMany(x => x.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.MigrationReadyToGoLive))
                                                       .Count();

            courseReportEntry.BulkUploadPendingcount = courses
                                                       .SelectMany(x => x.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.BulkUloadPending)).Count();

            courseReportEntry.BulkUploadReadyToGoLiveCount = courses
                                                             .SelectMany(x => x.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.BulkUploadReadyToGoLive))
                                                             .Count();

            courseReportEntry.LiveCount =
                courses.SelectMany(c => c.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.Live))
                .Count();

            courseReportEntry.PendingCount =
                courses.SelectMany(c => c.CourseRuns.Where(cr => cr.RecordStatus == RecordStatus.Pending))
                .Count();

            courseReportEntry.MigratedCount = courses
                                              .SelectMany(c => c.CourseRuns.Where(cr => migratedStatusList.Contains(cr.RecordStatus)))
                                              .Count();


            var collectionUri = UriFactory.CreateDocumentCollectionUri(
                configuration["CosmosDbSettings:DatabaseId"],
                configuration["CosmosDbCollectionSettings:MigrationReportCoursesCollectionId"]);

            await cosmosClient.UpsertDocumentAsync(collectionUri, courseReportEntry);
        }
예제 #2
0
 public static async Task Run(
     [TimerTrigger("%MigrationReportSchedule%")] TimerInfo myTimer,
     ILogger log,
     [Inject] IConfigurationRoot configuration,
     [Inject] ICosmosDbHelper cosmosDbHelper,
     [Inject] IBlobStorageHelper blobHelper,
     [Inject] IProviderCollectionService providerCollectionService,
     [Inject] ICourseCollectionService courseCollectionService,
     [Inject] IApprenticeshipCollectionService apprenticeshipCollectionService,
     [Inject] IMigrationReportCollectionService migrationReportCollectionService)
 {
     await new MigrationReportGeneratorService().Run(
         log, configuration, cosmosDbHelper, blobHelper, providerCollectionService, courseCollectionService,
         apprenticeshipCollectionService, migrationReportCollectionService
         );
 }
        private static async Task <string> GenerateCoursesExportForProvider(
            ILogger log,
            ICourseCollectionService courseCollectionService,
            StringBuilder logFile,
            IMiragtionProviderItem mpItem,
            CloudBlobContainer containerExporter,
            string containerNameExporter)
        {
            logFile.AppendLine($"Conditional logic for {mpItem} is True.");

            logFile.AppendLine($"\tAttempting to get courses' data for: {mpItem}");

            var courses = await courseCollectionService.GetAllLiveCoursesAsJsonForUkprnAsync(mpItem.Ukprn);

            logFile.AppendLine($"\tGot courses' data for: {mpItem}");

            if (courses != "[]")
            {
                logFile.AppendLine($"\t\tHas courses' data for: {mpItem}");

                var coursesFileName =
                    $"{DateTime.Today.ToString("yyyyMMdd")}\\Generated\\Courses_for_Provider_{mpItem.Ukprn}_{DateTime.Now.ToString("yyyy-MM-ddTHH-mm-ss")}.json";

                logFile.AppendLine($"\t\tGot reference to block blob containers for file: {coursesFileName}");

                var coursesBlob = containerExporter.GetBlockBlobReference(coursesFileName);

                logFile.AppendLine(
                    $"\t\tAttempting to upload file {coursesFileName} to blob container {containerNameExporter}");

                await coursesBlob.UploadTextAsync(courses);

                log.LogInformation($"uploaded {coursesFileName}");

                logFile.AppendLine($"\t\tUploaded file {coursesFileName} to blob container {containerNameExporter}");

                return(coursesFileName);
            }
            else
            {
                logFile.AppendLine($"\t\tHas no courses' data for: {mpItem}");
                return(null);
            }
        }
        public static async Task Run(
            [TimerTrigger("%schedule%")] TimerInfo myTimer,
            ILogger log,
            [Inject] IOptions <ExporterSettings> exporterSettings,
            [Inject] IBlobStorageHelper blobStorageHelper,
            [Inject] IProviderCollectionService providerCollectionService,
            [Inject] ICourseCollectionService courseCollectionService,
            [Inject] IVenueCollectionService venueCollectionService)
        {
            var configuration = exporterSettings.Value;

            log.LogInformation("[Export] waiting for trigger...");

            //TODO: add more logging after you get this working ...
            var logFile = new StringBuilder();

            logFile.AppendLine($"Starting {nameof(Export)} at {DateTime.Now}");

            var fileNames = new List <string>();
            var startDate = configuration.ExporterStartDate;

            var providersFileName = $"{DateTime.Today.ToString("yyyyMMdd")}\\Generated\\Providers_{DateTime.Now.ToString("yyyy-MM-ddTHH-mm-ss")}.json";

            logFile.AppendLine($"Start date: {startDate:dd/MM/yyyy hh:mm}");
            logFile.AppendLine($"Provider filename: {providersFileName}");

            var containerNameExporter      = configuration.ContainerNameExporter;
            var containerNameProviderFiles = configuration.ContainerNameProviderFiles;
            var migrationProviderCsv       = configuration.MigrationProviderCsv;

            logFile.AppendLine($"Attempting to get reference to blob containers: {containerNameExporter}, {containerNameProviderFiles}");

            var containerExporter      = blobStorageHelper.GetBlobContainer(containerNameExporter);
            var containerProviderFiles = blobStorageHelper.GetBlobContainer(containerNameProviderFiles);

            logFile.AppendLine($"Got references to blob containers: {containerNameExporter}, {containerNameProviderFiles}");

            try
            {
                log.LogInformation("[Export] grabbing providers");
                var providersForExport = await GetProvidersFromCsv(migrationProviderCsv, blobStorageHelper, logFile, containerProviderFiles);

                var providerFileName = await GenerateProvidersExport(providerCollectionService, providersForExport, logFile, providersFileName, containerExporter, containerNameExporter);

                fileNames.Add(providerFileName);

                var count = 0;
                var total = providersForExport.Count();

                // N.B. Deliberately not doing these in parallel to avoid creating too many DocumentClients...
                foreach (var provider in providersForExport)
                {
                    count++;

                    log.LogInformation($"[Export] checking {provider.Ukprn} [{count} of {total}]");

                    var export = await CheckForProviderUpdates(log, courseCollectionService,
                                                               venueCollectionService, logFile, provider, startDate, containerExporter,
                                                               containerNameExporter)
                                 .ConfigureAwait(false);

                    fileNames.AddRange(export);
                }

                var fileNamesFileName = $"{DateTime.Today.ToString("yyyyMMdd")}\\Generated\\FileNames.json";
                var fileNamesBlob     = containerExporter.GetBlockBlobReference(fileNamesFileName);
                await fileNamesBlob.UploadTextAsync(JsonConvert.SerializeObject(fileNames, Formatting.Indented));
            }
            catch (Exception e)
            {
                logFile.AppendLine(e.Message);
                logFile.AppendLine(e.ToString());
                throw;
            }
            finally
            {
                logFile.AppendLine($"Ending {nameof(Export)} at {DateTime.Now}");
                var logFileName     = $"{DateTime.Today.ToString("yyyyMMdd")}\\Generated\\Log_{DateTime.Now.ToString("yyyy-MM-ddTHH-mm-ss")}.txt";
                var logFileNameBlob = containerExporter.GetBlockBlobReference(logFileName);
                await logFileNameBlob.UploadTextAsync(logFile.ToString());
            }
        }
        private static async Task <IEnumerable <string> > CheckForProviderUpdates(
            ILogger log,
            ICourseCollectionService courseCollectionService,
            IVenueCollectionService venueCollectionService,
            StringBuilder logFile,
            IMiragtionProviderItem mpItem,
            DateTime fromDate,
            CloudBlobContainer containerExporter,
            string containerNameExporter)
        {
            var fileNames = new List <string>();

            logFile.AppendLine($"Attempting to get conditional data for: {mpItem}");

            var hasTodaysDate           = mpItem.DateMigrated.Date == DateTime.Today;
            var dateMigratedIsInThePast = mpItem.DateMigrated.Date < DateTime.Today;

            var hasCreatedCourses = await courseCollectionService.HasCoursesBeenCreatedSinceAsync(mpItem.Ukprn, fromDate);

            var hasCreatedCourseRuns =
                await courseCollectionService.HasCourseRunsBeenCreatedSinceAsync(mpItem.Ukprn, fromDate);

            var hasUpdatedCourses = await courseCollectionService.HasCoursesBeenUpdatedSinceAsync(mpItem.Ukprn, fromDate);

            var hasUpdatedCourseRuns =
                await courseCollectionService.HasCourseRunsBeenUpdatedSinceAsync(mpItem.Ukprn, fromDate);

            var hasDeletedCourses = await courseCollectionService.HasCoursesBeenDeletedSinceAsync(mpItem.Ukprn, fromDate);

            var hasDeletedCourseRuns =
                await courseCollectionService.HasCourseRunsBeenDeletedSinceAsync(mpItem.Ukprn, fromDate);

            var hasUpdatedVenues = await venueCollectionService.HasBeenAnUpdatedSinceAsync(mpItem.Ukprn, fromDate);

            logFile.AppendLine($"Got conditional data for: {mpItem}");
            logFile.AppendLine($"\tHas today's date: {hasTodaysDate}");
            logFile.AppendLine($"\tDate migrated is in the past: {dateMigratedIsInThePast}");
            logFile.AppendLine($"\tHas created Courses: {hasCreatedCourses}");
            logFile.AppendLine($"\tHas created CourseRuns: {hasCreatedCourseRuns}");
            logFile.AppendLine($"\tHas updated Courses: {hasUpdatedCourses}");
            logFile.AppendLine($"\tHas updated CourseRuns: {hasUpdatedCourseRuns}");
            logFile.AppendLine($"\tHas deleted Courses: {hasDeletedCourses}");
            logFile.AppendLine($"\tHas deleted CourseRuns: {hasDeletedCourseRuns}");
            logFile.AppendLine($"\tHas updated Venues: {hasUpdatedVenues}");
            logFile.AppendLine($"End of conditional data for: {mpItem}");

            if (hasTodaysDate || (dateMigratedIsInThePast))
            {
                if (hasCreatedCourses || hasCreatedCourseRuns || hasUpdatedCourses || hasUpdatedCourseRuns ||
                    hasDeletedCourses || hasDeletedCourseRuns)
                {
                    log.LogInformation($"updating courses for {mpItem.Ukprn}");

                    var courseFilename = await GenerateCoursesExportForProvider(log, courseCollectionService, logFile, mpItem, containerExporter,
                                                                                containerNameExporter).ConfigureAwait(false);

                    fileNames.Add(courseFilename);
                }

                if (hasUpdatedVenues)
                {
                    log.LogInformation($"updating venues for {mpItem.Ukprn}");

                    var venueFilename = await GenerateVenuesExportForProvider(log, venueCollectionService, logFile, mpItem, containerExporter,
                                                                              containerNameExporter).ConfigureAwait(false);

                    fileNames.Add(venueFilename);
                }
            }
            else
            {
                logFile.AppendLine($"Conditional logic for {mpItem} is False.");
            }

            return(fileNames);
        }
        public async Task Run(
            ILogger log,
            IConfigurationRoot configuration,
            ICosmosDbHelper cosmosDbHelper,
            IBlobStorageHelper blobHelper,
            IProviderCollectionService providerCollectionService,
            ICourseCollectionService courseCollectionService,
            IApprenticeshipCollectionService apprenticeshipCollectionService,
            IMigrationReportCollectionService migrationReportCollectionService)
        {
            log.LogInformation("Starting Migration Report generation");

            var migrationLog = new StringBuilder();

            migrationLog.AppendLine("-------------------------------------------------------");
            migrationLog.AppendLine("Starting Migration Report generation");
            migrationLog.AppendLine("-------------------------------------------------------");

            var stopWatch = new Stopwatch();

            stopWatch.Start();

            IReadOnlyList <RecordStatus> migratedStatusList = new List <RecordStatus>
            {
                RecordStatus.Live,
                RecordStatus.MigrationPending,
            };

            var blobContainer = blobHelper.GetBlobContainer(configuration["BlobStorageSettings:Container"]);

            var whiteListedProviders = await GetProviderWhiteList(blobHelper, blobContainer);

            var cosmosClient = cosmosDbHelper.GetClient();

            log.LogDebug("Fetching migrated provider count...");
            var migratedProvidersCount = (await providerCollectionService.GetAllMigratedProviders("Provider.Migrator")).Count;

            log.LogDebug($"Migrated Provider count: {migratedProvidersCount}.");

            log.LogDebug("Fetching providers...");
            var providers = await providerCollectionService.GetDocumentsByUkprn(whiteListedProviders);

            var providerTypeCounts = providers.GroupBy(t => t.ProviderType).Select(g => new { type = g.Key, qty = g.Count() });

            log.LogDebug($"Provider counts: {string.Join("; ", providerTypeCounts.Select(c => $"{c.type}: {c.qty}"))}. Total: {providers.Count}");

            int progress = 1;
            int feCourseReportEntryCount        = 0;
            int apprenticeshipsReportEntryCount = 0;

            foreach (var ukprn in whiteListedProviders)
            {
                try
                {
                    var provider = providers.Single(p => int.Parse(p.UnitedKingdomProviderReferenceNumber) == ukprn);

                    var logStart = $"STARTED : Generating report for provider with UKPRN: {provider.UnitedKingdomProviderReferenceNumber}. Progress: {progress++}/{whiteListedProviders.Count}";
                    log.LogDebug(logStart);
                    migrationLog.AppendLine(logStart);

                    switch (provider.ProviderType)
                    {
                    case ProviderType.Both:
                        await GenerateApprenticeshipReport(
                            configuration, apprenticeshipCollectionService, migrationReportCollectionService, provider,
                            migratedStatusList, cosmosClient);

                        apprenticeshipsReportEntryCount++;
                        await GenerateFECourseReport(
                            configuration, courseCollectionService, migrationReportCollectionService, provider,
                            migratedStatusList, cosmosClient);

                        feCourseReportEntryCount++;
                        break;

                    case ProviderType.Apprenticeship:
                        await GenerateApprenticeshipReport(
                            configuration, apprenticeshipCollectionService, migrationReportCollectionService, provider,
                            migratedStatusList, cosmosClient);

                        apprenticeshipsReportEntryCount++;
                        break;

                    case ProviderType.FE:
                        await GenerateFECourseReport(
                            configuration, courseCollectionService, migrationReportCollectionService, provider,
                            migratedStatusList, cosmosClient);

                        feCourseReportEntryCount++;
                        break;

                    case ProviderType.Undefined:
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    migrationLog.AppendLine($"COMPLETED : Report for provider {provider.UnitedKingdomProviderReferenceNumber}");
                }
                catch (Exception ex)
                {
                    migrationLog.AppendLine($"Error creating report for {ukprn}. {ex.GetBaseException().Message}");
                    log.LogError(ex, $"Error creating report for {ukprn}.");
                }
            }

            stopWatch.Stop();
            migrationLog.AppendLine("----------------------------------------------------------------");
            migrationLog.AppendLine($"Completed Migration Report generation in {stopWatch.Elapsed.TotalMinutes} minutes.");
            migrationLog.AppendLine($"Course Report Entries :  {feCourseReportEntryCount} for {migratedProvidersCount} migrated providers.");
            migrationLog.AppendLine($"Apps Report Entries :  {apprenticeshipsReportEntryCount} for {migratedProvidersCount} migrated providers");
            migrationLog.AppendLine("----------------------------------------------------------------");
            log.LogDebug(migrationLog.ToString());

            await blobHelper.UploadFile(
                blobContainer,
                $"MigrationReport_LogFile-{DateTime.Now:dd-MM-yy HHmm}.txt",
                GetResultAsByteArray(migrationLog));

            log.LogInformation($"Completed Migration Report generation. {feCourseReportEntryCount + apprenticeshipsReportEntryCount} records processed.");
        }
        public static async Task Run(
            string input,          // Work around https://github.com/Azure/azure-functions-vs-build-sdk/issues/168
            ILogger log,
            [Inject] IConfigurationRoot configuration,
            [Inject] ICourseCollectionService courseCollectionService,
            [Inject] ICosmosDbHelper cosmosDbHelper,
            [Inject] IBlobStorageHelper blobhelper,
            [Inject] IUkrlpApiService ukrlpApiService
            )
        {
            const string apprenticeshipAppName = "Validate.Course";

            var apprenticeshipValidationFileName = $"{apprenticeshipAppName}-{DateTime.Now.ToString("dd-MM-yy HHmm")}";
            var blobContainer = blobhelper.GetBlobContainer(configuration["BlobStorageSettings:Container"]);
            var validator     = new CourseValidator();

            List <CourseValidationResult> validationEResult = new List <CourseValidationResult>();

            var stopWatch = new Stopwatch();

            stopWatch.Start();

            var resultData = await courseCollectionService.GetAllCoursesAsync();

            foreach (var item in resultData)
            {
                //item.ContactEmail = "testing";
                //item.Url = "testing";
                //item.ContactWebsite = "testing";
                //item.ContactTelephone = "101101abc";
                //item.ApprenticeshipTitle = item.ApprenticeshipTitle + " @";

                var validationResult = validator.Validate(item);

                if (!validationResult.IsValid)
                {
                    foreach (var error in validationResult.Errors)
                    {
                        validationEResult.Add(new CourseValidationResult()
                        {
                            CourseId      = item.CourseId,
                            ProviderUkprn = item.ProviderUKPRN,
                            FieldName     = error.PropertyName,
                            ErrorMessage  = error.ErrorMessage
                        });
                    }
                }
            }

            var resultsObjBytes = GetResultAsByteArray(validationEResult);

            await WriteResultsToBlobStorage(resultsObjBytes);

            stopWatch.Stop();

            byte[] GetResultAsByteArray(IList <CourseValidationResult> message)
            {
                using (var memoryStream = new System.IO.MemoryStream())
                {
                    using (var streamWriter = new System.IO.StreamWriter(memoryStream))
                        using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture))
                        {
                            csvWriter.WriteRecords <CourseValidationResult>(message);
                        }
                    return(memoryStream.ToArray());
                }
            }

            async Task WriteResultsToBlobStorage(byte[] data)
            {
                await blobhelper.UploadFile(blobContainer, apprenticeshipValidationFileName, data);
            }
        }