using System; using System.Collections.Generic; using System.IO; using ScrewTurn.Wiki.AclEngine; using ScrewTurn.Wiki.PluginFramework; namespace ScrewTurn.Wiki { /// /// Provides methods for migrating data from a Provider to another. /// public static class DataMigrator { /// /// Migrates all the data from a Pages Provider to another one. /// /// The source Provider. /// The destination Provider. public static void MigratePagesStorageProviderData(IPagesStorageProviderV30 source, IPagesStorageProviderV30 destination) { // Move Snippets Snippet[] snippets = source.GetSnippets(); for(int i = 0; i < snippets.Length; i++) { destination.AddSnippet(snippets[i].Name, snippets[i].Content); source.RemoveSnippet(snippets[i].Name); } // Move Content Templates ContentTemplate[] templates = source.GetContentTemplates(); for(int i = 0; i < templates.Length; i++) { destination.AddContentTemplate(templates[i].Name, templates[i].Content); source.RemoveContentTemplate(templates[i].Name); } // Create namespaces NamespaceInfo[] namespaces = source.GetNamespaces(); NamespaceInfo[] createdNamespaces = new NamespaceInfo[namespaces.Length]; for(int i = 0; i < namespaces.Length; i++) { createdNamespaces[i] = destination.AddNamespace(namespaces[i].Name); } List sourceNamespaces = new List(); sourceNamespaces.Add(null); sourceNamespaces.AddRange(namespaces); int currentNamespaceIndex = 0; foreach(NamespaceInfo currentNamespace in sourceNamespaces) { // Load all nav paths now to avoid problems with missing pages from source provider // after the pages have been moved already NavigationPath[] sourceNavPaths = source.GetNavigationPaths(currentNamespace); // Copy categories (removed from source later) CategoryInfo[] sourceCats = source.GetCategories(currentNamespace); for(int i = 0; i < sourceCats.Length; i++) { destination.AddCategory(NameTools.GetNamespace(sourceCats[i].FullName), NameTools.GetLocalName(sourceCats[i].FullName)); } // Move Pages PageInfo[] pages = source.GetPages(currentNamespace); for(int i = 0; i < pages.Length; i++) { // Create Page PageInfo newPage = destination.AddPage(NameTools.GetNamespace(pages[i].FullName), NameTools.GetLocalName(pages[i].FullName), pages[i].CreationDateTime); if(newPage == null) { Log.LogEntry("Unable to move Page " + pages[i].FullName + " - Skipping", EntryType.Error, Log.SystemUsername); continue; } // Get content and store it, without backup PageContent c = source.GetContent(pages[i]); destination.ModifyPage(newPage, c.Title, c.User, c.LastModified, c.Comment, c.Content, c.Keywords, c.Description, SaveMode.Normal); // Move all the backups int[] revs = source.GetBackups(pages[i]); for(int k = 0; k < revs.Length; k++) { c = source.GetBackupContent(pages[i], revs[k]); destination.SetBackupContent(c, revs[k]); } // Move all messages Message[] messages = source.GetMessages(pages[i]); destination.BulkStoreMessages(newPage, messages); // Bind current page (find all proper categories, and use them to bind the page) List pageCats = new List(); for(int k = 0; k < sourceCats.Length; k++) { for(int z = 0; z < sourceCats[k].Pages.Length; z++) { if(sourceCats[k].Pages[z].Equals(newPage.FullName)) { pageCats.Add(sourceCats[k].FullName); break; } } } destination.RebindPage(newPage, pageCats.ToArray()); // Copy draft PageContent draft = source.GetDraft(pages[i]); if(draft != null) { destination.ModifyPage(newPage, draft.Title, draft.User, draft.LastModified, draft.Comment, draft.Content, draft.Keywords, draft.Description, SaveMode.Draft); } // Remove Page from source source.RemovePage(pages[i]); // Also deletes the Messages } // Remove Categories from source for(int i = 0; i < sourceCats.Length; i++) { source.RemoveCategory(sourceCats[i]); } // Move navigation paths List newPages = new List(destination.GetPages(currentNamespace == null ? null : createdNamespaces[currentNamespaceIndex])); for(int i = 0; i < sourceNavPaths.Length; i++) { PageInfo[] tmp = new PageInfo[sourceNavPaths[i].Pages.Length]; for(int k = 0; k < tmp.Length; k++) { tmp[k] = newPages.Find(delegate(PageInfo p) { return p.FullName == sourceNavPaths[i].Pages[k]; }); } destination.AddNavigationPath(NameTools.GetNamespace(sourceNavPaths[i].FullName), NameTools.GetLocalName(sourceNavPaths[i].FullName), tmp); source.RemoveNavigationPath(sourceNavPaths[i]); } if(currentNamespace != null) { // Set default page PageInfo defaultPage = currentNamespace.DefaultPage == null ? null : newPages.Find(delegate(PageInfo p) { return p.FullName == currentNamespace.DefaultPage.FullName; }); destination.SetNamespaceDefaultPage(createdNamespaces[currentNamespaceIndex], defaultPage); // Remove namespace from source source.RemoveNamespace(currentNamespace); currentNamespaceIndex++; } } } /// /// Migrates all the User Accounts from a Provider to another. /// /// The source Provider. /// The destination Provider. /// A value indicating whether or not to send a notification email message to the moved users. public static void MigrateUsersStorageProviderData(IUsersStorageProviderV30 source, IUsersStorageProviderV30 destination, bool sendEmailNotification) { // User groups UserGroup[] groups = source.GetUserGroups(); foreach(UserGroup group in groups) { destination.AddUserGroup(group.Name, group.Description); } // Users UserInfo[] users = source.GetUsers(); MovedUser[] movedUsers = new MovedUser[users.Length]; for(int i = 0; i < users.Length; i++) { // Generate new Password, create MovedUser object, add new User, delete old User string password = Tools.GenerateRandomPassword(); movedUsers[i] = new MovedUser(users[i].Username, users[i].Email, users[i].DateTime); UserInfo newUser = destination.AddUser(users[i].Username, users[i].DisplayName, password, users[i].Email, users[i].Active, users[i].DateTime); // Membership destination.SetUserMembership(newUser, users[i].Groups); // User data IDictionary uData = source.RetrieveAllUserData(users[i]); foreach(KeyValuePair pair in uData) { destination.StoreUserData(newUser, pair.Key, pair.Value); } source.RemoveUser(users[i]); } // Remove old groups foreach(UserGroup group in groups) { source.RemoveUserGroup(group); } if(sendEmailNotification) { // Send Emails for(int i = 0; i < movedUsers.Length; i++) { Users.SendPasswordResetMessage(movedUsers[i].Username, movedUsers[i].Email, movedUsers[i].DateTime); } } } /// /// Migrates all the stored files and page attachments from a Provider to another. /// /// The source Provider. /// The destination Provider. /// The settings storage provider that handles permissions. public static void MigrateFilesStorageProviderData(IFilesStorageProviderV30 source, IFilesStorageProviderV30 destination, ISettingsStorageProviderV30 settingsProvider) { // Directories MigrateDirectories(source, destination, "/", settingsProvider); // Attachments foreach(string page in source.GetPagesWithAttachments()) { PageInfo pageInfo = new PageInfo(page, null, DateTime.Now); string[] attachments = source.ListPageAttachments(pageInfo); foreach(string attachment in attachments) { // Copy file content using(MemoryStream ms = new MemoryStream(1048576)) { source.RetrievePageAttachment(pageInfo, attachment, ms, false); ms.Seek(0, SeekOrigin.Begin); destination.StorePageAttachment(pageInfo, attachment, ms, false); } // Copy download count FileDetails fileDetails = source.GetPageAttachmentDetails(pageInfo, attachment); destination.SetPageAttachmentRetrievalCount(pageInfo, attachment, fileDetails.RetrievalCount); // Delete attachment source.DeletePageAttachment(pageInfo, attachment); } } } private static void MigrateDirectories(IFilesStorageProviderV30 source, IFilesStorageProviderV30 destination, string current, ISettingsStorageProviderV30 settingsProvider) { // Copy files string[] files = source.ListFiles(current); foreach(string file in files) { // Copy file content using(MemoryStream ms = new MemoryStream(1048576)) { source.RetrieveFile(file, ms, false); ms.Seek(0, SeekOrigin.Begin); destination.StoreFile(file, ms, false); } // Copy download count FileDetails fileDetails = source.GetFileDetails(file); destination.SetFileRetrievalCount(file, fileDetails.RetrievalCount); // Delete source file, if root if(current == "/") { source.DeleteFile(file); } } settingsProvider.AclManager.RenameResource( Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(source, current), Actions.ForDirectories.ResourceMasterPrefix + AuthTools.GetDirectoryName(destination, current)); // Copy directories string[] directories = source.ListDirectories(current); foreach(string dir in directories) { destination.CreateDirectory(current, dir.Substring(dir.TrimEnd('/').LastIndexOf("/") + 1).Trim('/')); MigrateDirectories(source, destination, dir, settingsProvider); // Delete directory, if root if(current == "/") { source.DeleteDirectory(dir); } } } /// /// Copies the settings from a Provider to another. /// /// The source Provider. /// The destination Provider. /// The currently known page namespaces. /// The currently known plugins. public static void CopySettingsStorageProviderData(ISettingsStorageProviderV30 source, ISettingsStorageProviderV30 destination, string[] knownNamespaces, string[] knownPlugins) { // Settings destination.BeginBulkUpdate(); foreach(KeyValuePair pair in source.GetAllSettings()) { destination.SetSetting(pair.Key, pair.Value); } destination.EndBulkUpdate(); // Meta-data (global) destination.SetMetaDataItem(MetaDataItem.AccountActivationMessage, null, source.GetMetaDataItem(MetaDataItem.AccountActivationMessage, null)); destination.SetMetaDataItem(MetaDataItem.PasswordResetProcedureMessage, null, source.GetMetaDataItem(MetaDataItem.PasswordResetProcedureMessage, null)); destination.SetMetaDataItem(MetaDataItem.LoginNotice, null, source.GetMetaDataItem(MetaDataItem.LoginNotice, null)); destination.SetMetaDataItem(MetaDataItem.PageChangeMessage, null, source.GetMetaDataItem(MetaDataItem.PageChangeMessage, null)); destination.SetMetaDataItem(MetaDataItem.DiscussionChangeMessage, null, source.GetMetaDataItem(MetaDataItem.DiscussionChangeMessage, null)); // Meta-data (ns-specific) List namespacesToProcess = new List(); namespacesToProcess.Add(null); namespacesToProcess.AddRange(knownNamespaces); foreach(string nspace in namespacesToProcess) { destination.SetMetaDataItem(MetaDataItem.EditNotice, nspace, source.GetMetaDataItem(MetaDataItem.EditNotice, nspace)); destination.SetMetaDataItem(MetaDataItem.Footer, nspace, source.GetMetaDataItem(MetaDataItem.Footer, nspace)); destination.SetMetaDataItem(MetaDataItem.Header, nspace, source.GetMetaDataItem(MetaDataItem.Header, nspace)); destination.SetMetaDataItem(MetaDataItem.HtmlHead, nspace, source.GetMetaDataItem(MetaDataItem.HtmlHead, nspace)); destination.SetMetaDataItem(MetaDataItem.PageFooter, nspace, source.GetMetaDataItem(MetaDataItem.PageFooter, nspace)); destination.SetMetaDataItem(MetaDataItem.PageHeader, nspace, source.GetMetaDataItem(MetaDataItem.PageHeader, nspace)); destination.SetMetaDataItem(MetaDataItem.Sidebar, nspace, source.GetMetaDataItem(MetaDataItem.Sidebar, nspace)); } // Plugin assemblies string[] assemblies = source.ListPluginAssemblies(); foreach(string asm in assemblies) { destination.StorePluginAssembly(asm, source.RetrievePluginAssembly(asm)); } // Plugin status and config foreach(string plug in knownPlugins) { destination.SetPluginStatus(plug, source.GetPluginStatus(plug)); destination.SetPluginConfiguration(plug, source.GetPluginConfiguration(plug)); } // Outgoing links IDictionary allLinks = source.GetAllOutgoingLinks(); foreach(KeyValuePair link in allLinks) { destination.StoreOutgoingLinks(link.Key, link.Value); } // ACLs AclEntry[] allEntries = source.AclManager.RetrieveAllEntries(); foreach(AclEntry entry in allEntries) { destination.AclManager.StoreEntry(entry.Resource, entry.Action, entry.Subject, entry.Value); } } } /// /// Contains username, email and registration date/time of a moved User account. /// public class MovedUser { private string username, email; private DateTime dateTime; /// /// Initializes a new instance of the MovedUser class. /// /// The esername. /// The email address. /// The registration date/time. public MovedUser(string username, string email, DateTime dateTime) { this.username = username; this.email = email; this.dateTime = dateTime; } /// /// Gets the Username. /// public string Username { get { return username; } } /// /// Gets the Email. /// public string Email { get { return email; } } /// /// Gets the registration date/time. /// public DateTime DateTime { get { return dateTime; } } } }