Removed v7 import shit
This commit is contained in:
@@ -36,7 +36,7 @@ namespace AyaNova.Api.ControllerHelpers
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Process uploaded utility file (backup, import etc)
|
||||
/// Process uploaded utility file (backup)
|
||||
/// Anything that will be stored in the backup folder as is
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace AyaNova.Api.Controllers
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// V7 Import replace log entry
|
||||
/// V7 export replace log entry
|
||||
/// (internal use only)
|
||||
/// </summary>
|
||||
/// <param name="inObj"></param>
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using AyaNova.Models;
|
||||
using AyaNova.Api.ControllerHelpers;
|
||||
using AyaNova.Util;
|
||||
using AyaNova.Biz;
|
||||
|
||||
|
||||
namespace AyaNova.Api.Controllers
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Import AyaNova 7 data controller
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[ApiVersion("8.0")]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[Produces("application/json")]
|
||||
[Authorize]
|
||||
public class ImportAyaNova7Controller : ControllerBase
|
||||
{
|
||||
private readonly AyContext ct;
|
||||
private readonly ILogger<ImportAyaNova7Controller> log;
|
||||
private readonly ApiServerState serverState;
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dbcontext"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="apiServerState"></param>
|
||||
public ImportAyaNova7Controller(AyContext dbcontext, ILogger<ImportAyaNova7Controller> logger, ApiServerState apiServerState)
|
||||
{
|
||||
ct = dbcontext;
|
||||
log = logger;
|
||||
serverState = apiServerState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Upload AyaNova 7 import file
|
||||
/// </summary>
|
||||
/// <returns>NameValue list of filenames and id's</returns>
|
||||
[HttpPost]
|
||||
[DisableFormValueModelBinding]
|
||||
[RequestSizeLimit(10737418241)]//10737418240 = 10gb https://github.com/aspnet/Announcements/issues/267
|
||||
public async Task<IActionResult> Upload()
|
||||
{
|
||||
//outright closed then not allowed
|
||||
if (serverState.IsClosed)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
if (!Authorized.HasCreateRole(HttpContext.Items, AyaType.AyaNova7Import))
|
||||
{
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
}
|
||||
|
||||
var returnList = new List<String>();
|
||||
|
||||
try
|
||||
{
|
||||
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "FileUploadAttempt", $"Expected a multipart request, but got {Request.ContentType}"));
|
||||
}
|
||||
|
||||
var uploadFormData = await ApiUploadProcessor.ProcessUtilityFileUploadAsync(HttpContext);
|
||||
|
||||
bool badRequest = false;
|
||||
|
||||
string errorMessage = string.Empty;
|
||||
|
||||
//are these the right files?
|
||||
if (uploadFormData.UploadedFiles.Count > 0)
|
||||
{
|
||||
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
|
||||
{
|
||||
//should look like this: ayanova.data.dump.2018-04-2--12-30-57.zip
|
||||
string lwr = a.OriginalFileName.ToLowerInvariant();
|
||||
if (!(lwr.StartsWith("ayanova.data.dump") && lwr.EndsWith(".zip")))
|
||||
{
|
||||
badRequest = true;
|
||||
errorMessage = $"File uploaded \"{lwr}\" does not appear to be an AyaNova 7 data dump file. The name should start with \"ayanova.data.dump\" have a date in the middle and end with \".zip\". Upload process is terminated without saving.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (badRequest)
|
||||
{
|
||||
//delete temp files
|
||||
if (uploadFormData.UploadedFiles.Count > 0)
|
||||
{
|
||||
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
|
||||
{
|
||||
System.IO.File.Delete(a.InitialUploadedPathName);
|
||||
}
|
||||
}
|
||||
//return bad request
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, null, errorMessage));
|
||||
}
|
||||
|
||||
|
||||
//We have our files and a confirmed AyObject, ready to attach and save permanently
|
||||
if (uploadFormData.UploadedFiles.Count > 0)
|
||||
{
|
||||
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
|
||||
{
|
||||
returnList.Add(a.OriginalFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidDataException ex)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "FileUploadAttempt", ex.Message));
|
||||
}
|
||||
|
||||
//Return the list of attachment ids and filenames
|
||||
return Ok(ApiOkResponse.Response(returnList, true));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete import file
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns>Ok</returns>
|
||||
[HttpDelete("{filename}")]
|
||||
public ActionResult Delete([FromRoute] string filename)
|
||||
{
|
||||
if (serverState.IsClosed)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
}
|
||||
|
||||
|
||||
if (!Authorized.HasDeleteRole(HttpContext.Items, AyaType.AyaNova7Import))
|
||||
{
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
}
|
||||
|
||||
//do the delete
|
||||
//this handles removing the file if there are no efs left and also the db record for the attachment
|
||||
FileUtil.DeleteUtilityFile(filename);
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get AyaNova 7 data dump uploaded files list
|
||||
/// </summary>
|
||||
/// <returns>List of uploaded data dump files</returns>
|
||||
[HttpGet]
|
||||
public ActionResult List()
|
||||
{
|
||||
if (serverState.IsClosed)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.AyaNova7Import))
|
||||
{
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
}
|
||||
|
||||
//dump file name example: ayanova.data.dump.XXX.zip
|
||||
List<string> l = FileUtil.UtilityFileList("ayanova.data.dump.*.zip");
|
||||
return Ok(ApiOkResponse.Response(l, true));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// *ERASE DATABASE and start import of previously uploaded import file
|
||||
/// **This will permanently erase all current data in database without further warning as the first step in the import process**
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns>Ok</returns>
|
||||
[HttpPost("EraseDatabaseAndStartImport/{filename}")]
|
||||
public async Task<IActionResult> EraseDatabaseAndStartImport([FromRoute] string filename)
|
||||
{
|
||||
if (serverState.IsClosed)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
|
||||
if (!serverState.IsOpsOnly)
|
||||
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, "Server must be set to Operations Only mode before importing"));
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
}
|
||||
|
||||
//UPDATE: I think it should be ok so commenting this out for now pending something coming up in testing
|
||||
// //LOOKAT: I decided not to allow trial to import v7 data.
|
||||
// //This was a snap decision, I didn't think about it much other than
|
||||
// //I'm concerned right now as of April 17 2018 during development that
|
||||
// //a trial user will import their old AyaNova data and then ... well somehow continue to use it I guess,
|
||||
// //maybe it's a non-issue as a trial will only work so long anyway
|
||||
// #if (!DEBUG)
|
||||
// if (AyaNova.Core.License.LicenseIsTrial)
|
||||
// {
|
||||
// return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, "Current license is a trial license key. Only a licensed database can be used with import."));
|
||||
// }
|
||||
// #endif
|
||||
|
||||
//Create, in that they are creating new data in AyaNova
|
||||
if (!Authorized.HasCreateRole(HttpContext.Items, AyaType.AyaNova7Import))
|
||||
{
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
}
|
||||
|
||||
//does the file even exist?
|
||||
if (!FileUtil.UtilityFileExists(filename))
|
||||
{
|
||||
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND, "filename", "File not found, ensure the name via the GET route endpoint list of previously uploaded import files"));
|
||||
}
|
||||
|
||||
|
||||
//Create the job here
|
||||
dynamic jobInfo = new JObject();
|
||||
jobInfo.ImportFileName = filename;
|
||||
|
||||
OpsJob j = new OpsJob();
|
||||
j.Name = $"Import AyaNova7 data (import file \"{filename}\"";
|
||||
j.JobType = JobType.ImportV7Data;
|
||||
//j.O wnerId = UserIdFromContext.Id(HttpContext.Items);
|
||||
j.JobInfo = jobInfo.ToString();
|
||||
await JobsBiz.AddJobAsync(j, ct);
|
||||
return Accepted(new { JobId = j.GId });//202 accepted
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
}//eoc
|
||||
}//eons
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace AyaNova.Biz
|
||||
PickListTemplate = 7,
|
||||
DEPRECATED_REUSELATER_08 = 8,
|
||||
ServerJob = 9,
|
||||
AyaNova7Import = 10,
|
||||
DEPRECATED_10 = 10,
|
||||
TrialSeeder = 11,
|
||||
Metrics = 12,
|
||||
Translation = 13,
|
||||
|
||||
@@ -125,13 +125,13 @@ namespace AyaNova.Biz
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// V7 import handler
|
||||
/// Import needs to fixup event log CREATED entry to show original created and last modified times
|
||||
/// V7 export handler
|
||||
/// Exporter needs to fixup event log CREATED entry to show original created and last modified times
|
||||
/// and users
|
||||
/// </summary>
|
||||
internal static async Task V7_Modify_LogAsync(AyaNova.Api.Controllers.EventLogController.V7Event ev, AyContext ct)
|
||||
{
|
||||
//delete the automatically created entry from the import object
|
||||
//delete the automatically created entry from the exported object
|
||||
await ct.Database.ExecuteSqlInterpolatedAsync($"delete from aevent where aytype = {ev.AyType} and ayid={ev.AyId}");
|
||||
|
||||
//Now create the entries to reflect the original data from v7
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using AyaNova.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
||||
namespace AyaNova.Biz
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for biz objects that support importing AyaNova 7 data
|
||||
/// </summary>
|
||||
internal interface IImportAyaNova7Object
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Import from the JSON data provided
|
||||
/// </summary>
|
||||
/// <param name="v7ImportData">Json object containing source record</param>
|
||||
/// <param name="importMap">A collection that can be used to match import records to new records, NOT persistent between imports</param>
|
||||
/// <param name="JobId">JobId for logging or controlling jobs from within processor</param>
|
||||
/// <param name="tagLists">All the items imported to lists of tags with matching id for attribution / tagging imported object</param>
|
||||
/// <returns>True if imported, False if not imported due to invalid or other error (logged in job log)</returns>
|
||||
Task<bool> ImportV7Async(JObject v7ImportData, List<ImportAyaNova7MapItem> importMap, Guid JobId, Dictionary<string, Dictionary<Guid, string>> tagLists);
|
||||
|
||||
/// <summary>
|
||||
/// If true, relaxes validation rules so that incomplete data can be imported
|
||||
/// </summary>
|
||||
bool SeedOrImportRelaxedRulesMode { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
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()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// /// Handle the test job
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
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<ImportAyaNova7MapItem> importMap = new List<ImportAyaNova7MapItem>();
|
||||
|
||||
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<string>();
|
||||
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<string> 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<string, Dictionary<Guid, string>> TagLists = new Dictionary<string, Dictionary<Guid, string>>();
|
||||
|
||||
//IMPORT UNIT MODEL CATEGORIES AS TAGS
|
||||
TagLists.Add("UnitModelCategory", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.UnitModelCategory", job.GId, TagLists["UnitModelCategory"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Unit service type AS TAGS
|
||||
TagLists.Add("UnitServiceType", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.UnitServiceType", job.GId, TagLists["UnitServiceType"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Workorder Item Type AS TAGS
|
||||
TagLists.Add("WorkorderItemType", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.WorkorderItemType", job.GId, TagLists["WorkorderItemType"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Client group AS TAGS
|
||||
TagLists.Add("ClientGroup", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.ClientGroup", job.GId, TagLists["ClientGroup"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Workorder category AS TAGS
|
||||
TagLists.Add("WorkorderCategory", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.WorkorderCategory", job.GId, TagLists["WorkorderCategory"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Part Category AS TAGS
|
||||
TagLists.Add("PartCategory", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.PartCategory", job.GId, TagLists["PartCategory"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Dispatch zones AS TAGS
|
||||
TagLists.Add("DispatchZone", new Dictionary<Guid, string>());
|
||||
await ImportTagListAsync("GZTW.AyaNova.BLL.DispatchZone", job.GId, TagLists["DispatchZone"], importFileName, zipEntries);
|
||||
|
||||
//IMPORT Scheduleable User Groups AS TAGS
|
||||
TagLists.Add("ScheduleableUserGroup", new Dictionary<Guid, string>());
|
||||
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<Guid, string>());
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
/// <param name="entryStartsWith"></param>
|
||||
/// <param name="importTask"></param>
|
||||
/// <param name="importerType"></param>
|
||||
/// <param name="jobId"></param>
|
||||
/// <param name="importMap"></param>
|
||||
/// <param name="importFileName"></param>
|
||||
/// <param name="zipEntries"></param>
|
||||
/// <param name="tagLists"></param>
|
||||
/// <returns></returns>
|
||||
private async Task DoImportAsync(string entryStartsWith, string importTask, AyaType importerType, Guid jobId,
|
||||
List<ImportAyaNova7MapItem> importMap, string importFileName, List<string> zipEntries, Dictionary<string, Dictionary<Guid, string>> 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<Guid, string> tagDictionary, string importFileName, List<string> 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<string>();
|
||||
|
||||
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<string>());
|
||||
|
||||
//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<ImportAyaNova7MapItem> importMap, AyaType ayaType, AyContext ct)
|
||||
{
|
||||
var V7Id = new Guid(j["ID"].Value<string>());
|
||||
var RavenId = importMap.Where(m => m.V7ObjectId == V7Id).First().NewObjectAyaTypeId.ObjectId;
|
||||
var Creator = importMap.Where(m => m.V7ObjectId == new Guid(j["Creator"].Value<string>())).First().NewObjectAyaTypeId.ObjectId;
|
||||
var Modifier = importMap.Where(m => m.V7ObjectId == new Guid(j["Modifier"].Value<string>())).First().NewObjectAyaTypeId.ObjectId;
|
||||
var Created = j["Created"].Value<DateTime>();
|
||||
var Modified = j["Modified"].Value<DateTime>();
|
||||
|
||||
//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
|
||||
|
||||
@@ -9,8 +9,7 @@ namespace AyaNova.Biz
|
||||
{
|
||||
NotSet = 0,
|
||||
TestWidgetJob = 1,//test job for unit testing
|
||||
CoreJobSweeper = 2,
|
||||
ImportV7Data = 3,
|
||||
CoreJobSweeper = 2,
|
||||
SeedTestData = 4,
|
||||
|
||||
|
||||
|
||||
@@ -385,10 +385,7 @@ namespace AyaNova.Biz
|
||||
{
|
||||
case JobType.TestWidgetJob:
|
||||
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.Widget, ct);
|
||||
break;
|
||||
case JobType.ImportV7Data:
|
||||
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.AyaNova7Import, ct);
|
||||
break;
|
||||
break;
|
||||
case JobType.SeedTestData:
|
||||
o = (IJobObject)BizObjectFactory.GetBizObject(AyaType.TrialSeeder, ct);
|
||||
break;
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Text.RegularExpressions;
|
||||
namespace AyaNova.Biz
|
||||
{
|
||||
|
||||
internal class TranslationBiz : BizObject, IImportAyaNova7Object
|
||||
internal class TranslationBiz : BizObject
|
||||
{
|
||||
public bool SeedOrImportRelaxedRulesMode { get; set; }
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace AyaNova.Biz
|
||||
return await ct.TranslationItem.Where(m => m.TranslationId == ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID && m.Key == key).Select(m => m.Display).AsNoTracking().FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
//Get all stock keys that are valid (used for import)
|
||||
//Get all stock keys that are valid (used for key coverage reporting)
|
||||
internal static async Task<List<string>> GetKeyListAsync()
|
||||
{
|
||||
AyContext ct = ServiceProviderProvider.DBContext;
|
||||
@@ -253,8 +253,9 @@ namespace AyaNova.Biz
|
||||
|
||||
foreach (NewTextIdConcurrencyTokenItem tit in inObj)
|
||||
{
|
||||
var titem=await ct.TranslationItem.SingleOrDefaultAsync(m => m.Id == tit.Id);
|
||||
if(titem==null){
|
||||
var titem = await ct.TranslationItem.SingleOrDefaultAsync(m => m.Id == tit.Id);
|
||||
if (titem == null)
|
||||
{
|
||||
AddError(ApiErrorCode.NOT_FOUND, $"Translation item ID {tit.Id}");
|
||||
return false;
|
||||
}
|
||||
@@ -429,107 +430,6 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used by import, translate the old v7 translation key name into the new shorter version
|
||||
/// </summary>
|
||||
/// <param name="oldKey"></param>
|
||||
/// <returns></returns>
|
||||
public string Translatev7TranslationKey(string oldKey)
|
||||
{
|
||||
string s = oldKey.Replace(".Label.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (s.StartsWith("O.", StringComparison.InvariantCultureIgnoreCase))
|
||||
s = s.Replace("O.", "", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".ToolBar.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".Go.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".Command.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".Error.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".Object.", ".", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (s.StartsWith("UI.", StringComparison.InvariantCultureIgnoreCase))
|
||||
s = s.Replace("UI.", "", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace(".", "", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("AddressAddress", "Address", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ContactPhoneContactPhone", "ContactPhone", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ContactPhonePhone", "ContactPhone", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("PurchaseOrderPurchaseOrder", "PurchaseOrder", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("WorkorderItemMiscExpenseExpense", "WorkorderItemMiscExpense", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("WorkorderItemTravelTravel", "WorkorderItemTravel", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("DashboardDashboard", "Dashboard", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
//ScheduleMarkers -> Reminder
|
||||
s = s.Replace("ScheduleMarker", "Reminder", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerARGB", "ReminderARGB", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerColor", "ReminderColor", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerCompleted", "ReminderCompleted", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerEventCreated", "ReminderEventCreated", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerEventPendingAlert", "ReminderEventPendingAlert", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerFollowUp", "ReminderFollowUp", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerList", "ReminderList", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerName", "ReminderName", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerNotes", "ReminderNotes", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerRecurrence", "ReminderRecurrence", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerScheduleMarkerSourceType", "ReminderSourceType", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerSourceID", "ReminderSourceID", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerStartDate", "ReminderStartDate", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleMarkerStopDate", "ReminderStopDate", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleEditScheduleMarker", "ScheduleEditReminder", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("ScheduleNewScheduleMarker", "ScheduleNewReminder", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
|
||||
|
||||
|
||||
//Custom fields were 0 to 9, now 1 to 16
|
||||
s = s.Replace("Custom9", "Custom10", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom8", "Custom9", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom7", "Custom8", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom6", "Custom7", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom5", "Custom6", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom4", "Custom5", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom3", "Custom4", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom2", "Custom3", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (!s.EndsWith("Custom10"))
|
||||
s = s.Replace("Custom1", "Custom2", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("Custom0", "Custom1", StringComparison.InvariantCultureIgnoreCase);
|
||||
//separate code will handle adding the new keys that didn't exist in v7 (custom 11 - 16)
|
||||
|
||||
//CommonActive CommonID etc remove Common
|
||||
s = s.Replace("Common", "");
|
||||
|
||||
//Misc
|
||||
s = s.Replace("FormFieldDataType", "UiFieldDataType", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("UserUserType", "UserType", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("UserTypesUtilityNotification", "UserTypesUtility", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
//Localized -> Translation
|
||||
s = s.Replace("LocaleCustomizeText", "TranslationCustomizeText", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleExport", "TranslationExport", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleImport", "TranslationImport", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleList", "TranslationList", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleLocaleFile", "TranslationFile", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleUIDestLocale", "TranslationDest", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleUISourceLocale", "TranslationSource", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocaleWarnLocaleLocked", "TranslationWarnLocked", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocalizedTextDisplayText", "TranslationDisplayText", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocalizedTextDisplayTextCustom", "TranslationDisplayTextCustom", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocalizedTextKey", "TranslationKey", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocalizedTextLocale", "Translation", StringComparison.InvariantCultureIgnoreCase);
|
||||
s = s.Replace("LocalizedText", "TranslatedText", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
|
||||
//FUTURE
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
// s = s.Replace("WASXXX", "NOWXXXX", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -580,108 +480,6 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/// IMPORT v7 implementation
|
||||
public async Task<bool> ImportV7Async(
|
||||
JObject j, List<ImportAyaNova7MapItem> importMap,
|
||||
Guid jobId, Dictionary<string, Dictionary<Guid, string>> tagLists)
|
||||
{
|
||||
//some types need to import from more than one source hence the seemingly redundant switch statement for futureproofing
|
||||
switch (j["IMPORT_TASK"].Value<string>())
|
||||
{
|
||||
case "main":
|
||||
{
|
||||
//Get source translation name from filename using regex
|
||||
var SourceTranslationFileName = j["V7_SOURCE_FILE_NAME"].Value<string>();
|
||||
Regex RxExtractTranslationName = new Regex(@"translation\.(.*)\.json");
|
||||
var v = RxExtractTranslationName.Match(SourceTranslationFileName);
|
||||
var SourceTranslationName = v.Groups[1].ToString();
|
||||
|
||||
//Ensure doesn't already exist
|
||||
if (await TranslationExistsAsync(SourceTranslationName))
|
||||
{
|
||||
//If there are any validation errors, log in joblog and move on
|
||||
await JobsBiz.LogJobAsync(jobId, $"TranslationBiz::ImportV7Async -> - Translation \"{SourceTranslationName}\" already exists in database, can not import over an existing translation", ct);
|
||||
return false;
|
||||
}
|
||||
|
||||
//keys to skip importing
|
||||
List<string> SkipKeys = new List<string>();
|
||||
SkipKeys.Add("UI.Label.CurrentUserName");
|
||||
SkipKeys.Add("V7_SOURCE_FILE_NAME");
|
||||
SkipKeys.Add("V7_TYPE");
|
||||
SkipKeys.Add("IMPORT_TASK");
|
||||
|
||||
List<string> ValidKeys = await GetKeyListAsync();
|
||||
Dictionary<string, string> NewTranslationDict = new Dictionary<string, string>();
|
||||
foreach (var Pair in j.Children())
|
||||
{
|
||||
var V7Value = Pair.First.Value<string>().Replace(" && ", " ").Replace(" & ", " ").Replace("&", "");//clean out LT values that had double ampersands for old Windows menu shortcut scheme
|
||||
var V7KeyName = ((JProperty)Pair).Name;
|
||||
|
||||
if (!SkipKeys.Contains(V7KeyName))
|
||||
{
|
||||
var RavenKeyName = Translatev7TranslationKey(V7KeyName);
|
||||
if (!ValidKeys.Contains(RavenKeyName))
|
||||
{
|
||||
throw new System.ArgumentOutOfRangeException($"TranslationBiz::ImportV7 - old Key \"{V7KeyName}\" translates to new Key \"{RavenKeyName}\" which is not valid!");
|
||||
}
|
||||
|
||||
if (!NewTranslationDict.ContainsKey(RavenKeyName))
|
||||
{
|
||||
NewTranslationDict.Add(RavenKeyName, V7Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Use the shortest V7Value string in the case of dupes
|
||||
if (NewTranslationDict[RavenKeyName].Length > V7Value.Length)
|
||||
{
|
||||
NewTranslationDict[RavenKeyName] = V7Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Now add keys that were added after v7 for RAVEN using default translation values
|
||||
foreach (string s in ValidKeys)
|
||||
{
|
||||
if (!NewTranslationDict.ContainsKey(s))
|
||||
{
|
||||
NewTranslationDict.Add(s, await GetDefaultTranslationAsync(s));
|
||||
}
|
||||
}
|
||||
|
||||
//Validate it's the correct number of keys expected
|
||||
if (NewTranslationDict.Count != ValidKeys.Count)
|
||||
{
|
||||
throw new System.ArgumentOutOfRangeException($"TranslationBiz::ImportV7 - Import translation \"{SourceTranslationName}\" has an unexpected number of keys: {NewTranslationDict.Count}, expected {ValidKeys.Count} ");
|
||||
}
|
||||
|
||||
//have file name, have all localized text
|
||||
Translation l = new Translation();
|
||||
l.Name = SourceTranslationName;
|
||||
l.Stock = false;
|
||||
|
||||
foreach (KeyValuePair<string, string> K in NewTranslationDict)
|
||||
{
|
||||
l.TranslationItems.Add(new TranslationItem() { Key = K.Key, Display = K.Value });
|
||||
}
|
||||
|
||||
await ct.Translation.AddAsync(l);
|
||||
await ct.SaveChangesAsync();
|
||||
|
||||
//Log now that we have the Id, note that there is no source created / modified for this so just attributing to current userId
|
||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, l.Id, AyaType.Translation, AyaEvent.Created), ct);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//this is the equivalent of returning void for a Task signature with nothing to return
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -60,14 +60,8 @@ namespace AyaNova.Biz
|
||||
//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
|
||||
|
||||
|
||||
//FOR NOW NOT ASYNC so faking it at end of this method
|
||||
|
||||
|
||||
await JobsBiz.UpdateJobStatusAsync(job.GId, JobStatus.Running, ct);
|
||||
await JobsBiz.LogJobAsync(job.GId, $"Starting...", ct);
|
||||
|
||||
//Get the import filename from the jsondata
|
||||
await JobsBiz.LogJobAsync(job.GId, $"Starting...", ct);
|
||||
JObject jobData = JObject.Parse(job.JobInfo);
|
||||
var seedLevel = (Seeder.SeedLevel)jobData["seedLevel"].Value<int>();
|
||||
var timeZoneOffset = jobData["timeZoneOffset"].Value<decimal>();
|
||||
|
||||
@@ -6,15 +6,12 @@ using EnumsNET;
|
||||
using AyaNova.Util;
|
||||
using AyaNova.Api.ControllerHelpers;
|
||||
using AyaNova.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AyaNova.Biz
|
||||
{
|
||||
|
||||
|
||||
internal class UserBiz : BizObject, IJobObject, IImportAyaNova7Object, ISearchAbleObject
|
||||
internal class UserBiz : BizObject, IJobObject, ISearchAbleObject
|
||||
{
|
||||
|
||||
public bool SeedOrImportRelaxedRulesMode { get; set; }
|
||||
@@ -503,304 +500,6 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<bool> ImportV7Async(JObject j, List<ImportAyaNova7MapItem> importMap, Guid jobId, Dictionary<string, Dictionary<Guid, string>> tagLists)
|
||||
{
|
||||
|
||||
//NEEDS 3 of the tag lists
|
||||
|
||||
//TODO: Some of these items will need to be imported in future USEROPTIONS object that doesn't exist yet
|
||||
#region V7 record format
|
||||
/*
|
||||
{
|
||||
"DefaultLanguage": "Custom English",
|
||||
"DefaultServiceTemplateID": "ca83a7b8-4e5f-4a7b-a02b-9cf78d5f983f",
|
||||
"UserType": 2,
|
||||
"Active": true,
|
||||
"ClientID": "00000000-0000-0000-0000-000000000000",
|
||||
"HeadOfficeID": "00000000-0000-0000-0000-000000000000",
|
||||
* "MemberOfGroup": "0f8a80ff-4b03-4114-ae51-2d13b812dd65",
|
||||
"Created": "03/21/2005 07:19 AM",
|
||||
"Modified": "09/15/2015 12:22 PM",
|
||||
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"Modifier": "1d859264-3f32-462a-9b0c-a67dddfdf4d3",
|
||||
"ID": "1d859264-3f32-462a-9b0c-a67dddfdf4d3",
|
||||
"FirstName": "Hank",
|
||||
"LastName": "Rearden",
|
||||
"Initials": "HR",
|
||||
"EmployeeNumber": "EMP1236",
|
||||
"PageAddress": "",
|
||||
"PageMaxText": 24,
|
||||
"Phone1": "",
|
||||
"Phone2": "",
|
||||
"EmailAddress": "",
|
||||
"UserCertifications": [
|
||||
{
|
||||
"Created": "12/22/2005 02:07 PM",
|
||||
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"Modified": "12/22/2005 02:08 PM",
|
||||
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"ID": "4492360c-43e4-4209-9f33-30691b0808ed",
|
||||
"UserCertificationID": "b2f26359-7c42-4218-923a-e949f3ef1f85",
|
||||
"UserID": "1d859264-3f32-462a-9b0c-a67dddfdf4d3",
|
||||
"ValidStartDate": "2005-10-11T00:00:00-07:00",
|
||||
"ValidStopDate": "2006-10-11T00:00:00-07:00"
|
||||
}
|
||||
],
|
||||
"UserSkills": [
|
||||
{
|
||||
"Created": "12/22/2005 02:06 PM",
|
||||
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"Modified": "12/22/2005 02:08 PM",
|
||||
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"ID": "1dc5ce96-f411-4885-856e-5bdb3ad79728",
|
||||
"UserSkillID": "2e6f8b65-594c-4f6c-9cd6-e14a562daba8",
|
||||
"UserID": "1d859264-3f32-462a-9b0c-a67dddfdf4d3"
|
||||
},
|
||||
{
|
||||
"Created": "12/22/2005 02:06 PM",
|
||||
"Creator": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"Modified": "12/22/2005 02:08 PM",
|
||||
"Modifier": "2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed",
|
||||
"ID": "88e476d3-7526-45f5-a0dd-706c8053a63f",
|
||||
"UserSkillID": "47a4ee94-b0e9-41b5-afe5-4b4f2c981877",
|
||||
"UserID": "1d859264-3f32-462a-9b0c-a67dddfdf4d3"
|
||||
}
|
||||
],
|
||||
"Notes": "",
|
||||
"VendorID": "06e502c2-69ba-4e88-8efb-5b53c1687740",
|
||||
* "RegionID": "f856423a-d468-4344-b7b8-121e466738c6",
|
||||
* "DispatchZoneID": "00000000-0000-0000-0000-000000000000",
|
||||
"SubContractor": false,//This is not actually a feature in v7, you can just pick a vendorId for subcontractor but still be of type technician
|
||||
"DefaultWarehouseID": "d45eab37-b6e6-4ad2-9163-66d7ba83a98c",
|
||||
"Custom1": "",
|
||||
"Custom2": "",
|
||||
"Custom3": "",
|
||||
"Custom4": "",
|
||||
"Custom5": "",
|
||||
"Custom6": "",
|
||||
"Custom7": "",
|
||||
"Custom8": "",
|
||||
"Custom9": "",
|
||||
"Custom0": "",
|
||||
"ScheduleBackColor": -2097216,
|
||||
"TimeZoneOffset": null
|
||||
}
|
||||
*/
|
||||
|
||||
#endregion v7 record format
|
||||
|
||||
SeedOrImportRelaxedRulesMode = true;
|
||||
|
||||
//some types need to import from more than one source hence the seemingly redundant switch statement for futureproofing
|
||||
switch (j["IMPORT_TASK"].Value<string>())
|
||||
{
|
||||
case "main":
|
||||
{
|
||||
#region Main import
|
||||
var V7Id = new Guid(j["ID"].Value<string>());
|
||||
|
||||
//skip the administrator account but add it to the map for all the other import code that requires it
|
||||
if (V7Id == new Guid("2ecc77fc-69e2-4a7e-b88d-bd0ecaf36aed"))
|
||||
{
|
||||
var mapItem = new ImportAyaNova7MapItem(V7Id, BizType, 1);
|
||||
importMap.Add(mapItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Copy values
|
||||
User i = new User();
|
||||
|
||||
|
||||
i.Name = j["FirstName"].Value<string>() + " " + j["LastName"].Value<string>();
|
||||
var Temp = j["UserType"].Value<int>();
|
||||
i.UserType = (UserType)Temp;
|
||||
|
||||
//If there is a vendorId set then this user is actually a subcontractor in v7 so set accordingly
|
||||
var VendorId = new Guid(j["VendorID"].Value<string>());
|
||||
if (VendorId != Guid.Empty)
|
||||
{
|
||||
i.UserType = UserType.Subcontractor;
|
||||
}
|
||||
|
||||
i.Active = false;//Ignore incoming value and set all imports to false so that there's no chance of licensing getting circumvented; users all need to be edited anyway for pw and login
|
||||
i.EmployeeNumber = j["EmployeeNumber"].Value<string>();
|
||||
i.Notes = j["Notes"].Value<string>();
|
||||
|
||||
//TAGS
|
||||
//member of group is actually security group not sched user group so this was wrong anyway but moot now
|
||||
// var MemberOfGroupId = new Guid(j["MemberOfGroup"].Value<string>());
|
||||
// if (MemberOfGroupId != Guid.Empty)
|
||||
// {
|
||||
// string sTag = string.Empty;
|
||||
// if (tagLists["ScheduleableUserGroup"].TryGetValue(MemberOfGroupId, out sTag))
|
||||
// {
|
||||
// i.Tags.Add(sTag);
|
||||
// }
|
||||
// }
|
||||
|
||||
var RegionID = new Guid(j["RegionID"].Value<string>());
|
||||
if (RegionID != Guid.Empty)
|
||||
{
|
||||
string sTag = string.Empty;
|
||||
if (tagLists["Region"].TryGetValue(RegionID, out sTag))
|
||||
{
|
||||
i.Tags.Add(sTag);
|
||||
}
|
||||
}
|
||||
|
||||
var DispatchZoneID = new Guid(j["DispatchZoneID"].Value<string>());
|
||||
if (DispatchZoneID != Guid.Empty)
|
||||
{
|
||||
string sTag = string.Empty;
|
||||
if (tagLists["DispatchZone"].TryGetValue(DispatchZoneID, out sTag))
|
||||
{
|
||||
i.Tags.Add(sTag);
|
||||
}
|
||||
}
|
||||
|
||||
//User options
|
||||
i.UserOptions = new UserOptions();
|
||||
|
||||
//TimeZone Offset
|
||||
//NOT IMPORTED / SUPPORTED
|
||||
|
||||
|
||||
//Email address
|
||||
i.UserOptions.EmailAddress = j["EmailAddress"].Value<string>();
|
||||
|
||||
//UI colour
|
||||
//TODO: this needs to be tested now that it's a web friendly value in the dbdump file
|
||||
/*
|
||||
Hexadecimal notation: #RGB[A]
|
||||
R (red), G (green), B (blue), and A (alpha) are hexadecimal characters (0–9, A–F). A is optional. The three-digit notation (#RGB) is a shorter version of the six-digit form (#RRGGBB). For example, #f09 is the same color as #ff0099. Likewise, the four-digit RGB notation (#RGBA) is a shorter version of the eight-digit form (#RRGGBBAA). For example, #0f38 is the same color as #00ff3388.
|
||||
*/
|
||||
// This is untested as of now, but should work, maybe if it doesn't the selector needs to be combined with dot notation instead of two array notations?
|
||||
i.UserOptions.UiColor = j["jextra"]["hexaScheduleBackColor"].Value<string>();
|
||||
|
||||
|
||||
//Set unusable random login credentials
|
||||
i.Salt = Hasher.GenerateSalt();
|
||||
i.Login = Hasher.GenerateSalt();
|
||||
i.Password = Hasher.hash(i.Salt, Hasher.GenerateSalt());
|
||||
|
||||
//No rights
|
||||
i.Roles = AuthorizationRoles.NoRole;
|
||||
|
||||
//temporary translation id to satisfy db settings
|
||||
i.UserOptions.TranslationId = ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID;
|
||||
|
||||
User o = await CreateAsync(i);
|
||||
if (HasErrors)
|
||||
{
|
||||
//If there are any validation errors, log in joblog and move on
|
||||
await JobsBiz.LogJobAsync(jobId, $" -> import object \"{i.Name}\" source id {V7Id.ToString()} failed validation and was not imported: {GetErrorsAsString()} ", ct);
|
||||
|
||||
//This is a fundamental problem with the import as users are required for many things so bomb out entirely
|
||||
//other things might be able to work around but this is too serious
|
||||
throw new System.SystemException("UserBiz::ImportV7Async - FATAL ERROR, IMPORT FROM V7 CANNOT CONTINUE WITHOUT ALL USERS BEING IMPORTED, SEE JOB ERROR LOG FOR DETAILS");
|
||||
// return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
await ct.SaveChangesAsync();
|
||||
var mapItem = new ImportAyaNova7MapItem(V7Id, BizType, o.Id);
|
||||
importMap.Add(mapItem);
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
break;
|
||||
case "eventlog":
|
||||
{
|
||||
await ImportAyaNova7Biz.LogEventCreatedModifiedEventsAsync(j, importMap, BizType, ct);
|
||||
}
|
||||
break;
|
||||
case "translation":
|
||||
{
|
||||
#region set translation
|
||||
//get the userId
|
||||
//----
|
||||
var V7Id = new Guid(j["ID"].Value<string>());
|
||||
var MapItem = importMap.Where(m => m.V7ObjectId == V7Id).FirstOrDefault();
|
||||
if (MapItem == null)
|
||||
{
|
||||
throw new System.Exception("UserBiz::ImportV7Async-translation - FATAL ERROR, IMPORT FROM V7 CANNOT CONTINUE USER NOT FOUND IN IMPORTMAP");
|
||||
}
|
||||
var NewId = MapItem.NewObjectAyaTypeId.ObjectId;
|
||||
User u = ct.User.Where(m => m.Id == NewId).FirstOrDefault();
|
||||
if (u == null)
|
||||
{
|
||||
throw new System.Exception("UserBiz::ImportV7Async-translation - FATAL ERROR, IMPORT FROM V7 CANNOT CONTINUE USER NOT FOUND IN DATABASE");
|
||||
}
|
||||
|
||||
//handle translation entries for users now that we have the Translations created
|
||||
var V7Translation = j["DefaultLanguage"].Value<string>();
|
||||
|
||||
//Get new translation name
|
||||
var NewTranslationName = string.Empty;
|
||||
switch (V7Translation)
|
||||
{
|
||||
case "Français":
|
||||
NewTranslationName = "fr";
|
||||
break;
|
||||
case "Español":
|
||||
NewTranslationName = "es";
|
||||
break;
|
||||
case "Deutsch":
|
||||
NewTranslationName = "de";
|
||||
break;
|
||||
case "English":
|
||||
NewTranslationName = "en";
|
||||
break;
|
||||
default:
|
||||
{
|
||||
//It's a custom translation, translate it from v7 original format to imported name format
|
||||
//make lower and replace spaces with dashes
|
||||
NewTranslationName = V7Translation.ToLowerInvariant().Replace(" ", "-");
|
||||
|
||||
//ensure each character is a valid path character
|
||||
foreach (char c in System.IO.Path.GetInvalidFileNameChars())//is this kosher on linux? Original code was windows
|
||||
{
|
||||
NewTranslationName = NewTranslationName.Replace(c, '_');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
u.UserOptions.TranslationId = await TranslationBiz.TranslationNameToIdStaticAsync(NewTranslationName, ct);
|
||||
|
||||
ct.SaveChanges();
|
||||
#endregion set translation
|
||||
}
|
||||
break;
|
||||
|
||||
case "clientid":
|
||||
{
|
||||
var V7Id = new Guid(j["ID"].Value<string>());
|
||||
//handle setting client id for user client login
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
break;
|
||||
case "headofficeid":
|
||||
{
|
||||
var V7Id = new Guid(j["ID"].Value<string>());
|
||||
//handle setting ho id for user headoffice login
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//this is the equivalent of returning void for a Task signature with nothing to return
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Other job handlers here...
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
using AyaNova.Biz;
|
||||
namespace AyaNova.Models
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Provides mapping during import
|
||||
/// </summary>
|
||||
public partial class ImportAyaNova7MapItem
|
||||
{
|
||||
public AyaTypeId NewObjectAyaTypeId { get; set; }
|
||||
public Guid V7ObjectId { get; set; }
|
||||
|
||||
public ImportAyaNova7MapItem(Guid v7Guid, AyaType ayaType, long newId)
|
||||
{
|
||||
NewObjectAyaTypeId = new AyaTypeId(ayaType, newId);
|
||||
V7ObjectId = v7Guid;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -336,8 +336,7 @@ namespace AyaNova.Util
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Check if DB is empty
|
||||
// CALLED BY LICENSE CONTROLLER AND LICENSE.CS FOR TRIAL Request check
|
||||
// Also called by Import
|
||||
// CALLED BY LICENSE CONTROLLER AND LICENSE.CS FOR TRIAL Request check
|
||||
internal static async Task<bool> DBIsEmptyAsync(AyContext ct, ILogger _log)
|
||||
{
|
||||
//TODO: This needs to be way more thorough, only the main tables though, no need to get crazy with it
|
||||
|
||||
@@ -188,40 +188,40 @@ namespace AyaNova.Util
|
||||
return zipEntries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import utility - get individual files specified in zip archive as JSON objects
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="zipFileName">Name of utility zip import file</param>
|
||||
/// <param name="entryList">Name of entries in utility file archive to fetch</param>
|
||||
/// <returns></returns>
|
||||
internal static List<JObject> ZipGetUtilityArchiveEntriesAsJsonObjects(List<string> entryList, string zipFileName)
|
||||
{
|
||||
List<JObject> jList = new List<JObject>();
|
||||
var zipPath = GetFullPathForUtilityFile(zipFileName);
|
||||
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
|
||||
{
|
||||
foreach (string importFileName in entryList)
|
||||
{
|
||||
ZipArchiveEntry entry = archive.GetEntry(importFileName);
|
||||
if (entry != null)
|
||||
{
|
||||
//stream entry into a new jobject and add it to the list
|
||||
StreamReader reader = new StreamReader(entry.Open());
|
||||
string text = reader.ReadToEnd();
|
||||
var j = JObject.Parse(text);
|
||||
// /// <summary>
|
||||
// /// Import utility - get individual files specified in zip archive as JSON objects
|
||||
// ///
|
||||
// /// </summary>
|
||||
// /// <param name="zipFileName">Name of utility zip import file</param>
|
||||
// /// <param name="entryList">Name of entries in utility file archive to fetch</param>
|
||||
// /// <returns></returns>
|
||||
// internal static List<JObject> ZipGetUtilityArchiveEntriesAsJsonObjects(List<string> entryList, string zipFileName)
|
||||
// {
|
||||
// List<JObject> jList = new List<JObject>();
|
||||
// var zipPath = GetFullPathForUtilityFile(zipFileName);
|
||||
// using (ZipArchive archive = ZipFile.OpenRead(zipPath))
|
||||
// {
|
||||
// foreach (string importFileName in entryList)
|
||||
// {
|
||||
// ZipArchiveEntry entry = archive.GetEntry(importFileName);
|
||||
// if (entry != null)
|
||||
// {
|
||||
// //stream entry into a new jobject and add it to the list
|
||||
// StreamReader reader = new StreamReader(entry.Open());
|
||||
// string text = reader.ReadToEnd();
|
||||
// var j = JObject.Parse(text);
|
||||
|
||||
//Here add v7 import file name as sometimes it's needed later (Translations)
|
||||
j.Add("V7_SOURCE_FILE_NAME", JToken.FromObject(importFileName));
|
||||
jList.Add(j);
|
||||
}
|
||||
}
|
||||
// //Here add v7 import file name as sometimes it's needed later (Translations)
|
||||
// j.Add("V7_SOURCE_FILE_NAME", JToken.FromObject(importFileName));
|
||||
// jList.Add(j);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
return jList;
|
||||
// return jList;
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
#endregion Zip handling
|
||||
|
||||
Reference in New Issue
Block a user