using System; using System.Linq; using System.Threading.Tasks; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using EnumsNET; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Biz; using AyaNova.Models; namespace AyaNova.Biz { internal class ImportAyaNova7Biz : BizObject, IJobObject { // private readonly AyContext ct; // public readonly long userId; // private readonly AuthorizationRoles userRoles; internal ImportAyaNova7Biz(AyContext dbcontext, long currentUserId, AuthorizationRoles userRoles) { ct = dbcontext; UserId = currentUserId; CurrentUserRoles = userRoles; BizType = AyaType.AyaNova7Import; } //////////////////////////////////////////////////////////////////////////////////////////////// //JOB / OPERATIONS // public async Task HandleJobAsync(OpsJob job) { //Hand off the particular job to the corresponding processing code //NOTE: If this code throws an exception the caller (JobsBiz::ProcessJobsAsync) will automatically set the job to failed and log the exeption so //basically any error condition during job processing should throw up an exception if it can't be handled //There might be future other job types so doing it like this for all biz job handlers for now switch (job.JobType) { case JobType.ImportV7Data: await ProcessImportV7JobAsync(job); break; default: throw new System.ArgumentOutOfRangeException($"ImportAyaNovaBiz.HandleJob-> Invalid job type{job.JobType.ToString()}"); } } /// /// /// Handle the test job /// /// private async Task ProcessImportV7JobAsync(OpsJob job) { //NOTE: If this code throws an exception the caller will automatically set the job to failed and log the exeption so //basically any error condition during job processing should throw up an exception if it can't be handled List importMap = new List(); await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running, ct); await JobsBiz.LogJobAsync(job.GId, $"ImportAyaNova7 starting", ct); //Get the import filename from the jsondata JObject jobData = JObject.Parse(job.JobInfo); var importFileName = jobData["ImportFileName"].Value(); if (string.IsNullOrWhiteSpace(importFileName)) { throw new System.ArgumentNullException("ImportAyaNova7 job failed due to no import filename being specified"); } if (!FileUtil.UtilityFileExists(importFileName)) { throw new System.ArgumentNullException("ImportAyaNova7 job failed due to import file specified not existing"); } //Erase all the data except for the license, schema and the manager user Microsoft.Extensions.Logging.ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("ImportAyaNova7"); await JobsBiz.LogJobAsync(job.GId, "ImportAyaNova7 - Erasing data from database", ct); await DbUtil.EmptyBizDataFromDatabaseForSeedingOrImportingAsync(log); //get the contents of the archive List zipEntries = FileUtil.ZipGetUtilityFileEntries(importFileName); //Iterate through the import items in the preferred order, checking for corresponding entries in the zip file //In turn try to instantiate the type and id job that can handle that import, attempt to case or see if implements IImportAyaNova7Object //, if null / not supported for import then skip and log as not currently supported //Pass off the JSON data from the import file into the import job item by item //NOTE: Many of these require a second pass - one to get the object imported and then another to set another imported object to that object //////////////////////////////////// //TAGS // //FIRST: import items that will become tags first into temporary cache lists Dictionary> TagLists = new Dictionary>(); //IMPORT UNIT MODEL CATEGORIES AS TAGS TagLists.Add("UnitModelCategory", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.UnitModelCategory", job.GId, TagLists["UnitModelCategory"], importFileName, zipEntries); //IMPORT Unit service type AS TAGS TagLists.Add("UnitServiceType", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.UnitServiceType", job.GId, TagLists["UnitServiceType"], importFileName, zipEntries); //IMPORT Workorder Item Type AS TAGS TagLists.Add("WorkorderItemType", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.WorkorderItemType", job.GId, TagLists["WorkorderItemType"], importFileName, zipEntries); //IMPORT Client group AS TAGS TagLists.Add("ClientGroup", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.ClientGroup", job.GId, TagLists["ClientGroup"], importFileName, zipEntries); //IMPORT Workorder category AS TAGS TagLists.Add("WorkorderCategory", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.WorkorderCategory", job.GId, TagLists["WorkorderCategory"], importFileName, zipEntries); //IMPORT Part Category AS TAGS TagLists.Add("PartCategory", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.PartCategory", job.GId, TagLists["PartCategory"], importFileName, zipEntries); //IMPORT Dispatch zones AS TAGS TagLists.Add("DispatchZone", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.DispatchZone", job.GId, TagLists["DispatchZone"], importFileName, zipEntries); //IMPORT Scheduleable User Groups AS TAGS TagLists.Add("ScheduleableUserGroup", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.ScheduleableUserGroup", job.GId, TagLists["ScheduleableUserGroup"], importFileName, zipEntries); //Now can set users to correct tag for scheduleable user group // await ImportTagList("GZTW.AyaNova.BLL.ScheduleableUserGroup", "scheduleableusergrouptags", AyaType.Tag, job.GId, importMap, importFileName, zipEntries); //IMPORT REGIONS AS TAGS TagLists.Add("Region", new Dictionary()); await ImportTagListAsync("GZTW.AyaNova.BLL.Region", job.GId, TagLists["Region"], importFileName, zipEntries); //////////////////////////////////// // OBJECTS // //USERS await DoImportAsync("GZTW.AyaNova.BLL.User", "main", AyaType.User, job.GId, importMap, importFileName, zipEntries, TagLists); //Now can do event log entries await DoImportAsync("GZTW.AyaNova.BLL.User", "eventlog", AyaType.User, job.GId, importMap, importFileName, zipEntries, TagLists); //IMPORT TRANSLATIONS await DoImportAsync("GZTW.AyaNova.BLL.Translation", "main", AyaType.Translation, job.GId, importMap, importFileName, zipEntries, TagLists); //Now can do user translation settings properly await DoImportAsync("GZTW.AyaNova.BLL.User", "translation", AyaType.User, job.GId, importMap, importFileName, zipEntries, TagLists); //TODO: CLIENT //do import for client here //Now can do user client settings properly //await DoImport("GZTW.AyaNova.BLL.User","clientid", AyaType.User, job.GId, importMap, importFileName, zipEntries); //TODO: HEADOFFICE //do import for ho here //Now can do user ho settings properly //await DoImport("GZTW.AyaNova.BLL.User","headofficeid", AyaType.User, job.GId, importMap, importFileName, zipEntries); //---------------- await JobsBiz.LogJobAsync(job.GId, "ImportAyaNova7 finished", ct); await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Completed, ct); } /// /// This method does the actual import by /// - Fetching the list of entries in the zip archive that match the passed in startsWtih (folder name in zip archive) /// - Instantiating the corresponding new biz object type to handle the import /// - Passing the json parsed to the biz object one at a time to do the import /// /// /// /// /// /// /// /// /// /// private async Task DoImportAsync(string entryStartsWith, string importTask, AyaType importerType, Guid jobId, List importMap, string importFileName, List zipEntries, Dictionary> tagLists) { var zipObjectList = zipEntries.Where(m => m.StartsWith(entryStartsWith)).ToList(); long importCount = 0; long notImportCount = 0; if (zipObjectList.Count > 0) { if (importTask != "main") { await JobsBiz.LogJobAsync(jobId, $"Starting import sub-task {importTask} of {entryStartsWith} objects", ct); } else { await JobsBiz.LogJobAsync(jobId, $"Starting import of {entryStartsWith} objects", ct); } var jList = FileUtil.ZipGetUtilityArchiveEntriesAsJsonObjects(zipObjectList, importFileName); IImportAyaNova7Object o = (IImportAyaNova7Object)BizObjectFactory.GetBizObject(importerType, ct); foreach (JObject j in jList) { bool bImportSucceeded = false; //some new types can import multiple old types and it might matter which is which to the importer //so tag it with the original type //------ j.Add("V7_TYPE", JToken.FromObject(entryStartsWith)); j.Add("IMPORT_TASK", JToken.FromObject(importTask)); bImportSucceeded = await o.ImportV7Async(j, importMap, jobId, tagLists); if (bImportSucceeded) importCount++; else notImportCount++; } if (importCount > 0) { if (importTask != "main") { await JobsBiz.LogJobAsync(jobId, $"Successfully ran import subtask {importTask} on {importCount.ToString()} of {zipObjectList.Count.ToString()} {entryStartsWith} objects", ct); } else { await JobsBiz.LogJobAsync(jobId, $"Successfully imported {importCount.ToString()} of {zipObjectList.Count.ToString()} {entryStartsWith} objects", ct); } } if (notImportCount > 0) { if (importTask != "main") { await JobsBiz.LogJobAsync(jobId, $"Failed to run import subtask {importTask} on {notImportCount.ToString()} of {zipObjectList.Count.ToString()} {entryStartsWith} objects", ct); } else { await JobsBiz.LogJobAsync(jobId, $"Did not import {notImportCount.ToString()} of {zipObjectList.Count.ToString()} {entryStartsWith} objects", ct); } } } } //Other job handlers here... private async Task ImportTagListAsync(string entryStartsWith, Guid jobId, Dictionary tagDictionary, string importFileName, List zipEntries) { var zipObjectList = zipEntries.Where(m => m.StartsWith(entryStartsWith)).ToList(); long importCount = 0; if (zipObjectList.Count > 0) { await JobsBiz.LogJobAsync(jobId, $"Starting import to TAGS of {entryStartsWith} objects", ct); var jList = FileUtil.ZipGetUtilityArchiveEntriesAsJsonObjects(zipObjectList, importFileName); foreach (JObject j in jList) { //------- IMPORT OBJECTS NAME AND ID TO LIST ------ #region main import task var NewTagName = j["Name"].Value(); var ShortTypeName = string.Empty; switch (entryStartsWith) { case "GZTW.AyaNova.BLL.Region": ShortTypeName = "region"; break; case "GZTW.AyaNova.BLL.UnitModelCategory": ShortTypeName = "unitmodelcategory"; break; case "GZTW.AyaNova.BLL.UnitServiceType": ShortTypeName = "unitservicetype"; break; case "GZTW.AyaNova.BLL.WorkorderItemType": ShortTypeName = "workorderitemtype"; break; case "GZTW.AyaNova.BLL.ClientGroup": ShortTypeName = "clientgroup"; break; case "GZTW.AyaNova.BLL.WorkorderCategory": ShortTypeName = "workordercategory"; break; case "GZTW.AyaNova.BLL.PartCategory": ShortTypeName = "partcategory"; break; case "GZTW.AyaNova.BLL.DispatchZone": ShortTypeName = "dispatchzone"; break; case "GZTW.AyaNova.BLL.ScheduleableUserGroup": ShortTypeName = "scheduleableusergroup"; break; } NewTagName += "." + ShortTypeName; var OldV7Id = new Guid(j["ID"].Value()); //Ensure it follows the rules NewTagName = TagUtil.NormalizeTag(NewTagName); //Add to dictionary if not present tagDictionary.Add(OldV7Id, NewTagName); #endregion //----------------------------------------------- importCount++; } if (importCount > 0) { await JobsBiz.LogJobAsync(jobId, $"Successfully imported as TAGS {importCount.ToString()} of {zipObjectList.Count.ToString()} {entryStartsWith} objects", ct); } } } ////////////////////////////////////////////////////////////////// //UTILITIES internal static async Task LogEventCreatedModifiedEventsAsync(JObject j, List importMap, AyaType ayaType, AyContext ct) { var V7Id = new Guid(j["ID"].Value()); var RavenId = importMap.Where(m => m.V7ObjectId == V7Id).First().NewObjectAyaTypeId.ObjectId; var Creator = importMap.Where(m => m.V7ObjectId == new Guid(j["Creator"].Value())).First().NewObjectAyaTypeId.ObjectId; var Modifier = importMap.Where(m => m.V7ObjectId == new Guid(j["Modifier"].Value())).First().NewObjectAyaTypeId.ObjectId; var Created = j["Created"].Value(); var Modified = j["Modified"].Value(); //handle EventLog entries for users now that we have the user's created //Created await EventLogProcessor.LogEventToDatabaseAsync(new Event(Creator, RavenId, ayaType, AyaEvent.Created, Created), ct); //MODIFIED await EventLogProcessor.LogEventToDatabaseAsync(new Event(Modifier, RavenId, ayaType, AyaEvent.Modified, Modified), ct); } ///////////////////////////////////////////////////////////////////// }//eoc }//eons