using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.ComponentModel; using System.Windows.Forms; using System.Reflection; using AyaNova.PlugIn; using GZTW.AyaNova.BLL; using System.IO; using System.IO.Compression; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Linq; using System.Net.Http; using System.Net.Http.Headers; namespace AyaNova.PlugIn.V8 { class V8 : IAyaNovaPlugin { #region Plugin interface System.Resources.ResourceManager resman = null; private static List ObjectsWeCanDealWith = null; public string PluginName { get { return "Export to V8"; } } public string PluginVersion { get { return "7.6.1-alpha.8"; } } public string About { get { return "AyaNova V8 export plugin"; } } public Guid PluginID { get { return new Guid("{BD608E8A-820C-46D1-9D81-4CCB6E71B213}"); } } public System.Drawing.Image PluginSmallIcon { get { return Resource1.Dump16; } } public System.Drawing.Image PluginLargeIcon { get { return Resource1.Dump32; } } public System.Resources.ResourceManager AyaNovaResourceManager { set { resman = value; } get { return resman; } } public bool Initialize(Version AyaNovaVersion, LocalizedTextTable localizedText) { if (AyaNovaVersion.Major < 7) { MessageBox.Show("The V8 export plugin requires AyaNova version 7.6 or newer"); return false; } if (AyaNovaVersion.Minor < 6) { MessageBox.Show("The V8 export plugin requires AyaNova version 7.6 or newer"); return false; } util.LocaleText = localizedText; ObjectsWeCanDealWith = new List(); ObjectsWeCanDealWith.Add(RootObjectTypes.Nothing); return true; } public void Close() { ; } public bool SingleObjectMenuShow(RootObjectTypes objectType) { return (ObjectsWeCanDealWith.Contains(objectType)); } public bool MultipleObjectsMenuShow(RootObjectTypes objectType) { return false; } public List SingleObjectMenuOptions(RootObjectTypes objectType, object ayaNovaObject) { if (!ObjectsWeCanDealWith.Contains(objectType)) return null; List list = new List(); list.Add(new AyaNovaPluginMenuItem("V8 Export", "Export to AyaNova 8 server", null, null)); return list; } public List MultipleObjectsMenuOptions(RootObjectTypes objectType) { return null; } public bool CommandSelectedForList(string commandKey, RootObjectTypes objectType, List objectIDList, object listObject) { return false; } public void CommandSelectedForSingleObject(string commandKey, RootObjectTypes objectType, object ayaNovaObject) { util.PRE_RELEASE_VERSION_STRING = "Pre-release test " + this.PluginVersion; if (!User.CurrentUserIsAnAdministrator) { MessageBox.Show("This action can only be done by the AyaNova Administrator account"); return; } //#if(!DEBUG) if (!AyaBizUtils.AyaNovaConnectionSetting.SingleUserConnection) { MessageBox.Show("** WARNING: before proceeding ensure no other users are logged into AyaNova to ensure the integrity of your exported data. Failing to do so *will* result in damaged data. ***"); MessageBox.Show("** WARNING: before proceeding make sure your AyaNova Generator service is STOPPED to ensure the integrity of your exported data. Failing to do so *will* result in damaged data. ***"); } //#endif Auth d = new Auth(); var res = d.ShowDialog(); ; if (res == DialogResult.Cancel) { return; } Opt dOpt = new Opt(); var ro = dOpt.ShowDialog(); if (ro == DialogResult.Cancel) { return; } ExportAssignedDocs = dOpt.ExportAssignedDocs; //here because we logged in fine and can proceed //MessageBox.Show("Login successful! JWT is " + util.JWT); //Only one command DoExport(); } #endregion private Dictionary Map = new Dictionary(); private void AddMap(Guid v7id, long v8id) { if (Map.ContainsKey(v7id)) { throw new Exception("Error: AddMap - v7id already mapped previously, id is " + v7id.ToString()); } else Map.Add(v7id, v8id); } private bool IsDuplicateMapItem(Guid v7id, string name, ProgressForm progress) { if (Map.ContainsKey(v7id)) { progress.Append("DUPLICATE: " + name + " - has duplicate ID, not exported"); return true; } return false; } private long SafeGetUserMap(Guid id) { if (!Map.ContainsKey(id)) return 1;//1=raven administrator account return Map[id]; } private Dictionary TagMap = new Dictionary(); private Dictionary LocaleMap = new Dictionary(); private string ImportTag = "v7-import"; private bool ExportAssignedDocs = false; /// /// Dump the objects into a temporary directory as a series of JSON files /// then zip it all up into a single archive file and then erase the temporary folder /// private async void DoExport() { //Show progress form ProgressForm progress = new ProgressForm(); progress.Show(); progress.StartedImport(); progress.Append("Exporting data to AyaNova server @ " + util.ApiBaseUrl); progress.Append(util.PRE_RELEASE_VERSION_STRING); try { progress.Op("Preparing to export...."); Map.Clear(); TagMap.Clear(); LocaleMap.Clear(); //admin user (not exported but is there already) Map.Add(User.AdministratorID, 1); //not sure if this is a good idea or not because in some cases would want to know if something is unexpectedly empty but will see for now //Map.Add(Guid.Empty, 0); /* TODO: Need more detail when fails on release mode, right now no idea what actually happened Global wiki export to user Regions export wiki to user todo: export docs, settle on "Export" and edit all references to Import to switch it around as it's probably confusing artifact from dbdump days todo: User fields need to be rectified: headofficeid, clientid vendorid, phone1, phone2, pagermaxtext Yeah and a million other things too, this can wait until Stage7 - "Reality" */ //if (progress.KeepGoing) // await ExportLocales(progress); //return; //Export in correct order: //ERASE DB progress.Op("Erasing AyaNova 8 data"); var a = await util.PostAsync("License/PermanentlyEraseAllData", "\"I understand\""); //TAGS progress.Op("Compiling tags"); if (progress.KeepGoing) ExportUnitModelCategories(progress); if (progress.KeepGoing) ExportUnitServiceTypes(progress); if (progress.KeepGoing) ExportWorkorderItemTypes(progress); if (progress.KeepGoing) ExportRegions(progress); if (progress.KeepGoing) ExportClientGroups(progress); if (progress.KeepGoing) ExportWorkorderCategories(progress); if (progress.KeepGoing) ExportPartCategories(progress); if (progress.KeepGoing) ExportScheduleableUserGroups(progress); if (progress.KeepGoing) ExportDispatchZones(progress); if (progress.KeepGoing) ExportUserSkills(progress); if (progress.KeepGoing) ExportUserCertifications(progress); progress.Op("Exporting Business objects"); //BIZ objects await ExportLocales(progress); await ExportUsers(progress); await ExportClients(progress); await ExportHeadOffices(progress); await ExportContracts(progress); await ExportLoanItems(progress); await ExportParts(progress); await ExportProjects(progress); await ExportPurchaseOrders(progress); await ExportUnits(progress); await ExportUnitModels(progress); await ExportVendors(progress); await ExportServiceWorkorders(progress); //todo: these are now invalid and awaiting RAVEN end implementation //after which can copy mostly from service workorder block // await ExportQuotes(progress); // await ExportPMs(progress); //NOTE: when get to PRIORITY, or WORKORDER STATUS be sure to add color code as per already done in USER export if (progress.KeepGoing) { progress.Append("Export completed"); progress.Op(""); goto End; } progress.Append("Export cancelled before completing"); progress.Op(""); End: ; } catch (Exception ex) { progress.Append("ERROR, During operation: \n" + progress.LastOp + "\n" + progress.LastSubOp); progress.Append("\n************\nExport failed with error:\n"); progress.Append(ex.Message); progress.Append("stack:\n" + ex.StackTrace); } finally { progress.FinishedImport(); } //----------------------------------- //endof method } #region BIZ OBJECT Export methods List UsedNames = new List(); long LUniqueName = 1; private string GetUniqueName(string tryName) { string retName = tryName; do { if (!UsedNames.Contains(retName)) { UsedNames.Add(retName); return retName; } retName = util.UniqueNameBuilder(tryName, LUniqueName++, 255); } while (true); } private void ResetUniqueNames() { LUniqueName = 1; UsedNames.Clear(); } #region users private async System.Threading.Tasks.Task ExportUsers(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start User export"); progress.SubOp(""); ResetUniqueNames(); //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport("User"); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, "User", "User"); //Step 2: export the objects UserPickList pl = UserPickList.GetList(false); progress.Append("Exporting " + pl.Count.ToString() + " Users"); #region Export administrator wiki and attached files if present { User admin = User.GetItem(User.AdministratorID); progress.Op("Administrator account"); var adminTid = new TypeAndID(RootObjectTypes.User, User.AdministratorID); //Attachments and wiki string AdminWikiContent = null; var hasWiki = WikiPage.HasWiki(User.AdministratorID); if (hasWiki) { await ExportAttachments(adminTid, progress); AdminWikiContent = GetWikiContent(adminTid); } string adminCustomFields = null; //Custom fields? if (ShouldExportCustom) { adminCustomFields = CustomFieldData(admin, DateCustomFields); } //check if we need to do anything with the manager account itself if (hasWiki || adminCustomFields != null) { //yes, so fetch it and modify it and put it back again var a = await util.GetAsync("User/1"); dynamic d = a.ObjectResponse["data"]; d.wiki = AdminWikiContent; d.customFields = CustomFieldData(admin, DateCustomFields); await util.PutAsync("User/1", d.ToString()); } } #endregion admin export foreach (UserPickList.UserPickListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); //skip administrator user fields //but do export administrator if (i.ID == User.AdministratorID) continue; User c = User.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.User, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.FirstName + " " + c.LastName); if (IsDuplicateMapItem(c.ID, c.FirstName + " " + c.LastName, progress)) continue; progress.Op("User " + d.name); d.userType = (int)c.UserType; //if special 3rd party user type then set their parent object id to -1 to signify will fill in later and satisfy biz rules at server switch (c.UserType) { case UserTypes.Client: d.customerId = -1; break; case UserTypes.HeadOffice: d.headOfficeId = -1; break; } if (c.VendorID != Guid.Empty) { d.userType = 7;//7 is the RAVEN user type for subcontractor d.subVendorId = -1; } d.active = false;//all imported users are inactive to start d.roles = 0;//todo: try to determine role from v7 member of group? or is that even possible? d.login = util.RandomString(); d.password = util.RandomString(); d.employeeNumber = c.EmployeeNumber; d.notes = c.Notes; Tagit(c.RegionID, tags); Tagit(c.DispatchZoneID, tags); foreach (UserSkillAssigned skill in c.UserSkills) { Tagit(skill.UserSkillID, tags); } foreach (UserCertificationAssigned cert in c.UserCertifications) { Tagit(cert.UserCertificationID, tags); } SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync("User", d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //USER OPTIONS if (c.ScheduleBackColor != 0 || !string.IsNullOrWhiteSpace(c.EmailAddress)) { var rOptions = await util.GetAsync("UserOptions/" + RavenId.ToString()); d = rOptions.ObjectResponse["data"]; d.uiColor = System.Drawing.ColorTranslator.ToHtml(System.Drawing.Color.FromArgb(c.ScheduleBackColor)); d.emailAddress = string.IsNullOrWhiteSpace(c.EmailAddress) ? null : c.EmailAddress; if (LocaleMap.ContainsKey(c.DefaultLanguage)) d.translationId = LocaleMap[c.DefaultLanguage]; else d.translationId = 1; await util.PutAsync("UserOptions/" + RavenId.ToString(), d.ToString()); } //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync("User/" + RavenId.ToString(), d.ToString()); //----- } //EVENT LOG //Because this is the User's we need to do the event log *after* they have all been posted as event log requires all user's id foreach (UserPickList.UserPickListInfo i in pl) { if (!progress.KeepGoing) return; User c = User.GetItem(i.ID); var newId = Map[c.ID]; var creator = SafeGetUserMap(c.Creator); var modifier = SafeGetUserMap(c.Modifier); await util.EventLog(util.AyaType.User, newId, creator, modifier, c.Created, c.Modified); } } #endregion users #region Clients private async System.Threading.Tasks.Task ExportClients(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Client export"); progress.SubOp(""); ResetUniqueNames(); var ObjectTypeName = "Client"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, "Customer"); //Step 2: export the objects ClientPickList pl = ClientPickList.GetList(); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (ClientPickList.ClientPickListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Client c = Client.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Client, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.RegionID, tags); Tagit(c.DispatchZoneID, tags); Tagit(c.ClientGroupID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync("Customer", d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync("Customer/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Customer, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Clients #region Headoffices private async System.Threading.Tasks.Task ExportHeadOffices(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Head office export"); progress.SubOp(""); ResetUniqueNames(); var ObjectTypeName = "HeadOffice"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "headoffice"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); HeadOffice c = HeadOffice.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.HeadOffice, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.RegionID, tags); Tagit(c.ClientGroupID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync("HeadOffice", d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.HeadOffice, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion ho #region Contracts private async System.Threading.Tasks.Task ExportContracts(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Contract export"); progress.SubOp(""); var ObjectTypeName = "Contract"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "contract"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Contract c = Contract.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Contract, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.RegionID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Contract, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Contracts #region LoanItems private async System.Threading.Tasks.Task ExportLoanItems(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Loan item export"); progress.SubOp(""); var ObjectTypeName = "LoanItem"; var RavenObjectName = "LoanUnit"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, RavenObjectName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "loanitem"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); LoanItem c = LoanItem.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.LoanItem, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.RegionID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(RavenObjectName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(RavenObjectName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.LoanUnit, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion LoanItems #region Parts private async System.Threading.Tasks.Task ExportParts(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Parts export"); progress.SubOp(""); var ObjectTypeName = "Part"; var RavenObjectName = "Part"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, RavenObjectName); //Step 2: export the objects PartPickList pl = PartPickList.GetAllParts(); // PickListAutoComplete pl = PickListAutoComplete.GetList("**", "loanitem"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PartPickList.PartPickListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Part c = Part.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Part, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(i.DisplayName(AyaBizUtils.GlobalSettings.DefaultPartDisplayFormat));//todo: temporary for testing if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(RavenObjectName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Part, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Parts #region Projects private async System.Threading.Tasks.Task ExportProjects(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Projects export"); progress.SubOp(""); var ObjectTypeName = "Project"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "project"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Project c = Project.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Project, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.RegionID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Project, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Projects #region PurchaseOrders private async System.Threading.Tasks.Task ExportPurchaseOrders(ProgressForm progress) { if (!progress.KeepGoing) return; var ObjectTypeName = "PurchaseOrder"; progress.Op("Start Purchase orders export"); progress.SubOp(""); //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PurchaseOrderList pl = PurchaseOrderList.GetListByCriteria(""); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PurchaseOrderList.PurchaseOrderListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); PurchaseOrder c = PurchaseOrder.GetItem(i.LT_PurchaseOrder_Label_PONumber.Value); var ObjectTID = new TypeAndID(RootObjectTypes.PurchaseOrder, c.ID); dynamic d = new JObject(); d.name = c.PONumber.ToString(); if (IsDuplicateMapItem(c.ID, i.LT_PurchaseOrder_Label_PONumber.Display, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); // d.active = c.Active; d.notes = c.Notes; // Tagit(c.RegionID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.PurchaseOrder, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion PurchaseOrders #region Units private async System.Threading.Tasks.Task ExportUnits(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Units export"); progress.SubOp(""); var ObjectTypeName = "Unit"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects UnitPickList pl = UnitPickList.GetListOfAll(); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (UnitPickList.UnitPickListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Unit c = Unit.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Unit, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Serial); if (IsDuplicateMapItem(c.ID, c.Serial, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; // Tagit(c.RegionID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Unit, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Units #region UnitModels private async System.Threading.Tasks.Task ExportUnitModels(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Unit models export"); progress.SubOp(""); var ObjectTypeName = "UnitModel"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "unitmodel"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); UnitModel c = UnitModel.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.UnitModel, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; Tagit(c.UnitModelCategoryID, tags); SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.UnitModel, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion UnitModels #region Vendors private async System.Threading.Tasks.Task ExportVendors(ProgressForm progress) { ResetUniqueNames(); if (!progress.KeepGoing) return; progress.Op("Start Vendors export"); progress.SubOp(""); var ObjectTypeName = "Vendor"; //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport(ObjectTypeName); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, ObjectTypeName, ObjectTypeName); //Step 2: export the objects PickListAutoComplete pl = PickListAutoComplete.GetList("**", "vendor"); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Vendor c = Vendor.GetItem(i.ID); var ObjectTID = new TypeAndID(RootObjectTypes.Vendor, c.ID); dynamic d = new JObject(); d.name = GetUniqueName(c.Name); if (IsDuplicateMapItem(c.ID, c.Name, progress)) continue; progress.Op(ObjectTypeName + " " + d.name); d.active = c.Active; d.notes = c.Notes; SetTags(d, tags); //Custom fields? if (ShouldExportCustom) d.customFields = CustomFieldData(c, DateCustomFields); var rMainObject = await util.PostAsync(ObjectTypeName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); //Attachments / FILES await ExportAttachments(ObjectTID, progress); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified d.login = null; d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(ObjectTypeName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.Vendor, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); } } #endregion Vendors #region Service Workorders private async System.Threading.Tasks.Task ExportServiceWorkorders(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Service workorders export"); progress.SubOp(""); var ObjectTypeName = "Workorder"; var RavenRouteName = "workorders"; //TODO: this in the workorder Items loop //Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too var ocf = ObjectHasCustomFieldDataToExport("WorkorderItem"); bool ShouldExportCustom = ocf != null; var DateCustomFields = await ExportCustomFieldSchema(ocf, "WorkorderItem", "WorkOrderItem"); //Step 2: export the objects //sort by woid var crit = @" "; WorkorderServiceList pl = WorkorderServiceList.GetList(crit); progress.Append("Exporting " + pl.Count.ToString() + " Service " + ObjectTypeName + "s"); foreach (WorkorderServiceList.WorkorderServiceListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Workorder c = Workorder.GetItem(i.LT_O_Workorder.Value); if (IsDuplicateMapItem(c.ID, c.WorkorderService.ServiceNumber.ToString(), progress)) continue; var ObjectTID = new TypeAndID(RootObjectTypes.WorkorderService, c.ID); dynamic d = new JObject(); //d.concurrencyToken = util.CTokenFromResponse(rMainObject); progress.Op(ObjectTypeName + " " + c.WorkorderService.ServiceNumber); d.active = true;//probably can remove this at server, just stubbed in for now Tagit(c.RegionID, tags); SetTags(d, tags); var rMainObject = await util.PostAsync(RavenRouteName, d.ToString()); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); d = rMainObject.ObjectResponse["data"]; d.serial = c.WorkorderService.ServiceNumber; d.notes = c.Summary; //Attachments / FILES await ExportAttachments(ObjectTID, progress, util.AyaType.WorkOrder); //----- // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress, util.AyaType.WorkOrder); if (!string.IsNullOrEmpty(NonFileUrls)) { ////need to repost the user with the notes modified //d.login = null; //d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; } //put the final object await util.PutAsync(RavenRouteName, d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.WorkOrder, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); //iterate all workorder items foreach (WorkorderItem wi in c.WorkorderItems) { dynamic dwi = new JObject(); dwi.workOrderId = RavenId; // d.concurrencyToken = util.CTokenFromResponse(rMainObject); progress.Op("WorkorderItem " + wi.ID.ToString()); dwi.active = true;//probably can remove this at server, just stubbed in for now Tagit(wi.TypeID, tags); Tagit(wi.WorkorderItemUnitServiceTypeID, tags); SetTags(dwi, tags); ////Custom fields? if (ShouldExportCustom) dwi.customFields = CustomFieldData(wi, DateCustomFields); dwi.notes = "Summary:\n" + wi.Summary + "TechNotes: \n" + wi.TechNotes; await util.PostAsync("workorders/items", dwi.ToString()); //and rest of tree below here... } } } #endregion Workorders #region Quote Workorders private async System.Threading.Tasks.Task ExportQuotes(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Quotes export"); progress.SubOp(""); var ObjectTypeName = "Quote"; var RavenObjectName = "Quote"; //TODO: this in the workorder Items loop ////Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too //var ocf = ObjectHasCustomFieldDataToExport("WorkorderItem"); //bool ShouldExportCustom = ocf != null; //var DateCustomFields = await ExportCustomFieldSchema(ocf, "WorkorderItem", "WorkOrderItem"); //Step 2: export the objects WorkorderQuoteList pl = WorkorderQuoteList.GetList(""); progress.Append("Exporting " + pl.Count.ToString() + " " + ObjectTypeName + "s"); foreach (WorkorderQuoteList.WorkorderQuoteListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Workorder c = Workorder.GetItem(i.LT_O_WorkorderQuote.Value); if (IsDuplicateMapItem(c.ID, c.WorkorderQuote.QuoteNumber.ToString(), progress)) continue; var ObjectTID = new TypeAndID(RootObjectTypes.WorkorderQuote, c.ID); //make one on the server to update var rMainObject = await util.PostAsync(RavenObjectName + "/Create?serial=" + c.WorkorderQuote.QuoteNumber); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); dynamic d = new JObject(); d.concurrencyToken = util.CTokenFromResponse(rMainObject); progress.Op(ObjectTypeName + " " + c.WorkorderQuote.QuoteNumber); d.active = true;//probably can remove this at server, just stubbed in for now Tagit(c.RegionID, tags); SetTags(d, tags); ////Custom fields? //if (ShouldExportCustom) // d.customFields = CustomFieldData(c, DateCustomFields); // var rMainObject = await util.PostAsync(RavenObjectName, d.ToString()); //Attachments / FILES await ExportAttachments(ObjectTID, progress, util.AyaType.Quote); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress, util.AyaType.Quote); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified //d.login = null; //d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(RavenObjectName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.WorkOrder, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); //todo: workorder items etc } } #endregion Quotes #region PM Workorders private async System.Threading.Tasks.Task ExportPMs(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Preventive Maintenance export"); progress.SubOp(""); var ObjectTypeName = "Preventive Maintenance"; var RavenObjectName = "PM"; //TODO: this in the workorder Items loop ////Step 1: export the CustomFields to FormCustom if applicable so that when doing individual items we can export their custom data too //var ocf = ObjectHasCustomFieldDataToExport("WorkorderItem"); //bool ShouldExportCustom = ocf != null; //var DateCustomFields = await ExportCustomFieldSchema(ocf, "WorkorderItem", "WorkOrderItem"); //Step 2: export the objects WorkorderPMList pl = WorkorderPMList.GetList(""); progress.Append("Exporting " + pl.Count.ToString() + " Service " + ObjectTypeName + "s"); foreach (WorkorderPMList.WorkorderPMListInfo i in pl) { if (!progress.KeepGoing) return; List tags = new List(); tags.Add(ImportTag); Workorder c = Workorder.GetItem(i.LT_O_WorkorderPreventiveMaintenance.Value); if (IsDuplicateMapItem(c.ID, c.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber.ToString(), progress)) continue; var ObjectTID = new TypeAndID(RootObjectTypes.WorkorderPreventiveMaintenance, c.ID); //make one on the server to update var rMainObject = await util.PostAsync(RavenObjectName + "/Create?serial=" + c.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber); long RavenId = util.IdFromResponse(rMainObject); AddMap(c.ID, RavenId); dynamic d = new JObject(); d.concurrencyToken = util.CTokenFromResponse(rMainObject); progress.Op(ObjectTypeName + " " + c.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber); d.active = true;//probably can remove this at server, just stubbed in for now Tagit(c.RegionID, tags); SetTags(d, tags); ////Custom fields? //if (ShouldExportCustom) // d.customFields = CustomFieldData(c, DateCustomFields); // var rMainObject = await util.PostAsync(RavenObjectName, d.ToString()); //Attachments / FILES await ExportAttachments(ObjectTID, progress, util.AyaType.PM); //----- bool repost = false; d = rMainObject.ObjectResponse["data"]; // wiki if (WikiPage.HasWiki(c.ID)) { // await ExportAttachments(ObjectTID, progress); d.wiki = GetWikiContent(ObjectTID); repost = true; } //docs string NonFileUrls = await ExportDocs(ObjectTID, c.Docs, progress, util.AyaType.PM); if (!string.IsNullOrEmpty(NonFileUrls)) { //need to repost the user with the notes modified //d.login = null; //d.password = null; d.notes = NonFileUrls + "\n-----------------\n" + d.notes; repost = true; } if (repost) await util.PutAsync(RavenObjectName + "/" + RavenId.ToString(), d.ToString()); //----- //Event log fixup await util.EventLog(util.AyaType.WorkOrder, RavenId, SafeGetUserMap(c.Creator), SafeGetUserMap(c.Modifier), c.Created, c.Modified); //todo: workorder items etc } } #endregion PM Workorders #region locales private async System.Threading.Tasks.Task ExportLocales(ProgressForm progress) { if (!progress.KeepGoing) return; progress.Op("Start Locales export"); progress.SubOp(""); progress.Append("Exporting customized Locales"); ////checksum locales ////if a recognized checksum then don't import because it means it wasn't modified from stock ///* // Stock fresh trial db (fb) values: // Locale Custom English [signature: -1965948581] // Locale Deutsch [signature: -564065723] // Locale English [signature: -1965948581] // Locale Español [signature: -1122936791] // Locale Français [signature: -679171126] //Do not use these keys in hash calculation which were added / modified during various schema updates // Global.Label.UseInventory.Description // Locale.Label.LocaleFile // UnitNameDisplayFormats.Label.ModelSerial // UnitNameDisplayFormats.Label.SerialModel // UnitNameDisplayFormats.Label.SerialModelVendor // UnitNameDisplayFormats.Label.VendorModelSerial // O.PartBin //*/ //List StockLocaleHashes = new List(); //StockLocaleHashes.Add(-1965948581); //StockLocaleHashes.Add(-564065723); //StockLocaleHashes.Add(-1122936791); //StockLocaleHashes.Add(-679171126); //Get a list of RAVEN translations and ID's var a = await util.GetAsync("Translation/List"); JArray ja = (JArray)a.ObjectResponse["data"]; var RavenLanguageList = ja.ToObject>(); LocaleList l = LocaleList.GetList(); foreach (LocaleList.LocaleListInfo i in l) { ResetUniqueNames(); if (!progress.KeepGoing) return; LocalizedTextTable lt = LocalizedTextTable.Load(i.Locale); progress.Op("Checking if locale " + i.Locale + " is customized"); if (!util.LocaleIsCustomized(i.Locale, lt, progress)) continue; ////calculate hash //List allStrings = new List(); //foreach (var entry in lt.LT) //{ // if(entry.Key=="Global.Label.UseInventory.Description") continue; // if(entry.Key=="Locale.Label.LocaleFile") continue; // if(entry.Key=="UnitNameDisplayFormats.Label.ModelSerial") continue; // if(entry.Key=="UnitNameDisplayFormats.Label.SerialModel") continue; // if(entry.Key=="UnitNameDisplayFormats.Label.SerialModelVendor") continue; // if(entry.Key=="UnitNameDisplayFormats.Label.VendorModelSerial") continue; // if (entry.Key == "O.PartBin") continue; // allStrings.Add(entry.Value); //} //int CurrentLocaleHash = util.GetOrderIndependentHashCode(allStrings); //allStrings.Clear(); //if (StockLocaleHashes.Contains(CurrentLocaleHash)) continue; //progress.Append("Locale " + i.Locale + " is customized [signature: "+CurrentLocaleHash.ToString()+"]; exporting"); //collection to hold items sent to server List exportItems = new List(); //Iterate all RAVEN languages for (int x = 1; x < 5; x++)//first four translations are the stock ones { //get raven name of locale var RavenLocaleName = RavenLanguageList.Find(m => m.Id == x).Name; //add stock locale mappings in case users are set to a stock one in v7 //so can set them later //this is some half baked shit,it's intended for when users are exported later but it only works with stock locales //so..not sure the exact point, maybe should just default all to english and let admin fix them later //as they likely will have to anyway. Harmless though I guess so keeping switch (RavenLocaleName) { case "en": if (!LocaleMap.ContainsKey("English")) LocaleMap.Add("English", x); break; case "fr": if (!LocaleMap.ContainsKey("Français")) LocaleMap.Add("Français", x); break; case "de": if (!LocaleMap.ContainsKey("Deutsch")) LocaleMap.Add("Deutsch", x); break; case "es": if (!LocaleMap.ContainsKey("Español")) LocaleMap.Add("Español", x); break; } //MAKE A DUPLICATE //name like this: "My custom (Espanol)" etc one for each target stock language var exportName = GetUniqueName(i.Locale + " (" + RavenLocaleName + ")"); progress.SubOp(""); progress.Op("Exporting " + i.Locale + " to " + exportName); var t = new util.NameIdItem { Name = exportName, Id = x }; a = await util.PostAsync("Translation/Duplicate", JObject.FromObject(t).ToString()); var targetTranslationId = util.IdFromResponse(a); var ctoken = util.CTokenFromResponse(a); //add to maps so can set user to it on export //going to default to the English based one because //that's the majority of the users if (RavenLocaleName == "en" && !LocaleMap.ContainsKey(i.Locale)) LocaleMap.Add(i.Locale, targetTranslationId); //Ok, have our target locale created, not we need to insert our custom translations one by one var trans = ((JArray)a.ObjectResponse["data"]["translationItems"]).ToObject>(); var DuplicateAvoidanceList = new List(); //SET MATCHING KEYS TO OUR TEXT //iterate v7 locale items foreach (var v7item in lt.LT) { progress.SubOp("Processing key: " + v7item.Key); var v8key = Translatev7TranslationKey(v7item.Key); if (v8key == "**SKIP**") continue; if (!DuplicateAvoidanceList.Contains(v8key)) { DuplicateAvoidanceList.Add(v8key); } else continue; //System.Diagnostics.Debug.WriteLine("v7key:" + v7item.Key + " -> v8key: " + v8key); TranslationItem v8TransItem = trans.FirstOrDefault(m => m.Key == v8key); if (v8TransItem == null) { throw new ArgumentOutOfRangeException("On exporting custom locale " + i.Locale + " source key " + v7item.Key + ", destination key " + v8key + " was not found."); } //collect exportItems.Add(new UpdateTranslationItem { Id = v8TransItem.Id, ConcurrencyToken = v8TransItem.ConcurrencyToken, NewText = v7item.Value }); } //update it progress.SubOp("Posting translation " + exportName + " to server "); await util.PutAsync("Translation/UpdateTranslationItemsDisplayText", JArray.FromObject(exportItems).ToString()); progress.Op(""); progress.SubOp(""); } } progress.Op(""); progress.SubOp(""); } #region locale utility public class TranslationItem { public long Id { get; set; } public uint ConcurrencyToken { get; set; } public string Key { get; set; } public string Display { get; set; } public long TranslationId { get; set; } } public class UpdateTranslationItem { public long Id { get; set; } public uint ConcurrencyToken { get; set; } public string NewText { get; set; } } /// /// Used by import, translate the old v7 translation key name into the new shorter version /// /// /// public string Translatev7TranslationKey(string oldKey) { //skip keys definitely not in destination //swaths: if (oldKey.StartsWith("UI.ToolBar.")) return "**SKIP**"; if (oldKey.StartsWith("UI.Toolbar.")) return "**SKIP**"; // Custom English source key UI.Toolbar.ClientsToolBar, destination key ToolbarClientsToolBar was not found. switch (oldKey) { // case "XXXX": case "O.WikiPage": //skip over wikipage it's been dropped as it's an international term case "UI.Command.LocalizedTextDesign": case "O.WorkorderItemOutsideService": case "O.WorkorderService.CloseByDate": case "UI.Label.CurrentUserName": case "UI.Go.Search": case "ClientRequestTech.Label.ClientServiceRequestItemID": return "**SKIP**"; } string s = oldKey.Replace(".Label.", "."); if (s.StartsWith("O.")) s = s.Replace("O.", ""); s = s.Replace(".ToolBar.", "."); s = s.Replace(".Go.", "."); s = s.Replace(".Command.", "."); s = s.Replace(".Error.", "."); s = s.Replace(".Object.", "."); if (s.StartsWith("UI.")) s = s.Replace("UI.", ""); s = s.Replace(".", ""); s = s.Replace("AddressAddress", "Address"); s = s.Replace("ContactPhoneContactPhone", "ContactPhone"); s = s.Replace("ContactPhonePhone", "ContactPhone"); s = s.Replace("PurchaseOrderPurchaseOrder", "PurchaseOrder"); s = s.Replace("WorkorderItemMiscExpenseExpense", "WorkorderItemMiscExpense"); s = s.Replace("WorkorderItemTravelTravel", "WorkorderItemTravel"); s = s.Replace("DashboardDashboard", "Dashboard"); //ScheduleMarkers -> Reminder s = s.Replace("ScheduleMarkerScheduleMarker", "ScheduleMarker"); s = s.Replace("ScheduleMarker", "Reminder"); s = s.Replace("ScheduleMarkerARGB", "ReminderARGB"); s = s.Replace("ScheduleMarkerColor", "ReminderColor"); s = s.Replace("ScheduleMarkerCompleted", "ReminderCompleted"); s = s.Replace("ScheduleMarkerEventCreated", "ReminderEventCreated"); s = s.Replace("ScheduleMarkerEventPendingAlert", "ReminderEventPendingAlert"); s = s.Replace("ScheduleMarkerFollowUp", "ReminderFollowUp"); s = s.Replace("ScheduleMarkerList", "ReminderList"); s = s.Replace("ScheduleMarkerName", "ReminderName"); s = s.Replace("ScheduleMarkerNotes", "ReminderNotes"); s = s.Replace("ScheduleMarkerRecurrence", "ReminderRecurrence"); s = s.Replace("ScheduleMarkerScheduleMarkerSourceType", "ReminderSourceType"); s = s.Replace("ScheduleMarkerSourceID", "ReminderSourceID"); s = s.Replace("ScheduleMarkerStartDate", "ReminderStartDate"); s = s.Replace("ScheduleMarkerStopDate", "ReminderStopDate"); s = s.Replace("ScheduleEditScheduleMarker", "ScheduleEditReminder"); s = s.Replace("ScheduleNewScheduleMarker", "ScheduleNewReminder"); //Custom fields were 0 to 9, now 1 to 16 s = s.Replace("Custom9", "Custom10"); s = s.Replace("Custom8", "Custom9"); s = s.Replace("Custom7", "Custom8"); s = s.Replace("Custom6", "Custom7"); s = s.Replace("Custom5", "Custom6"); s = s.Replace("Custom4", "Custom5"); s = s.Replace("Custom3", "Custom4"); s = s.Replace("Custom2", "Custom3"); if (!s.EndsWith("Custom10")) s = s.Replace("Custom1", "Custom2"); s = s.Replace("Custom0", "Custom1"); //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"); s = s.Replace("UserUserType", "UserType"); s = s.Replace("UserTypesUtilityNotification", "UserTypesUtility"); //Localized -> Translation s = s.Replace("LocaleCustomizeText", "TranslationCustomizeText"); s = s.Replace("LocaleExport", "TranslationExport"); s = s.Replace("LocaleImport", "TranslationImport"); s = s.Replace("LocaleList", "TranslationList"); s = s.Replace("LocaleLocaleFile", "TranslationFile"); s = s.Replace("LocaleUIDestLocale", "TranslationDest"); s = s.Replace("LocaleUISourceLocale", "TranslationSource"); s = s.Replace("LocaleWarnLocaleLocked", "TranslationWarnLocked"); s = s.Replace("LocalizedTextDisplayText", "TranslationDisplayText"); s = s.Replace("LocalizedTextDisplayTextCustom", "TranslationDisplayTextCustom"); s = s.Replace("LocalizedTextKey", "TranslationKey"); s = s.Replace("LocalizedTextLocale", "Translation"); s = s.Replace("LocalizedText", "TranslatedText"); //items that came up after moving this to v8 export plugin s = s.Replace("DateRangeInTheLastYear", "DateRangePastYear"); s = s.Replace("ToolbarCustomizeDialog", "CustomizeDialog"); s = s.Replace("Client", "Customer"); s = s.Replace("LoanItem", "LoanUnit"); s = s.Replace("WorkorderPreventiveMaintenance", "PM"); s = s.Replace("WorkorderQuote", "Quote"); s = s.Replace("WorkorderService", "Workorder"); s = s.Replace("Workorder", "WorkOrder"); s = s.Replace("CustomerNoteCustomerNoteTypeID", "CustomerNoteTypeId"); s = s.Replace("CustomerRequestPartCustomerServiceRequestItemID", "CustomerRequestItemId"); s = s.Replace("WorkOrderItemMiscExpense", "WorkOrderItemExpense"); s = s.Replace("WorkOrderItemLoanLoan", "WorkOrderItemLoan"); s = s.Replace("WorkOrderItemLaborLabor", "WorkOrderItemLabor"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); //FUTURE // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); // s = s.Replace("WASXXX", "NOWXXXX"); return s; } #endregion locale utility #endregion locales #region TAG ITEMS #region Unitmodelcategories private void ExportUnitModelCategories(ProgressForm progress) { ResetUniqueNames(); UnitModelCategories l = UnitModelCategories.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Unit model categories"); foreach (UnitModelCategory i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "unitmodelcategory")); } #endregion #region Unitservicetypes private void ExportUnitServiceTypes(ProgressForm progress) { ResetUniqueNames(); UnitServiceTypes l = UnitServiceTypes.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Unit service types"); foreach (UnitServiceType i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "unitservicetype")); } #endregion #region WorkorderItemTypes private void ExportWorkorderItemTypes(ProgressForm progress) { ResetUniqueNames(); WorkorderItemTypes l = WorkorderItemTypes.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Workorder item types"); foreach (WorkorderItemType i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "workorderitemtype")); } #endregion #region REGIONS private void ExportRegions(ProgressForm progress) { ResetUniqueNames(); RegionList l = RegionList.GetList(string.Empty); progress.Append("Compiling " + l.Count.ToString() + " Regions"); foreach (RegionList.RegionListInfo i in l) TagMap.Add(i.LT_Region_Label_Name.Value, util.NormalizeTag(GetUniqueName(i.LT_Region_Label_Name.Display) + "." + "region")); } #endregion #region Client groups private void ExportClientGroups(ProgressForm progress) { ResetUniqueNames(); ClientGroups l = ClientGroups.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Client groups"); foreach (ClientGroup i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "clientgroup")); } #endregion #region Workorder categories private void ExportWorkorderCategories(ProgressForm progress) { ResetUniqueNames(); WorkorderCategories l = WorkorderCategories.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Workorder categories"); foreach (WorkorderCategory i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "workordercategory")); } #endregion #region Part categories private void ExportPartCategories(ProgressForm progress) { ResetUniqueNames(); PartCategories l = PartCategories.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " Part categories"); foreach (PartCategory i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "partcategory")); } #endregion #region ScheduleableUserGroups private void ExportScheduleableUserGroups(ProgressForm progress) { ResetUniqueNames(); ScheduleableUserGroupPickList pl = ScheduleableUserGroupPickList.GetList(); progress.Append("Compiling " + pl.Count.ToString() + " Scheduleable user groups"); foreach (ScheduleableUserGroupPickList.ScheduleableUserGroupPickListInfo i in pl) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "partcategory")); } #endregion clients #region Dispatch zones private void ExportDispatchZones(ProgressForm progress) { ResetUniqueNames(); DispatchZones l = DispatchZones.GetItems(false); progress.Append("Compiling " + l.Count.ToString() + " Dispatch zones"); foreach (DispatchZone i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "dispatchzone")); } #endregion private void ExportUserSkills(ProgressForm progress) { ResetUniqueNames(); UserSkills l = UserSkills.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " User skills"); foreach (UserSkill i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "user-skill")); } private void ExportUserCertifications(ProgressForm progress) { ResetUniqueNames(); UserCertifications l = UserCertifications.GetItems(); progress.Append("Compiling " + l.Count.ToString() + " User certifications"); foreach (UserCertification i in l) TagMap.Add(i.ID, util.NormalizeTag(GetUniqueName(i.Name) + "." + "user-certification")); } #endregion TAG ITEMS //-------------------------------------------- #endregion object export #region Custom fields exporter //export objects custom field data into jobject string private string CustomFieldData(object biz, List dateFields) { dynamic d = new JObject(); for (int x = 0; x < 10; x++) { object o = (object)biz.GetType().GetProperty("Custom" + x.ToString()).GetValue(biz, null); string s = o.ToString(); if (string.IsNullOrWhiteSpace(s)) { s = null; } if (s != null && dateFields.Contains(x)) { //parse out to UTC date DateTime dt = new DateTime(); if (DateTime.TryParse(s, out dt)) { s = dt.ToUniversalTime().ToString("s"); } } if (!string.IsNullOrWhiteSpace(s)) d["c" + (x + 1).ToString()] = s; } return d.ToString(); } static public ObjectCustomFields ObjectHasCustomFieldDataToExport(string sObject) { ObjectCustomFields ocf = ObjectCustomFields.GetItems(sObject); if (ocf.Count == 0) { return null; } foreach (ObjectCustomField f in ocf) { if (f.Visible) return ocf; } return null; } private async System.Threading.Tasks.Task> ExportCustomFieldSchema(ObjectCustomFields ocf, string v7CustomFieldObjectName, string RavenCustomTranslationKeyObjectName) { var ret = new List(); if (ocf == null) return ret; //NOTE: this code inspired by winforApp::Util.cs PrepareCustomFieldsGrid method dynamic d = new JObject(); d.formkey = RavenCustomTranslationKeyObjectName; dynamic dtemplate = new JArray(); foreach (ObjectCustomField f in ocf) { if (f.Visible) { int n = Convert.ToInt32(f.FieldName.Replace("Custom", "")) + 1;//raven custom fields are 1 based, v7 are zero based //CustomFieldLocaleKeys.Add(RavenCustomTranslationKeyObjectName + n.ToString(), // util.LocaleText.GetLocalizedText(v7CustomFieldObjectName + ".Label." + f.FieldName)); dynamic dt = new JObject(); dt.fld = RavenCustomTranslationKeyObjectName + "Custom" + n.ToString(); dt.hide = false; dt.required = false; switch (f.FieldType) { case FormFieldDataTypes.Currency: dt.type = util.AyaUiFieldDataType.Currency; break; case FormFieldDataTypes.DateOnly: dt.type = util.AyaUiFieldDataType.Date; ret.Add(n - 1); break; case FormFieldDataTypes.DateTime: dt.type = util.AyaUiFieldDataType.DateTime; ret.Add(n - 1); break; case FormFieldDataTypes.Number: dt.type = util.AyaUiFieldDataType.Decimal; break; case FormFieldDataTypes.Text: dt.type = util.AyaUiFieldDataType.Text; break; case FormFieldDataTypes.TimeOnly: dt.type = util.AyaUiFieldDataType.Time; ret.Add(n - 1); break; case FormFieldDataTypes.TrueFalse: dt.type = util.AyaUiFieldDataType.Bool; break; default: dt.type = util.AyaUiFieldDataType.Text; break; } dtemplate.Add(dt); } } d.template = dtemplate.ToString(); //ok, were here because there *are* custom fields available var a = await util.GetAsync("FormCustom/" + RavenCustomTranslationKeyObjectName); var ctoken = util.CTokenFromResponse(a); d.concurrencyToken = ctoken; await util.PutAsync("FormCustom/" + RavenCustomTranslationKeyObjectName, d.ToString()); return ret; } #endregion custom fields #region Attachments exporter private async System.Threading.Tasks.Task ExportAttachments(TypeAndID tid, ProgressForm progress, util.AyaType specificRavenType = util.AyaType.NoType) { if (!WikiPage.HasWiki(tid.ID)) return; WikiPage w = WikiPage.GetItem(tid); AyaFileList fl = AyaFileList.GetList(w.ID); if (fl.Count == 0) return; //iterate the files foreach (AyaFileList.AyaFileListInfo i in fl) { if (!progress.KeepGoing) return; var af = AyaFile.GetItem(i.LT_O_AyaFile.Value); if (af == null) continue; progress.SubOp("Wikifile: \"" + af.Name + "\" " + AyaBizUtils.FileSizeDisplay((decimal)af.FileSize)); if (IsDuplicateMapItem(i.LT_O_AyaFile.Value, i.LT_O_AyaFile.Display, progress)) continue; //Compile the FileData property var sDate = i.LT_Common_Label_Created.ToString(); DateTimeOffset dtLastModified = DateTime.UtcNow; if (sDate != null) { //parse out to UTC date DateTime dt = new DateTime(); if (DateTime.TryParse(sDate, out dt)) { dtLastModified = dt.ToUniversalTime(); } } dynamic dFileData = new JArray(); dynamic dFile = new JObject(); dFile.name = af.Name; dFile.lastModified = dtLastModified.ToUnixTimeMilliseconds(); dFileData.Add(dFile); //Upload MultipartFormDataContent formDataContent = new MultipartFormDataContent(); //Form data like the bizobject type and id string RavenTypeAsString = ""; if (specificRavenType != util.AyaType.NoType) RavenTypeAsString = ((int)specificRavenType).ToString(); else RavenTypeAsString = ((int)util.RootObjectToAyaType(tid.RootObjectType)).ToString(); formDataContent.Add(new StringContent(RavenTypeAsString), name: "AttachToObjectType"); formDataContent.Add(new StringContent(Map[tid.ID].ToString()), name: "AttachToObjectId"); formDataContent.Add(new StringContent(ImportTag), name: "Notes"); formDataContent.Add(new StringContent(dFileData.ToString()), name: "FileData"); StreamContent AttachmentFile = new StreamContent(af.GetContent()); //try to get a more accurate mimetype than was originally //in v7 as it uses the same method but from long ago and far far away... string MType = af.mimeType; try { MType = MimeTypeMap.GetMimeType(Path.GetExtension(af.Name));//latest up to date mime type } catch { } AttachmentFile.Headers.ContentType = new MediaTypeHeaderValue(MType); AttachmentFile.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data"); AttachmentFile.Headers.ContentDisposition.FileName = af.Name; AttachmentFile.Headers.ContentDisposition.ModificationDate = dtLastModified; formDataContent.Add(AttachmentFile); //Upload var a = await util.PostFormDataAsync("Attachment", formDataContent); //Map it for later processing of wiki //attachment upload route returns all attachments for this object in file name order //so need to find *our* most recent uploaded attachment so need to find the highest raven id number var returnArray = ((JArray)a.ObjectResponse["data"]); var ravenId = -1L; foreach (JObject o in returnArray) { var oId = o["id"].Value(); if (oId > ravenId) ravenId = oId; } AddMap(af.ID, ravenId); } progress.SubOp(""); } #endregion attachments #region Assigned docs exporter private async System.Threading.Tasks.Task ExportDocs(TypeAndID tid, AssignedDocs docs, ProgressForm progress, util.AyaType specificRavenType = util.AyaType.NoType) { if (!ExportAssignedDocs) return null; if (docs.Count == 0) return null; string NonFileUrls = string.Empty; //iterate the files foreach (AssignedDoc doc in docs) { if (!progress.KeepGoing) return null; //is it a local file? if (!new Uri(doc.URL).IsFile) { NonFileUrls += (doc.Description + "(" + ImportTag + ")\n" + doc.URL + "\n"); continue; } //can we see it? if (!File.Exists(doc.URL)) { NonFileUrls += (ImportTag + " - Assigned doc. file not found:\n" + doc.Description + "\n" + doc.URL + "\n"); continue; } //get the file info FileInfo fi = new FileInfo(doc.URL); progress.SubOp("Assigned doc: \"" + doc.URL + "\" " + AyaBizUtils.FileSizeDisplay((decimal)fi.Length)); //Compile the FileData property DateTimeOffset dtLastModified = fi.LastWriteTimeUtc; dynamic dFileData = new JArray(); dynamic dFile = new JObject(); dFile.name = fi.Name; dFile.lastModified = dtLastModified.ToUnixTimeMilliseconds(); dFileData.Add(dFile); //Upload MultipartFormDataContent formDataContent = new MultipartFormDataContent(); //Form data like the bizobject type and id string RavenTypeAsString = ""; if (specificRavenType != util.AyaType.NoType) RavenTypeAsString = ((int)specificRavenType).ToString(); else RavenTypeAsString = ((int)util.RootObjectToAyaType(tid.RootObjectType)).ToString(); formDataContent.Add(new StringContent(RavenTypeAsString), name: "AttachToObjectType"); formDataContent.Add(new StringContent(Map[tid.ID].ToString()), name: "AttachToObjectId"); formDataContent.Add(new StringContent(doc.Description + " (" + ImportTag + ")"), name: "Notes"); formDataContent.Add(new StringContent(dFileData.ToString()), name: "FileData"); StreamContent AttachmentFile = new StreamContent(fi.OpenRead()); AttachmentFile.Headers.ContentType = new MediaTypeHeaderValue(MimeTypeMap.GetMimeType(fi.Extension)); AttachmentFile.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data"); AttachmentFile.Headers.ContentDisposition.FileName = fi.Name; AttachmentFile.Headers.ContentDisposition.ModificationDate = dtLastModified; formDataContent.Add(AttachmentFile); //Upload await util.PostFormDataAsync("Attachment", formDataContent); //No need to map it or save response as long as it works that's all that matters } progress.SubOp(""); return NonFileUrls; } #endregion assigned docs #region WIKI page exporter //WIKI private string GetWikiContent(TypeAndID tid) { //may not exist // if (!WikiPage.HasWiki(tid.ID)) return null; WikiPage w = WikiPage.GetItem(tid); var content = w.GetContentAsString; if (string.IsNullOrWhiteSpace(content)) return null; //TODO: fixup internal urls using MAP of file attachment uploads MatchCollection mc = AyaBizUtils.rxAyaImageTags.Matches(content); foreach (Match m in mc) { var RavenId = Map[new Guid(m.Groups["guid"].Value)]; content = content.Replace(m.Value, ""); } //todo: fixup font size, try to convert to heading tags instead //figure out how to remove the inline style tag as it comes through for some reason //TODO: Convert to Markdown format //found 2 likely candidate libs to do this //https://www.nuget.org/packages/Html2Markdown/ //https://www.nuget.org/packages/ReverseMarkdown/ //Not much difference at first glance, very similar stats, reverse markdown is a little more widely used and seems to have more config options //built in, the other has to make some kind of processor for some stuff maybe so going with reverse for now //NOTE: for this to work had to add an assembly redirect in app.config for ayanova project as it was looking for a really old version of //the HtmlAgilityPack var config = new ReverseMarkdown.Config { UnknownTags = ReverseMarkdown.Config.UnknownTagsOption.Bypass, GithubFlavored = true, // generate GitHub flavoured markdown, supported for BR, PRE and table tags RemoveComments = true, // will ignore all comments, (narrator: "It doesn't") SmartHrefHandling = true // remove markdown output for links where appropriate }; var converter = new ReverseMarkdown.Converter(config); string res = converter.Convert(content); //strip out comment and style chunk that is left behind by above tool //style is an artifact of the rtf2html converter used by v7 int nStart = res.IndexOf(""); if (nStart != -1 && nEnd != -1) { res = res.Substring(0, nStart) + res.Substring(nEnd + 3); // res = newRes; } return res; } #region sample before and after /* * INPUT * Untitled document
Here is a title
 
This document has all possible options on it except for picking every single font size so instead here is the smallest font size which is 6
and here is the largest font size which is 150
 
italics and underlined and bold
 
red
 
green
 
blue
 
  • ·      List one
  • ·      list two
  • ·      list three
 
 
 
Arial font
 
Consolas font
 
Comic  sans
 
font size 16 double default size whih is 8
 
font size 32 which is quadruple default of 8
 
 
This block is
left aligned
 
 
this block is
center aligned
 
This block is
right aligned
 
 
 
 Wiki page - User: AyaNova Administrator
 
and more:
 
and more
 
 
======================================== Untitled document
Wiki page - User: Eva Alexander - ALL REGIONS
Here is some under title text
 
Here is another title
 
Here is some more under title text.
Some more lines
like this one
and this one
 
=-=-=-==- * * * output * Untitled document **Here is a title** This document has all possible options on it except for picking every single font size so instead here is the smallest font size which is 6 and here is the largest font size which is 150 *italics*and underlined and **bold** **red** **green** **blue** - **·****List one** - **·****list two** - **·****list three** Arial font Consolas font Comic  sans font size 16 double default size whih is 8 font size 32 which is quadruple default of 8 This block is left aligned this block is center aligned This block is right aligned ![]([ATTACH:4])Wiki page - User: AyaNova Administrator and more: ![]([ATTACH:4]) and more ![]([ATTACH:4]) ========================= Untitled document Wiki page - User: Eva Alexander - ALL REGIONS Here is some under title text Here is another title Here is some more under title text. Some more lines like this one and this one * */ #endregion sample #endregion wiki #region TAGS private void Tagit(Guid g, List tags) { if (g == Guid.Empty) return; if (!TagMap.ContainsKey(g)) return; var t = TagMap[g]; if (!string.IsNullOrWhiteSpace(t)) { tags.Add(t); } } private void SetTags(dynamic d, List tags) { dynamic dtags = new JArray(); foreach (string s in tags) dtags.Add(s); d.tags = dtags; } #endregion tags #region OLD JSON EXPORT STUFF #region Global settings private void ExportGlobalSettings(ProgressForm progress) { progress.Append("STUB: Dumping Global Settings"); ////DumpObjectToFolder(tempArchiveFolder, AyaBizUtils.GlobalSettings, "globalsettings", objectExcludeProperties, new TypeAndID(RootObjectTypes.Global, Address.GlobalAddressID)); } #endregion globalsettings #region Seeds private class GZSeeds { public int InventoryAdjustmentStartSeed = 1; public int PurchaseOrderStartSeed = 1; public int QuoteNumberStartSeed = 1; public int WorkorderNumberStartSeed = 1; public int PreventiveMaintenanceNumberStartSeed = 1; } private void ExportSeedNumbers(ProgressForm progress) { // List objectExcludeProperties = new List(standardExcludePropertiesList); progress.Append("Dumping seeds"); //create a new object with the id numbers in it and then dump it WorkorderPMList pml = WorkorderPMList.GetList(" \r\n" + " \r\n" + " \r\n" + " "); int PMStartSeed = 0; if (pml.Count > 0) { PMStartSeed = int.Parse(pml[0].LT_O_WorkorderPreventiveMaintenance.Display); } var seeds = new GZSeeds(); seeds.InventoryAdjustmentStartSeed = AyaBizUtils.GlobalSettings.InventoryAdjustmentStartSeed + 1; seeds.PurchaseOrderStartSeed = AyaBizUtils.GlobalSettings.PurchaseOrderStartSeed + 1; seeds.QuoteNumberStartSeed = AyaBizUtils.GlobalSettings.QuoteNumberStartSeed + 1; seeds.WorkorderNumberStartSeed = AyaBizUtils.GlobalSettings.WorkorderNumberStartSeed + 1; seeds.PreventiveMaintenanceNumberStartSeed = PMStartSeed + 1; //DumpObjectToFolder(tempArchiveFolder, seeds, "seeds", objectExcludeProperties, TypeAndID.Empty, "GZTW.AyaNova.BLL.Seed"); } #endregion globalsettings #region contract resolver //public class ExcludeNamedPropertiesContractResolver : DefaultContractResolver //{ // private readonly List _excludeProperties; // public ExcludeNamedPropertiesContractResolver(List excludeProperties) // { // _excludeProperties = excludeProperties; // } // protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) // { // IList properties = base.CreateProperties(type, memberSerialization); // // only serializer properties that start with the specified character // //properties = properties.Where(p => p.PropertyName.StartsWith(_startingWithChar.ToString())).ToList(); // properties = properties.Where(p => !_excludeProperties.Contains(p.PropertyName)).ToList(); // return properties; // } //} #endregion contract resolver //private static string EnsureValidFileName(string fileName) //{ // //make lower and replace spaces with dashes // fileName = fileName.ToLowerInvariant().Replace(" ", "-"); // //ensure each character is a valid path character // foreach (char c in System.IO.Path.GetInvalidFileNameChars()) // { // fileName = fileName.Replace(c, '_'); // } // return fileName; //} //private static void makeFolderIfNotExist(string fldr, bool shouldNotExist = false) //{ // if (Directory.Exists(fldr)) // { // if (shouldNotExist) // throw new System.Exception("Error: path already exists and shouldn't:\r\n" + fldr); // return; // } // Directory.CreateDirectory(fldr); //} //private List standardExcludePropertiesList //{ // get // { // return new List() // { // "CanWiki", // "CanDuplicate", // "IsValid", // "IsDirty", // "CurrentUserID", // "IsEditing", // "IsNew", // "IsDeleted", // "IsSavable", // "Notify", // "BrokenRulesText", // "Docs", // "MapQuestURL", // "FullAddress" // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX", // //"XXX" // }; // } //} #endregion old //eoc } //eons }