/// <summary> /// Ensure that the name of the item is unique. For example, two Web Pages named PageOne. /// </summary> /// <param name="nameList"></param> /// <param name="newItem"></param> /// <param name="appendTo"></param> /// <returns></returns> private string GetItemUniqueName(Dictionary <Guid, string> nameList, EditablePortalItem newItem, string appendTo = null) { // if the ID is already in the list, just return it if (nameList.ContainsKey(newItem.Id)) { return(nameList[newItem.Id]); } else { // see if the name already exists in the list for this section var newName = newItem.EscapeName(); // see if something additional has been added to ensure uniqueness (like partial URL) if (appendTo != null) { newName += $" - {appendTo}"; } newName = EditablePortalItem.EscapeForFileName(newName); var origName = newName; var counter = 0; while (nameList.Where(n => n.Value == newName).ToList().Count > 0) { counter++; newName = $"{origName} ({counter})"; } // add to the list for the next round nameList.Add(newItem.Id, newName); return(newName); } }
/// <summary> /// Export the Portal contents to individual files on disk /// </summary> /// <param name="portalItems">New list of EditablePortalItem objects</param> /// <param name="exportFolder">Target folder for the export</param> /// <param name="isLegacyPortal">Flag indicating whether this is an older version of the Portal</param> /// <param name="searchText">Text to filter the list</param> /// <param name="searchInContent">Flag indicating whether to search within the Content as well as names</param> /// <param name="clearFolder">Before export, delete all contents</param> private void Export(List <EditablePortalItem> portalItems, string exportFolder, bool isLegacyPortal, string searchText = null, bool searchInContent = true, bool clearFolder = false) { // preset the filtered list to the current list of items var filteredItems = portalItems; // if search text has been provided, search the list if (searchText != null) { // search case insensitive searchText = searchText.ToLower(); filteredItems = portalItems.Where(i => searchText.Length == 0 || (i.Name?.ToLower().Contains(searchText) ?? false) || searchInContent && i.Items.Any(i2 => i2.Content?.ToLower().Contains(searchText) ?? false)) .ToList(); } // build out the folder strucure. this will mimick the tree view structure pretty closely. // delete the folders? if (clearFolder) { DirectoryInfo di = new DirectoryInfo(exportFolder); foreach (FileInfo file in di.GetFiles()) { file.Delete(); } foreach (DirectoryInfo dir in di.GetDirectories()) { dir.Delete(true); } } // keep track of the names by type by website that have been exported so we do not overrite content // might be easier to look for file... var websiteNameList = new Dictionary <Guid, Dictionary <string, Dictionary <Guid, string> > >(); // begin the work! foreach (var item in filteredItems) { var currentPath = ""; var websiteReference = item.WebsiteReference; if (websiteReference == null) { continue; } // build current folder path starting with the website, appended to the selected folder var websiteName = websiteReference.Id == Guid.Empty ? "(Not website related)" : websiteReference.Name; websiteName = EditablePortalItem.EscapeForFileName(websiteName); currentPath = Path.Combine(exportFolder, websiteName); // add a new structure to track names for this website if (!websiteNameList.ContainsKey(websiteReference.Id)) { websiteNameList.Add(websiteReference.Id, GetWebSiteNameList()); } var nameList = websiteNameList[websiteReference.Id]; if (!Directory.Exists(currentPath)) { Directory.CreateDirectory(currentPath); Directory.CreateDirectory(Path.Combine(currentPath, WebPage.NODENAME)); if (!isLegacyPortal) { Directory.CreateDirectory(Path.Combine(currentPath, ContentSnippet.NODENAME)); Directory.CreateDirectory(Path.Combine(currentPath, EntityForm.NODENAME)); Directory.CreateDirectory(Path.Combine(currentPath, EntityList.NODENAME)); Directory.CreateDirectory(Path.Combine(currentPath, WebFormStep.NODENAME)); Directory.CreateDirectory(Path.Combine(currentPath, WebTemplate.NODENAME)); } Directory.CreateDirectory(Path.Combine(websiteName, WebFile.NODENAME)); } if (item is WebPage page) { // new web page, append to the current path currentPath = AppendToPath(currentPath, WebPage.NODENAME); if (page.IsRoot || page.ParentPageId == Guid.Empty) { var name = GetItemUniqueName(nameList[WebPage.NODENAME], page, page.PartialUrl); // new folder for web page currentPath = AppendToPath(currentPath, name); if (isLegacyPortal) { // path to JS and CSS file only page.WriteContent(currentPath); } } else { // find the parent page Id to get the name of the folder // TODO - do we want to account for the root page? var parent = portalItems .FirstOrDefault(w => (w as WebPage)?.Id == page.ParentPageId) as WebPage; if (parent == null) { continue; } var name = GetItemUniqueName(nameList[WebPage.NODENAME], parent, page.PartialUrl); // new path for website and the language currentPath = AppendToPath(currentPath, name); currentPath = AppendToPath(currentPath, page.Language); // path to JS and CSS file only page.WriteContent(currentPath); } } else if (item is EntityForm form) { var name = GetItemUniqueName(nameList[EntityForm.NODENAME], form); // new entity form, append to the current path currentPath = AppendToPath(currentPath, EntityForm.NODENAME); currentPath = AppendToPath(currentPath, name); form.WriteContent(currentPath); } else if (item is EntityList list) { var name = GetItemUniqueName(nameList[EntityList.NODENAME], list); // new entity list, append to the current path currentPath = AppendToPath(currentPath, EntityList.NODENAME); currentPath = AppendToPath(currentPath, name); list.WriteContent(currentPath); } else if (item is WebTemplate template) { var name = GetItemUniqueName(nameList[WebTemplate.NODENAME], template); // new Web Template, append to the current path currentPath = AppendToPath(currentPath, WebTemplate.NODENAME); currentPath = AppendToPath(currentPath, name); template.WriteContent(currentPath); } else if (item is WebFile file) { // var name = GetItemUniqueName(nameList[WebFile.NODENAME], file); // NOTE assume the filename is unique // new Web File, append to the current path currentPath = AppendToPath(currentPath, WebFile.NODENAME); currentPath = Path.Combine(currentPath, file.Name); file.WriteContent(currentPath); } else if (item is WebFormStep wfStep) { // NOTE assume the WF Steps are unique within the WF // new Web Form Step... first, append to web forms currentPath = AppendToPath(currentPath, WebFormStep.NODENAME); // then find the web form name for the root folder if (wfStep.WebFormReference != null) { // add the web form name to the path currentPath = AppendToPath(currentPath, WebFormStep.EscapeForFileName(wfStep.WebFormReference.Name)); } // now down to the web form step name for a folder and then the js var name = wfStep.EscapeName(); currentPath = AppendToPath(currentPath, name); wfStep.WriteContent(currentPath); } else if (item is ContentSnippet snippet) { var name = GetItemUniqueName(nameList[ContentSnippet.NODENAME], snippet); // new content snippet. put all in the same folder, appending extension currentPath = AppendToPath(currentPath, ContentSnippet.NODENAME); currentPath = AppendToPath(currentPath, name); snippet.WriteContent(currentPath); } else { throw new Exception($"Unsupported portal item type: {item.GetType().Name}"); } } }