using System; using System.Collections.Generic; using System.Linq; using System.Text; 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 ICSharpCode.SharpZipLib.Zip; namespace AyaNova.Plugin.Dump { class Dump : IAyaNovaPlugin { #region Plugin interface System.Resources.ResourceManager resman = null; private static List ObjectsWeCanDealWith = null; public string PluginName { get { return "DBDump export database"; } } public string PluginVersion { get { return "7.5"; } } public string About { get { return "AyaNova DBDump plugin\r\n" + "Built " + AyaNova.PlugIn.Dump.Timestamp.BuildAt.ToString() + "\r\n" + "Copyright 2018 Ground Zero Tech-Works Inc."; } } public Guid PluginID { get { return new Guid("{73D7B77F-C96A-4198-9449-6529AFB6AA5B}"); } } 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("This DBDump plugin requires AyaNova version 7.5 or newer"); return false; } if (AyaNovaVersion.Minor < 5) { MessageBox.Show("This DBDump plugin requires AyaNova version 7.5 or newer"); return false; } 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("DBDump", "Dump database to export file", 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) { if (!User.CurrentUserIsAnAdministrator) { MessageBox.Show("This action can only be done by the AyaNova Administrator account"); return; } 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 could 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 could result in damaged data. ***"); } //Only one command DumpIt(); } #endregion /// /// 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 void DumpIt() { string dumpname = "ayanova.data.dump." + DateTime.Now.ToString("yyyy-MM-d--HH-mm-ss"); string dumpfolder = string.Empty; #if(DEBUG) dumpfolder = @"c:\temp"; #else MessageBox.Show("Select a location to dump AyaNova data"); using (var folderDialog = new FolderBrowserDialog()) { if (folderDialog.ShowDialog() == DialogResult.OK) { dumpfolder = folderDialog.SelectedPath; } else { return; } } #endif //create a temporary folder to generate JSON in string tempArchiveFolder = dumpfolder + Path.DirectorySeparatorChar + dumpname; string zipName = dumpfolder + Path.DirectorySeparatorChar + dumpname + ".zip"; makeFolderIfNotExist(tempArchiveFolder, true); //Show progress form ProgressForm progress = new ProgressForm(); progress.Show(); progress.StartedImport(); progress.Append("Dumping data to " + tempArchiveFolder); //DUMP IT! dumpUsers(tempArchiveFolder, progress); dumpGlobalSettings(tempArchiveFolder, progress); dumpLocales(tempArchiveFolder, progress); dumpRegions(tempArchiveFolder, progress); dumpSeedNumbers(tempArchiveFolder, progress); dumpClients(tempArchiveFolder, progress); dumpHeadOffices(tempArchiveFolder, progress); dumpUnitModelCategories(tempArchiveFolder, progress); dumpUnitServiceTypes(tempArchiveFolder, progress); dumpWorkorderItemTypes(tempArchiveFolder, progress); dumpClientGroups(tempArchiveFolder, progress); dumpWorkorderCategories(tempArchiveFolder, progress); dumpPartCategories(tempArchiveFolder, progress); dumpScheduleableUserGroups(tempArchiveFolder, progress); dumpDispatchZones(tempArchiveFolder, progress); progress.Append("Zipping up archive"); FastZip fastZip = new FastZip(); fastZip.CreateZip(zipName, tempArchiveFolder, true, null); progress.Append("Cleaning up temporary folder"); Directory.Delete(tempArchiveFolder, true); progress.Append("Dump completed"); progress.FinishedImport(); //----------------------------------- //endof method } #region Object dump methods #region Global settings private void dumpGlobalSettings(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); progress.Append("Dumping Global Settings"); DumpObjectToFolder(tempArchiveFolder, AyaBizUtils.GlobalSettings, "globalsettings", objectExcludeProperties); } #endregion globalsettings #region locales private void dumpLocales(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //Skip stock locales already handled in Raven List SkipLocales = new List(); SkipLocales.Add("Deutsch"); SkipLocales.Add("English"); SkipLocales.Add("Español"); SkipLocales.Add("Français"); LocaleList l = LocaleList.GetList(); progress.Append("Dumping " + l.Count.ToString() + " Locales"); foreach (LocaleList.LocaleListInfo i in l) { if (!SkipLocales.Contains(i.Locale)) { LocalizedTextTable lt = LocalizedTextTable.Load(i.Locale); DumpObjectToFolder(tempArchiveFolder, lt.LT, "locale." + EnsureValidFileName(i.Locale), objectExcludeProperties, "GZTW.AyaNova.BLL.Locale"); } } } #endregion locales #region REGIONS private void dumpRegions(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); objectExcludeProperties.Add("ContractName"); objectExcludeProperties.Add("uiHasTechNotes"); RegionList l = RegionList.GetList(string.Empty); progress.Append("Dumping " + l.Count.ToString() + " Regions"); foreach (RegionList.RegionListInfo i in l) { Region o = Region.GetItem(i.LT_Region_Label_Name.Value); DumpObjectToFolder(tempArchiveFolder, o, "region." + o.ID.ToString(), objectExcludeProperties); } } #endregion #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 dumpSeedNumbers(string tempArchiveFolder, 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, "GZTW.AyaNova.BLL.Seed"); } #endregion globalsettings #region clients private void dumpClients(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); objectExcludeProperties.Add("ContractName"); objectExcludeProperties.Add("uiHasTechNotes"); ClientPickList pl = ClientPickList.GetList(); progress.Append("Dumping " + pl.Count.ToString() + " Clients"); foreach (ClientPickList.ClientPickListInfo i in pl) { Client c = Client.GetItem(i.ID); DumpObjectToFolder(tempArchiveFolder, c, "client." + c.ID.ToString(), objectExcludeProperties); } } #endregion clients #region headoffices private void dumpHeadOffices(string tempArchiveFolder, ProgressForm progress) { List excludes = new List(standardExcludePropertiesList); //excludes.Add("ContractInEffect"); //excludes.Add("uiHasTechNotes"); PickListAutoComplete pl = PickListAutoComplete.GetList("**", "headoffice"); progress.Append("Dumping " + pl.Count.ToString() + " Head offices"); foreach (PickListAutoComplete.PickListAutoCompleteInfo i in pl) { HeadOffice c = HeadOffice.GetItem(i.ID); DumpObjectToFolder(tempArchiveFolder, c, "headoffice." + c.ID.ToString(), excludes); } } #endregion clients #region users private void dumpUsers(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); objectExcludeProperties.Add("LastView"); objectExcludeProperties.Add("LastSchedGroupID"); objectExcludeProperties.Add("LastSchedStartDate"); objectExcludeProperties.Add("LastSchedStopDate"); objectExcludeProperties.Add("LastSchedView"); objectExcludeProperties.Add("ScheduleLastGraphicalPrintSettings"); objectExcludeProperties.Add("MainGridLastRowCount"); objectExcludeProperties.Add("ScheduleLastViewOpenOnly"); objectExcludeProperties.Add("IsAdministrator"); objectExcludeProperties.Add("IsGenerator"); objectExcludeProperties.Add("IsScheduleable"); objectExcludeProperties.Add("IsClientOrHeadOfficeAccount"); objectExcludeProperties.Add("IsClientAccount"); objectExcludeProperties.Add("IsHeadOfficeAccount"); objectExcludeProperties.Add("OrganizationTypeAndID"); UserPickList pl = UserPickList.GetList(false); progress.Append("Dumping " + pl.Count.ToString() + " Users"); foreach (UserPickList.UserPickListInfo i in pl) { User c = User.GetItem(i.ID); DumpObjectToFolder(tempArchiveFolder, c, "user." + c.ID.ToString(), objectExcludeProperties); } } #endregion clients #region Unitmodelcategories private void dumpUnitModelCategories(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); UnitModelCategories l = UnitModelCategories.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Unit model categories"); foreach (UnitModelCategory i in l) { DumpObjectToFolder(tempArchiveFolder, i, "unitmodelcategory." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region Unitservicetypes private void dumpUnitServiceTypes(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); UnitServiceTypes l = UnitServiceTypes.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Unit service types"); foreach (UnitServiceType i in l) { DumpObjectToFolder(tempArchiveFolder, i, "unitservicetype." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region WorkorderItemTypes private void dumpWorkorderItemTypes(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); WorkorderItemTypes l = WorkorderItemTypes.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Workorder item types"); foreach (WorkorderItemType i in l) { DumpObjectToFolder(tempArchiveFolder, i, "workorderitemtype." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region Client groups private void dumpClientGroups(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); ClientGroups l = ClientGroups.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Client groups"); foreach (ClientGroup i in l) { DumpObjectToFolder(tempArchiveFolder, i, "clientgroup." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region Workorder categories private void dumpWorkorderCategories(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); WorkorderCategories l = WorkorderCategories.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Workorder categories"); foreach (WorkorderCategory i in l) { DumpObjectToFolder(tempArchiveFolder, i, "workordercategory." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region Part categories private void dumpPartCategories(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); PartCategories l = PartCategories.GetItems(); progress.Append("Dumping " + l.Count.ToString() + " Part categories"); foreach (PartCategory i in l) { DumpObjectToFolder(tempArchiveFolder, i, "partcategory." + i.ID.ToString(), objectExcludeProperties); } } #endregion #region ScheduleableUserGroups private void dumpScheduleableUserGroups(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); objectExcludeProperties.Add("ContractName"); objectExcludeProperties.Add("uiHasTechNotes"); ScheduleableUserGroupPickList pl = ScheduleableUserGroupPickList.GetList(); progress.Append("Dumping " + pl.Count.ToString() + " Scheduleable user groups"); foreach (ScheduleableUserGroupPickList.ScheduleableUserGroupPickListInfo i in pl) { ScheduleableUserGroup c = ScheduleableUserGroup.GetItem(i.ID); DumpObjectToFolder(tempArchiveFolder, c, "scheduleableusergroup." + c.ID.ToString(), objectExcludeProperties); } } #endregion clients #region Dispatch zones private void dumpDispatchZones(string tempArchiveFolder, ProgressForm progress) { List objectExcludeProperties = new List(standardExcludePropertiesList); //objectExcludeProperties.Add("ContractName"); //objectExcludeProperties.Add("uiHasTechNotes"); DispatchZones l = DispatchZones.GetItems(false); progress.Append("Dumping " + l.Count.ToString() + " Dispatch zones"); foreach (DispatchZone i in l) { DumpObjectToFolder(tempArchiveFolder, i, "dispatchzone." + i.ID.ToString(), objectExcludeProperties); } } #endregion //-------------------------------------------- #endregion object dump methods #region Dump /// /// Write out the object properties as JSON /// /// /// private void DumpObjectToFolder(string tempArchiveFolder, object o, string objectFileName, List excludeProperties, string forceTypeString = "") { var typestring = o.GetType().ToString(); if (!string.IsNullOrWhiteSpace(forceTypeString)) { typestring = forceTypeString; } var dumpFolder = tempArchiveFolder + Path.DirectorySeparatorChar + typestring; makeFolderIfNotExist(dumpFolder); var outputFileName = dumpFolder + Path.DirectorySeparatorChar + objectFileName + ".json"; JsonSerializer serializer = new JsonSerializer(); serializer.NullValueHandling = NullValueHandling.Include; serializer.ContractResolver = new ExcludeNamedPropertiesContractResolver(excludeProperties); serializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; #if(DEBUG) serializer.Formatting = Formatting.Indented; #endif // serializer.Converters.Add(new JavaScriptDateTimeConverter()); // serializer.NullValueHandling = NullValueHandling.Ignore; //generate file name, should be ID of object plus .json using (StreamWriter sw = new StreamWriter(outputFileName)) using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer, o); // {"ExpiryDate":new Date(1230375600000),"Price":0} } } #endregion dump #region Utility methods 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 #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 //eoc } //eons }