Contains the Content of a Page.
        protected void Page_Load(object sender, EventArgs e)
        {
            page = Pages.FindPage(Request["Page"]);
            if(page == null) UrlTools.RedirectHome();

            // Check permissions
            bool canView = false;
            if(Request["Discuss"] == null) {
                canView = AuthChecker.CheckActionForPage(page, Actions.ForPages.ReadPage,
                    SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
            }
            else {
                canView = AuthChecker.CheckActionForPage(page, Actions.ForPages.ReadDiscussion,
                    SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
            }
            if(!canView) UrlTools.Redirect("AccessDenied.aspx");

            content = Content.GetPageContent(page, true);

            Literal canonical = new Literal();
            canonical.Text = Tools.GetCanonicalUrlTag(Request.Url.ToString(), page, Pages.FindNamespace(NameTools.GetNamespace(page.FullName)));
            Page.Header.Controls.Add(canonical);

            Page.Title = FormattingPipeline.PrepareTitle(content.Title, false, FormattingContext.PageContent, page) + " - " + Settings.WikiTitle;

            PrintContent();
        }
        /// <summary>
        /// Stores the content for a revision.
        /// </summary>
        /// <param name="transaction">A database transaction.</param>
        /// <param name="content">The content.</param>
        /// <param name="revision">The revision.</param>
        /// <returns><c>true</c> if the content is stored, <c>false</c> otherwise.</returns>
        private bool SetContent(DbTransaction transaction, PageContent content, int revision)
        {
            string name, nspace;
            NameTools.ExpandFullName(content.PageInfo.FullName, out nspace, out name);
            if(nspace == null) nspace = "";

            ICommandBuilder builder = GetCommandBuilder();
            QueryBuilder queryBuilder = new QueryBuilder(builder);

            string query = queryBuilder.InsertInto("PageContent",
                new string[] { "Page", "Namespace", "Revision", "Title", "User", "LastModified", "Comment", "Content", "Description" },
                new string[] { "Page", "Namespace", "Revision", "Title", "User", "LastModified", "Comment", "Content", "Description" });

            List<Parameter> parameters = new List<Parameter>(9);
            parameters.Add(new Parameter(ParameterType.String, "Page", name));
            parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace));
            parameters.Add(new Parameter(ParameterType.Int16, "Revision", revision));
            parameters.Add(new Parameter(ParameterType.String, "Title", content.Title));
            parameters.Add(new Parameter(ParameterType.String, "User", content.User));
            parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", content.LastModified));
            if(!string.IsNullOrEmpty(content.Comment)) parameters.Add(new Parameter(ParameterType.String, "Comment", content.Comment));
            else parameters.Add(new Parameter(ParameterType.String, "Comment", DBNull.Value));
            parameters.Add(new Parameter(ParameterType.String, "Content", content.Content));
            if(!string.IsNullOrEmpty(content.Description)) parameters.Add(new Parameter(ParameterType.String, "Description", content.Description));
            else parameters.Add(new Parameter(ParameterType.String, "Description", DBNull.Value));

            DbCommand command = builder.GetCommand(transaction, query, parameters);

            int rows = ExecuteNonQuery(command, false);

            if(rows != 1) return false;

            if(content.Keywords.Length > 0) {
                parameters = new List<Parameter>(content.Keywords.Length * 4);
                string fullQuery = "";
                int count = 0;
                string countString;
                foreach(string kw in content.Keywords) {
                    countString = count.ToString();

                    query = queryBuilder.InsertInto("PageKeyword", new string[] { "Page", "Namespace", "Revision", "Keyword" },
                        new string[] { "Page" + countString, "Namespace" + countString, "Revision" + countString, "Keyword" + countString });
                    fullQuery = queryBuilder.AppendForBatch(fullQuery, query);

                    parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name));
                    parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace));
                    parameters.Add(new Parameter(ParameterType.Int16, "Revision" + countString, revision));
                    parameters.Add(new Parameter(ParameterType.String, "Keyword" + countString, kw));

                    count++;
                }

                command = builder.GetCommand(transaction, fullQuery, parameters);

                rows = ExecuteNonQuery(command, false);

                return rows == content.Keywords.Length;
            }
            else return true;
        }
        /// <summary>
        /// Gets the content of a specific revision of a page.
        /// </summary>
        /// <param name="transaction">A database transaction.</param>
        /// <param name="page">The page.</param>
        /// <param name="revision">The revision.</param>
        /// <returns>The content.</returns>
        private PageContent GetContent(DbTransaction transaction, PageInfo page, int revision)
        {
            // Internal version to work with GetContent, GetBackupContent, GetDraft

            ICommandBuilder builder = GetCommandBuilder();
            QueryBuilder queryBuilder = new QueryBuilder(builder);

            string name, nspace;
            NameTools.ExpandFullName(page.FullName, out nspace, out name);
            if(nspace == null) nspace = "";

            string query = queryBuilder.SelectFrom("PageContent", "PageKeyword", new string[] { "Page", "Namespace", "Revision" }, new string[] { "Page", "Namespace", "Revision" }, Join.LeftJoin,
                new string[] { "Title", "User", "LastModified", "Comment", "Content", "Description" }, new string[] { "Keyword" });
            query = queryBuilder.Where(query, "PageContent", "Page", WhereOperator.Equals, "Page");
            query = queryBuilder.AndWhere(query, "PageContent", "Namespace", WhereOperator.Equals, "Namespace");
            query = queryBuilder.AndWhere(query, "PageContent", "Revision", WhereOperator.Equals, "Revision");

            List<Parameter> parameters = new List<Parameter>(3);
            parameters.Add(new Parameter(ParameterType.String, "Page", name));
            parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace));
            parameters.Add(new Parameter(ParameterType.Int16, "Revision", (short)revision));

            DbCommand command = builder.GetCommand(transaction, query, parameters);

            DbDataReader reader = ExecuteReader(command);

            if(reader != null) {
                PageContent result = null;

                string title = null, user = null, comment = null, content = null, description = null;
                DateTime dateTime = DateTime.MinValue;
                List<string> keywords = new List<string>(10);

                while(reader.Read()) {
                    if(title == null) {
                        title = reader["PageContent_Title"] as string;
                        user = reader["PageContent_User"] as string;
                        dateTime = (DateTime)reader["PageContent_LastModified"];
                        comment = GetNullableColumn<string>(reader, "PageContent_Comment", "");
                        content = reader["PageContent_Content"] as string;
                        description = GetNullableColumn<string>(reader, "PageContent_Description", null);
                    }

                    if(!IsDBNull(reader, "PageKeyword_Keyword")) {
                        keywords.Add(reader["PageKeyword_Keyword"] as string);
                    }
                }

                if(title != null) {
                    result = new PageContent(page, title, user, dateTime, comment, content, keywords.ToArray(), description);
                }

                CloseReader(reader);

                return result;
            }
            else return null;
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.Title = Properties.Messages.EditTitle + " - " + Settings.WikiTitle;

            lblEditNotice.Text = Formatter.FormatPhase3(Formatter.Format(Settings.Provider.GetMetaDataItem(
                MetaDataItem.EditNotice, DetectNamespace()), false, FormattingContext.Other, null), FormattingContext.Other, null);

            // Prepare page unload warning
            string ua = Request.UserAgent;
            if(!string.IsNullOrEmpty(ua)) {
                ua = ua.ToLowerInvariant();
                StringBuilder sbua = new StringBuilder(50);
                sbua.Append(@"<script type=""text/javascript"">");
                sbua.Append("\r\n<!--\r\n");
                if(ua.Contains("gecko")) {
                    // Mozilla
                    sbua.Append("addEventListener('beforeunload', __UnloadPage, true);");
                }
                else {
                    // IE
                    sbua.Append("window.attachEvent('onbeforeunload', __UnloadPage);");
                }
                sbua.Append("\r\n// -->\r\n");
                sbua.Append("</script>");
                lblUnloadPage.Text = sbua.ToString();
            }

            if(!Page.IsPostBack) {
                PopulateCategories(new CategoryInfo[0]);

                if(Settings.AutoGeneratePageNames) {
                    pnlPageName.Visible = false;
                    pnlManualName.Visible = true;
                }
            }

            // Load requested page, if any
            if(Request["Page"] != null || Page.IsPostBack) {
                string name = null;
                if(Request["Page"] != null) {
                    name = Request["Page"];
                }
                else {
                    name = txtName.Text;
                }

                currentPage = Pages.FindPage(name);

                // If page already exists, load the content and disable page name,
                // otherwise pre-fill page name
                if(currentPage != null) {
                    // Look for a draft
                    currentContent = Pages.GetDraft(currentPage);

                    if(currentContent == null) {
                        // No cache because the page will be probably modified in a few minutes
                        currentContent = Content.GetPageContent(currentPage, false);
                    }
                    else isDraft = true;

                    // Set current page for editor and attachment manager
                    editor.CurrentPage = currentPage;
                    attachmentManager.CurrentPage = currentPage;

                    if(!int.TryParse(Request["Section"], out currentSection)) currentSection = -1;

                    // Fill data, if not posted back
                    if(!Page.IsPostBack) {
                        // Set keywords, description
                        SetKeywords(currentContent.Keywords);
                        txtDescription.Text = currentContent.Description;

                        txtName.Text = NameTools.GetLocalName(currentPage.FullName);
                        txtName.Enabled = false;
                        pnlPageName.Visible = false;
                        pnlManualName.Visible = false;

                        PopulateCategories(Pages.GetCategoriesForPage(currentPage));

                        txtTitle.Text = currentContent.Title;

                        // Manage section, if appropriate (disable if draft)
                        if(!isDraft && currentSection != -1) {
                            int startIndex, len;
                            string dummy = "";
                            ExtractSection(currentContent.Content, currentSection, out startIndex, out len, out dummy);
                            editor.SetContent(currentContent.Content.Substring(startIndex, len), Settings.UseVisualEditorAsDefault);
                        }
                        else {
                            // Select default editor view (WikiMarkup or Visual) and populate content
                            editor.SetContent(currentContent.Content, Settings.UseVisualEditorAsDefault);
                        }
                    }
                }
                else {
                    // Pre-fill name, if not posted back
                    if(!Page.IsPostBack) {
                        // Set both name and title, as the NAME was provided from the query-string and must be preserved
                        pnlPageName.Visible = true;
                        pnlManualName.Visible = false;
                        txtName.Text = NameTools.GetLocalName(name);
                        txtTitle.Text = txtName.Text;
                        editor.SetContent(LoadTemplateIfAppropriate(), Settings.UseVisualEditorAsDefault);
                    }
                }
            }
            else {
                if(!Page.IsPostBack) {
                    chkMinorChange.Visible = false;
                    chkSaveAsDraft.Visible = false;

                    editor.SetContent(LoadTemplateIfAppropriate(), Settings.UseVisualEditorAsDefault);
                }
            }

            // Here is centralized all permissions-checking code
            DetectPermissions();

            // Verify the following permissions:
            // - if new page, check for page creation perms
            // - else, check for editing perms
            //    - full edit or edit with approval
            // - categories management
            // - attachment manager
            // - CAPTCHA if enabled and user is anonymous
            // ---> recheck every time an action is performed

            if(currentPage == null) {
                // Check permissions for creating new pages
                if(!canCreateNewPages) {
                    if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Tools.GetCurrentUrlFixed()));
                    else UrlTools.Redirect("AccessDenied.aspx");
                }
            }
            else {
                // Check permissions for editing current page
                if(!canEdit && !canEditWithApproval) {
                    if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Tools.GetCurrentUrlFixed()));
                    else UrlTools.Redirect("AccessDenied.aspx");
                }
            }

            if(!canEdit && canEditWithApproval) {
                // Hard-wire status of draft and minor change checkboxes
                chkMinorChange.Enabled = false;
                chkSaveAsDraft.Enabled = false;
                chkSaveAsDraft.Checked = true;
            }

            // Setup categories
            lstCategories.Enabled = canManagePageCategories;
            pnlCategoryCreation.Visible = canCreateNewCategories;

            // Setup attachment manager (require at least download permissions)
            attachmentManager.Visible = canDownloadAttachments;

            // CAPTCHA
            pnlCaptcha.Visible = SessionFacade.LoginKey == null && !Settings.DisableCaptchaControl;
            captcha.Visible = pnlCaptcha.Visible;

            // Moderation notice
            pnlApprovalRequired.Visible = !canEdit && canEditWithApproval;

            // Check and manage editing collisions
            ManageEditingCollisions();

            if(!Page.IsPostBack) {
                ManageTemplatesDisplay();

                // Display draft status
                ManageDraft();
            }

            // Setup session refresh iframe
            PrintSessionRefresh();
        }
        private void AssertPageContentsAreEqual(PageContent expected, PageContent actual)
        {
            AssertPageInfosAreEqual(expected.PageInfo, actual.PageInfo, true);
            Assert.AreEqual(expected.Title, actual.Title, "Wrong title");
            Assert.AreEqual(expected.User, actual.User, "Wrong user");
            Tools.AssertDateTimesAreEqual(expected.LastModified, actual.LastModified, true);
            Assert.AreEqual(expected.Comment, actual.Comment, "Wrong comment");
            Assert.AreEqual(expected.Content, actual.Content, "Wrong content");

            if(expected.LinkedPages != null) {
                Assert.IsNotNull(actual.LinkedPages, "LinkedPages is null");
                Assert.AreEqual(expected.LinkedPages.Length, actual.LinkedPages.Length, "Wrong linked page count");
                for(int i = 0; i < expected.LinkedPages.Length; i++) {
                    Assert.AreEqual(expected.LinkedPages[i], actual.LinkedPages[i], "Wrong linked page");
                }
            }

            if(expected.Keywords != null) {
                Assert.IsNotNull(actual.Keywords);
                Assert.AreEqual(expected.Keywords.Length, actual.Keywords.Length, "Wrong keyword count");
                for(int i = 0; i < expected.Keywords.Length; i++) {
                    Assert.AreEqual(expected.Keywords[i], actual.Keywords[i], "Wrong keyword");
                }
            }

            Assert.AreEqual(expected.Description, actual.Description, "Wrong description");
        }
        public void SetBackupContent_GetBackupContent_Sub()
        {
            IPagesStorageProviderV30 prov = GetProvider();

            NamespaceInfo ns = prov.AddNamespace("Namespace");

            PageInfo p = prov.AddPage(ns.Name, "Page", DateTime.Now);
            prov.ModifyPage(p, "Title", "NUnit", DateTime.Now, "Comment", "Content", null, null, SaveMode.Normal);
            prov.ModifyPage(p, "Title1", "NUnit1", DateTime.Now, "Comment1", "Content1", null, null, SaveMode.Backup);

            PageContent content = new PageContent(p, "Title100", "NUnit100", DateTime.Now.AddDays(-1), "Comment100", "Content100", null, null);
            PageContent contentInexistent = new PageContent(new PageInfo(NameTools.GetFullName(ns.Name, "PPP"), prov, DateTime.Now),
                "Title100", "NUnit100", DateTime.Now.AddDays(-1), "Comment100", "Content100", null, null);

            Assert.IsFalse(prov.SetBackupContent(contentInexistent, 0), "SetBackupContent should return ");

            Assert.IsTrue(prov.SetBackupContent(content, 0), "SetBackupContent should return true");

            PageContent contentOutput = prov.GetBackupContent(p, 0);

            AssertPageContentsAreEqual(content, contentOutput);
        }
        /// <summary>
        /// Indexes a page.
        /// </summary>
        /// <param name="content">The content of the page.</param>
        /// <returns>The number of indexed words, including duplicates.</returns>
        private int IndexPage(PageContent content)
        {
            lock(this) {
                try {
                    string documentName = PageDocument.GetDocumentName(content.PageInfo);

                    DumpedDocument ddoc = new DumpedDocument(0, documentName, host.PrepareTitleForIndexing(content.PageInfo, content.Title),
                        PageDocument.StandardTypeTag, content.LastModified);

                    // Store the document
                    // The content should always be prepared using IHost.PrepareForSearchEngineIndexing()
                    int count = index.StoreDocument(new PageDocument(content.PageInfo, ddoc, TokenizeContent),
                        content.Keywords, host.PrepareContentForIndexing(content.PageInfo, content.Content), null);

                    if(count == 0 && content.Content.Length > 0) {
                        host.LogEntry("Indexed 0 words for page " + content.PageInfo.FullName + ": possible index corruption. Please report this error to the developers",
                            LogEntryType.Warning, null, this);
                    }

                    return count;
                }
                catch(Exception ex) {
                    host.LogEntry("Page indexing error for " + content.PageInfo.FullName + " (skipping page): " + ex.ToString(), LogEntryType.Error, null, this);
                    return 0;
                }
            }
        }
        /// <summary>
        /// Modifies the Content of a Page.
        /// </summary>
        /// <param name="page">The Page.</param>
        /// <param name="title">The Title of the Page.</param>
        /// <param name="username">The Username.</param>
        /// <param name="dateTime">The Date/Time.</param>
        /// <param name="comment">The Comment of the editor, about this revision.</param>
        /// <param name="content">The Page Content.</param>
        /// <param name="keywords">The keywords, usually used for SEO.</param>
        /// <param name="description">The description, usually used for SEO.</param>
        /// <param name="saveMode">The save mode for this modification.</param>
        /// <returns><c>true</c> if the Page has been modified successfully, <c>false</c> otherwise.</returns>
        /// <remarks>If <b>saveMode</b> equals <b>Draft</b> and a draft already exists, it is overwritten.</remarks>
        /// <exception cref="ArgumentNullException">If <paramref name="page"/>, <paramref name="title"/> <paramref name="username"/> or <paramref name="content"/> are <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If <paramref name="title"/> or <paramref name="username"/> are empty.</exception>
        public bool ModifyPage(PageInfo page, string title, string username, DateTime dateTime, string comment, string content,
            string[] keywords, string description, SaveMode saveMode)
        {
            if(page == null) throw new ArgumentNullException("page");
            if(title == null) throw new ArgumentNullException("title");
            if(title.Length == 0) throw new ArgumentException("Title cannot be empty", "title");
            if(username == null) throw new ArgumentNullException("username");
            if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username");
            if(content == null) throw new ArgumentNullException("content"); // content can be empty

            lock(this) {
                LocalPageInfo local = LoadLocalPageInfo(page);
                if(local == null) return false;

                if(saveMode == SaveMode.Backup) {
                    Backup(local);
                }

                StringBuilder sb = new StringBuilder();
                sb.Append(title);
                sb.Append("\r\n");
                sb.Append(username);
                sb.Append("|");
                sb.Append(dateTime.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
                if(!string.IsNullOrEmpty(comment)) {
                    sb.Append("|");
                    sb.Append(Tools.EscapeString(comment));
                }
                if((keywords != null && keywords.Length > 0) || !string.IsNullOrEmpty(description)) {
                    sb.Append("|(((");
                    if(keywords != null) {
                        for(int i = 0; i < keywords.Length; i++) {
                            sb.Append(Tools.EscapeString(keywords[i]));
                            if(i != keywords.Length - 1) sb.Append(",");
                        }
                    }
                    sb.Append(")))(((");
                    sb.Append(Tools.EscapeString(description));
                    sb.Append(")))");
                }
                sb.Append("\r\n##PAGE##\r\n");
                sb.Append(content);

                if(saveMode == SaveMode.Draft) {
                    // Create the namespace directory for the draft, if needed
                    // Drafts\NS\Page.cs
                    string targetFileFullPath = GetDraftFullPath(local);
                    if(!Directory.Exists(Path.GetDirectoryName(targetFileFullPath))) {
                        Directory.CreateDirectory(Path.GetDirectoryName(targetFileFullPath));
                    }
                    File.WriteAllText(targetFileFullPath, sb.ToString());
                }
                else {
                    File.WriteAllText(GetFullPathForPageContent(local.File), sb.ToString());

                    // Update search engine index
                    PageContent pageContent = new PageContent(page, title, username, dateTime, comment, content, keywords, description);
                    IndexPage(pageContent);
                }

            }
            return true;
        }
Beispiel #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="T:RevisionRow" /> class.
 /// </summary>
 /// <param name="revision">The revision (<b>-1</b> for current).</param>
 /// <param name="content">The original page content.</param>
 /// <param name="canRollback">A value indicating whether the current user can rollback the page.</param>
 public RevisionRow(int revision, PageContent content, bool canRollback)
 {
     this.page = content.PageInfo.FullName;
     if(revision == -1) this.revision = Properties.Messages.Current;
     else this.revision = revision.ToString();
     title = FormattingPipeline.PrepareTitle(content.Title, false, FormattingContext.PageContent, content.PageInfo);
     savedOn = Preferences.AlignWithTimezone(content.LastModified).ToString(Settings.DateTimeFormat);
     savedBy = Users.UserLink(content.User);
     comment = content.Comment;
     this.canRollback = canRollback;
 }
Beispiel #10
0
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.Title = Properties.Messages.HistoryTitle + " - " + Settings.WikiTitle;

            page = Pages.FindPage(Request["Page"]);

            if(page != null) {
                canRollback = AuthChecker.CheckActionForPage(page, Actions.ForPages.ManagePage,
                    SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());

                content = Content.GetPageContent(page, true);
                lblTitle.Text = Properties.Messages.PageHistory + ": " + FormattingPipeline.PrepareTitle(content.Title, false, FormattingContext.PageContent, page);

                bool canView = AuthChecker.CheckActionForPage(page, Actions.ForPages.ReadPage,
                    SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
                if(!canView) UrlTools.Redirect("AccessDenied.aspx");
            }
            else {
                lblTitle.Text = Properties.Messages.PageNotFound;
                return;
            }

            if(!Page.IsPostBack && page != null) {
                List<int> revisions = Pages.GetBackups(page);
                revisions.Reverse();
                // Populate dropdown lists
                lstRev1.Items.Clear();
                lstRev2.Items.Clear();
                lstRev2.Items.Add(new ListItem(Properties.Messages.Current, "Current"));
                if(Request["Rev2"] != null && Request["Rev2"].Equals(lstRev2.Items[0].Value))
                    lstRev2.SelectedIndex = 0;
                for(int i = 0; i < revisions.Count; i++) {
                    lstRev1.Items.Add(new ListItem(revisions[i].ToString(), revisions[i].ToString()));
                    lstRev2.Items.Add(new ListItem(revisions[i].ToString(), revisions[i].ToString()));
                    if(Request["Rev1"] != null && Request["Rev1"].Equals(lstRev1.Items[i].Value))
                        lstRev1.SelectedIndex = i;
                    if(Request["Rev2"] != null && Request["Rev2"].Equals(lstRev2.Items[i + 1].Value))
                        lstRev2.SelectedIndex = i + 1;
                }
                if(revisions.Count == 0) btnCompare.Enabled = false;
            }

            PrintHistory();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="T:PageRow" /> class.
        /// </summary>
        /// <param name="page">The original page.</param>
        /// <param name="currentContent">The current content.</param>
        /// <param name="firstContent">The first revision content.</param>
        /// <param name="discussionCount">The number of messages in the discussion.</param>
        /// <param name="revisionCount">The number of revisions.</param>
        /// <param name="isOrphan">A value indicating whether the page is orphan.</param>
        /// <param name="canEdit">A value indicating whether the current user can edit the page.</param>
        /// <param name="canSelect">A value indicating whether the current user can select the page.</param>
        /// <param name="canSetPermissions">A value indicating whether the current user can set permissions for the page.</param>
        /// <param name="selected">A value indicating whether the page is selected.</param>
        public PageRow(PageInfo page, PageContent currentContent, PageContent firstContent, int discussionCount, int revisionCount,
            bool isOrphan, bool canEdit, bool canSelect, bool canSetPermissions, bool selected)
        {
            fullName = page.FullName;
            title = FormattingPipeline.PrepareTitle(currentContent.Title, false, FormattingContext.Other, page);
            createdBy = firstContent.User;
            createdOn = Preferences.AlignWithTimezone(page.CreationDateTime).ToString(Settings.DateTimeFormat);
            lastModifiedBy = currentContent.User;
            lastModifiedOn = Preferences.AlignWithTimezone(currentContent.LastModified).ToString(Settings.DateTimeFormat);
            discussion = discussionCount.ToString();
            revisions = revisionCount.ToString();
            provider = page.Provider.Information.Name;

            this.isOrphan = isOrphan;

            this.canEdit = canEdit;
            this.canSelect = canSelect;
            this.canSetPermissions = canSetPermissions;
            additionalClass = selected ? " selected" : "";
        }
Beispiel #12
0
        protected void Page_Load(object sender, EventArgs e)
        {
            discussMode = Request["Discuss"] != null;
            viewCodeMode = Request["Code"] != null && !discussMode;
            if(!Settings.EnableViewPageCodeFeature) viewCodeMode = false;

            currentPage = DetectPageInfo(true);

            VerifyAndPerformRedirects();

            // The following actions are verified:
            // - View content (redirect to AccessDenied)
            // - Edit or Edit with Approval (for button display)
            // - Any Administrative activity (Rollback/Admin/Perms) (for button display)
            // - Download attachments (for button display - download permissions are also checked in GetFile)
            // - View discussion (for button display in content mode)
            // - Post discussion (for button display in discuss mode)

            string currentUsername = SessionFacade.GetCurrentUsername();
            string[] currentGroups = SessionFacade.GetCurrentGroupNames();

            bool canView = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ReadPage, currentUsername, currentGroups);
            bool canEdit = false;
            bool canEditWithApproval = false;
            Pages.CanEditPage(currentPage, currentUsername, currentGroups, out canEdit, out canEditWithApproval);
            if(canEditWithApproval && canEdit) canEditWithApproval = false;
            bool canDownloadAttachments = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.DownloadAttachments, currentUsername, currentGroups);
            bool canSetPerms = AuthChecker.CheckActionForGlobals(Actions.ForGlobals.ManagePermissions, currentUsername, currentGroups);
            bool canAdmin = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ManagePage, currentUsername, currentGroups);
            bool canViewDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ReadDiscussion, currentUsername, currentGroups);
            bool canPostDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.PostDiscussion, currentUsername, currentGroups);
            bool canManageDiscussion = AuthChecker.CheckActionForPage(currentPage, Actions.ForPages.ManageDiscussion, currentUsername, currentGroups);

            if(!canView) {
                if(SessionFacade.LoginKey == null) UrlTools.Redirect("Login.aspx?Redirect=" + Tools.UrlEncode(Request.Url.ToString()));
                else UrlTools.Redirect(UrlTools.BuildUrl("AccessDenied.aspx"));
            }
            attachmentViewer.Visible = canDownloadAttachments;

            attachmentViewer.PageInfo = currentPage;
            currentContent = Content.GetPageContent(currentPage, true);

            pnlPageInfo.Visible = Settings.EnablePageInfoDiv;

            SetupTitles();

            SetupToolbarLinks(canEdit || canEditWithApproval, canViewDiscussion, canPostDiscussion, canDownloadAttachments, canAdmin, canAdmin, canSetPerms);

            SetupLabels();
            SetupPrintAndRssLinks();
            SetupMetaInformation();
            VerifyAndPerformPageRedirection();
            SetupRedirectionSource();
            SetupNavigationPaths();
            SetupAdjacentPages();

            SessionFacade.Breadcrumbs.AddPage(currentPage);
            SetupBreadcrumbsTrail();

            SetupDoubleClickHandler();

            SetupEmailNotification();

            SetupPageContent(canPostDiscussion, canManageDiscussion);
        }
Beispiel #13
0
        /// <summary>
        /// Sets the Content of a Page.
        /// </summary>
        /// <param name="pageInfo">The Page Info object related to the Content being stored.</param>
        /// <param name="content">The Content of the Page.</param>
        /// <exception cref="ArgumentNullException">If <b>pageInfo</b> or <b>content</b> are <c>null</c>.</exception>
        public void SetPageContent(PageInfo pageInfo, PageContent content)
        {
            if(pageInfo == null) throw new ArgumentNullException("pageInfo");
            if(content == null) throw new ArgumentNullException("content");

            lock(_pageContentCache) {
                _pageContentCache[pageInfo] = content;
                lock(_pageCacheUsage) {
                    _pageCacheUsage[pageInfo] = 0;
                }
            }
        }
Beispiel #14
0
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.Title = Properties.Messages.PostTitle + " - " + Settings.WikiTitle;

            if(Request["Page"] == null) UrlTools.RedirectHome();
            page = Pages.FindPage(Request["Page"]);
            if(page == null) UrlTools.RedirectHome();
            editor.CurrentPage = page;

            if(page.Provider.ReadOnly) UrlTools.Redirect(UrlTools.BuildUrl(page.FullName, Settings.PageExtension));

            content = Content.GetPageContent(page, true);
            if(!Page.IsPostBack) lblTitle.Text += " - " + FormattingPipeline.PrepareTitle(content.Title, false, FormattingContext.MessageBody, page);

            // Verify permissions and setup captcha
            bool canPostMessage = AuthChecker.CheckActionForPage(page, Actions.ForPages.PostDiscussion,
                SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
            if(!canPostMessage) UrlTools.Redirect(UrlTools.BuildUrl(Tools.UrlEncode(page.FullName), Settings.PageExtension));
            captcha.Visible = SessionFacade.LoginKey == null && !Settings.DisableCaptchaControl;

            if(Page.IsPostBack) return;

            editor.SetContent("", Settings.UseVisualEditorAsDefault);

            string username = Request.UserHostAddress;
            if(SessionFacade.LoginKey != null) username = SessionFacade.CurrentUsername;

            bool edit = Request["Edit"] != null;

            if(!edit) {
                if(Request["Parent"] != null) {
                    try {
                        int.Parse(Request["Parent"]);
                    }
                    catch {
                        UrlTools.RedirectHome();
                    }
                    Message[] messages = Pages.GetPageMessages(page);
                    Message parent = Pages.FindMessage(messages, int.Parse(Request["Parent"]));

                    if(parent != null) {
                        txtSubject.Text = (!parent.Subject.ToLowerInvariant().StartsWith("re:") ? "Re: " : "") + parent.Subject;
                    }
                }
            }
            else {
                try {
                    int.Parse(Request["Edit"]);
                }
                catch {
                    UrlTools.RedirectHome();
                }
                Message[] messages = Pages.GetPageMessages(page);
                Message msg = Pages.FindMessage(messages, int.Parse(Request["Edit"]));

                if(msg != null) {
                    txtSubject.Text = msg.Subject;
                    editor.SetContent(msg.Body, Settings.UseVisualEditorAsDefault);
                }
                else throw new Exception("Message not found (" + page.FullName + "." + Request["Edit"] + ").");
            }
        }
Beispiel #15
0
 public PageContent GetContent()
 {
     return this.content ?? (this.content = this.page.Provider.GetContent(this.page));
 }
        public void RemovePageContent()
        {
            ICacheProviderV30 prov = GetProvider();

            PageInfo p1 = new PageInfo("Page1", MockPagesProvider(), DateTime.Now);
            PageInfo p2 = new PageInfo("Page2", MockPagesProvider(), DateTime.Now);
            PageContent c1 = new PageContent(p1, "Page 1", "admin", DateTime.Now, "Comment", "Content", null, null);
            PageContent c2 = new PageContent(p2, "Page 2", "user", DateTime.Now, "", "Blah", null, null);

            Assert.AreEqual(0, prov.PageCacheUsage, "Wrong cache usage");

            prov.SetPageContent(p1, c1);
            prov.SetPageContent(p2, c2);
            prov.SetFormattedPageContent(p1, "Content 1");
            prov.SetFormattedPageContent(p2, "Content 2");

            Assert.AreEqual(2, prov.PageCacheUsage, "Wrong cache usage");

            prov.RemovePage(p2);

            Assert.IsNotNull(prov.GetFormattedPageContent(p1), "GetFormattedPageContent should not return null");
            Assert.IsNotNull(prov.GetPageContent(p1), "GetPageContent should not return null");

            Assert.IsNull(prov.GetFormattedPageContent(p2), "GetFormattedPageContent should return null");
            Assert.IsNull(prov.GetPageContent(p2), "GetPageContent should return null");
        }
Beispiel #17
0
        public void SetUp()
        {
            mocks = new MockRepository();

            ISettingsStorageProviderV30 settingsProvider = mocks.StrictMock<ISettingsStorageProviderV30>();
            Expect.Call(settingsProvider.GetSetting("ProcessSingleLineBreaks")).Return("false").Repeat.Any();

            Collectors.SettingsProvider = settingsProvider;

            IPagesStorageProviderV30 pagesProvider = mocks.StrictMock<IPagesStorageProviderV30>();
            Collectors.PagesProviderCollector = new ProviderCollector<IPagesStorageProviderV30>();
            Collectors.PagesProviderCollector.AddProvider(pagesProvider);

            Expect.Call(settingsProvider.GetSetting("DefaultPagesProvider")).Return(pagesProvider.GetType().FullName).Repeat.Any();

            PageInfo page1 = new PageInfo("page1", pagesProvider, DateTime.Now);
            PageContent page1Content = new PageContent(page1, "Page 1", "User", DateTime.Now, "Comment", "Content", null, null);
            Expect.Call(pagesProvider.GetPage("page1")).Return(page1).Repeat.Any();
            Expect.Call(pagesProvider.GetContent(page1)).Return(page1Content).Repeat.Any();

            Expect.Call(pagesProvider.GetPage("page2")).Return(null).Repeat.Any();

            //Pages.Instance = new Pages();

            Host.Instance = new Host();

            Expect.Call(settingsProvider.GetSetting("CacheSize")).Return("100").Repeat.Any();
            Expect.Call(settingsProvider.GetSetting("CacheCutSize")).Return("20").Repeat.Any();

            Expect.Call(settingsProvider.GetSetting("DefaultCacheProvider")).Return(typeof(CacheProvider).FullName).Repeat.Any();

            // Cache needs setting to init
            mocks.Replay(settingsProvider);

            ICacheProviderV30 cacheProvider = new CacheProvider();
            cacheProvider.Init(Host.Instance, "");
            Collectors.CacheProviderCollector = new ProviderCollector<ICacheProviderV30>();
            Collectors.CacheProviderCollector.AddProvider(cacheProvider);

            mocks.Replay(pagesProvider);

            Collectors.FormatterProviderCollector = new ProviderCollector<IFormatterProviderV30>();

            //System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter(new System.IO.StreamWriter(new System.IO.MemoryStream()));
            //System.Web.Hosting.SimpleWorkerRequest request = new System.Web.Hosting.SimpleWorkerRequest("Default.aspx", "?Page=MainPage", writer);
            System.Web.HttpContext.Current = new System.Web.HttpContext(new DummyRequest());
        }
        public void SetPageContent_GetPageContent()
        {
            ICacheProviderV30 prov = GetProvider();

            PageInfo p1 = new PageInfo("Page1", MockPagesProvider(), DateTime.Now);
            PageInfo p2 = new PageInfo("Page2", MockPagesProvider(), DateTime.Now);
            PageContent c1 = new PageContent(p1, "Page 1", "admin", DateTime.Now, "Comment", "Content", new string[] { "test", "page" }, null);
            PageContent c2 = new PageContent(p2, "Page 2", "user", DateTime.Now, "", "Blah", null, null);
            PageContent c3 = new PageContent(p2, "Page 5", "john", DateTime.Now, "Comm.", "Blah 222", null, "Description");

            Assert.AreEqual(0, prov.PageCacheUsage, "Wrong cache usage");

            prov.SetPageContent(p1, c1);
            prov.SetPageContent(p2, c2);
            prov.SetPageContent(p2, c3);

            Assert.AreEqual(2, prov.PageCacheUsage, "Wrong cache usage");

            PageContent res = prov.GetPageContent(p1);
            Assert.AreEqual(c1.PageInfo, res.PageInfo, "Wrong page info");
            Assert.AreEqual(c1.Title, res.Title, "Wrong title");
            Assert.AreEqual(c1.User, res.User, "Wrong user");
            Assert.AreEqual(c1.LastModified, res.LastModified, "Wrong date/time");
            Assert.AreEqual(c1.Comment, res.Comment, "Wrong comment");
            Assert.AreEqual(c1.Content, res.Content, "Wrong content");
            Assert.AreEqual(2, c1.Keywords.Length, "Wrong keyword count");
            Assert.AreEqual("test", c1.Keywords[0], "Wrong keyword");
            Assert.AreEqual("page", c1.Keywords[1], "Wrong keyword");
            Assert.IsNull(c1.Description, "Description should be null");

            res = prov.GetPageContent(p2);
            Assert.AreEqual(c3.PageInfo, res.PageInfo, "Wrong page info");
            Assert.AreEqual(c3.Title, res.Title, "Wrong title");
            Assert.AreEqual(c3.User, res.User, "Wrong user");
            Assert.AreEqual(c3.LastModified, res.LastModified, "Wrong date/time");
            Assert.AreEqual(c3.Comment, res.Comment, "Wrong comment");
            Assert.AreEqual(c3.Content, res.Content, "Wrong content");
            Assert.AreEqual(0, c3.Keywords.Length, "Keywords should be empty");
            Assert.AreEqual("Description", c3.Description, "Wrong description");

            Assert.IsNull(prov.GetPageContent(new PageInfo("Blah", MockPagesProvider(), DateTime.Now)), "GetPageContent should return null");
        }
        /// <summary>
        /// Forces to overwrite or create a Backup.
        /// </summary>
        /// <param name="content">The Backup content.</param>
        /// <param name="revision">The revision.</param>
        /// <returns>True if the Backup has been created successfully.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="content"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="revision"/> is less than zero.</exception>
        public bool SetBackupContent(PageContent content, int revision)
        {
            if(content == null) throw new ArgumentNullException("content");
            if(revision < 0) throw new ArgumentOutOfRangeException("Invalid Revision", "revision");

            lock(this) {
                LocalPageInfo local = LoadLocalPageInfo(content.PageInfo);
                if(local == null) return false;

                StringBuilder sb = new StringBuilder();
                sb.Append(content.Title);
                sb.Append("\r\n");
                sb.Append(content.User);
                sb.Append("|");
                sb.Append(content.LastModified.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
                if(!string.IsNullOrEmpty(content.Comment)) {
                    sb.Append("|");
                    sb.Append(Tools.EscapeString(content.Comment));
                }
                sb.Append("\r\n##PAGE##\r\n");
                sb.Append(content.Content);

                string filename = Path.GetFileNameWithoutExtension(local.File) + "." + Tools.GetVersionString(revision) + Path.GetExtension(local.File);
                File.WriteAllText(GetFullPathForPageContent(GetNamespacePartialPathForPageContent(NameTools.GetNamespace(content.PageInfo.FullName)) + filename), sb.ToString());
            }
            return true;
        }
        public void SetPageContent_NullPage()
        {
            ICacheProviderV30 prov = GetProvider();

            PageInfo p1 = new PageInfo("Page1", MockPagesProvider(), DateTime.Now);
            PageContent c1 = new PageContent(p1, "Page 1", "admin", DateTime.Now, "Comment", "Content", null, null);

            prov.SetPageContent(null, c1);
        }
        /// <summary>
        /// Removes a page from the search engine index.
        /// </summary>
        /// <param name="content">The content of the page to remove.</param>
        private void UnindexPage(PageContent content)
        {
            lock(this) {
                string documentName = PageDocument.GetDocumentName(content.PageInfo);

                DumpedDocument ddoc = new DumpedDocument(0, documentName, host.PrepareTitleForIndexing(content.PageInfo, content.Title),
                    PageDocument.StandardTypeTag, content.LastModified);
                index.RemoveDocument(new PageDocument(content.PageInfo, ddoc, TokenizeContent), null);
            }
        }
        /// <summary>
        /// Modifies the Content of a Page.
        /// </summary>
        /// <param name="page">The Page.</param>
        /// <param name="title">The Title of the Page.</param>
        /// <param name="username">The Username.</param>
        /// <param name="dateTime">The Date/Time.</param>
        /// <param name="comment">The Comment of the editor, about this revision.</param>
        /// <param name="content">The Page Content.</param>
        /// <param name="keywords">The keywords, usually used for SEO.</param>
        /// <param name="description">The description, usually used for SEO.</param>
        /// <param name="saveMode">The save mode for this modification.</param>
        /// <returns><c>true</c> if the Page has been modified successfully, <c>false</c> otherwise.</returns>
        /// <remarks>If <b>saveMode</b> equals <b>Draft</b> and a draft already exists, it is overwritten.</remarks>
        /// <exception cref="ArgumentNullException">If <paramref name="page"/>, <paramref name="title"/>, <paramref name="username"/> or <paramref name="content"/> are <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If <paramref name="title"/> or <paramref name="username"/> are empty.</exception>
        public bool ModifyPage(PageInfo page, string title, string username, DateTime dateTime, string comment, string content, string[] keywords, string description, SaveMode saveMode)
        {
            if(page == null) throw new ArgumentNullException("page");
            if(title == null) throw new ArgumentNullException("title");
            if(title.Length == 0) throw new ArgumentException("Title cannot be empty", "title");
            if(username == null) throw new ArgumentNullException("username");
            if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username");
            if(content == null) throw new ArgumentNullException("content"); // content can be empty

            ICommandBuilder builder = GetCommandBuilder();
            DbConnection connection = builder.GetConnection(connString);
            DbTransaction transaction = BeginTransaction(connection);

            PageContent currentContent = GetContent(transaction, page, CurrentRevision);

            PageContent pageContent = new PageContent(page, title, username, dateTime, comment, content, keywords != null ? keywords : new string[0], description);

            switch(saveMode) {
                case SaveMode.Backup:
                    // Do backup (if there is something to backup), delete current version (if any), store new version
                    if(currentContent != null) UnindexPage(currentContent, transaction);
                    Backup(transaction, page);
                    DeleteContent(transaction, page, CurrentRevision);
                    bool done1 = SetContent(transaction, pageContent, CurrentRevision);
                    if(done1) IndexPage(pageContent, transaction);

                    if(done1) CommitTransaction(transaction);
                    else RollbackTransaction(transaction);

                    return done1;
                case SaveMode.Normal:
                    // Delete current version (if any), store new version
                    if(currentContent != null) UnindexPage(currentContent, transaction);
                    DeleteContent(transaction, page, CurrentRevision);
                    bool done2 = SetContent(transaction, pageContent, CurrentRevision);
                    if(done2) IndexPage(pageContent, transaction);

                    if(done2) CommitTransaction(transaction);
                    else RollbackTransaction(transaction);

                    return done2;
                case SaveMode.Draft:
                    // Delete current draft (if any), store new draft
                    DeleteContent(transaction, page, DraftRevision);
                    bool done3 = SetContent(transaction, pageContent, DraftRevision);

                    if(done3) CommitTransaction(transaction);
                    else RollbackTransaction(transaction);

                    return done3;
                default:
                    RollbackTransaction(transaction);
                    throw new NotSupportedException();
            }
        }
        public void SetBackupContent_InexistentRevision_Sub()
        {
            IPagesStorageProviderV30 prov = GetProvider();

            NamespaceInfo ns = prov.AddNamespace("NS");

            PageInfo p = prov.AddPage(ns.Name, "Page", DateTime.Now);
            prov.ModifyPage(p, "Title", "NUnit", DateTime.Now, "Comment", "Content", null, null, SaveMode.Normal);
            prov.ModifyPage(p, "Title1", "NUnit1", DateTime.Now, "Comment1", "Content1", null, null, SaveMode.Backup);

            PageContent testContent = new PageContent(p, "Title100", "NUnit100", DateTime.Now, "Comment100", "Content100", null, null);

            prov.SetBackupContent(testContent, 5);

            PageContent backup = prov.GetBackupContent(p, 5);

            AssertPageContentsAreEqual(testContent, backup);

            int[] baks = prov.GetBackups(p);
            Assert.AreEqual(2, baks.Length, "Wrong backup count");
            Assert.AreEqual(0, baks[0], "Wrong backup number");
            Assert.AreEqual(5, baks[1], "Wrong backup number");
        }
        /// <summary>
        /// Forces to overwrite or create a Backup.
        /// </summary>
        /// <param name="content">The Backup content.</param>
        /// <param name="revision">The revision.</param>
        /// <returns>True if the Backup has been created successfully.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="content"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="revision"/> is less than zero.</exception>
        public bool SetBackupContent(PageContent content, int revision)
        {
            if(content == null) throw new ArgumentNullException("content");
            if(revision < 0) throw new ArgumentOutOfRangeException("revision", "Invalid Revision");

            // 1. DeletebBackup, if any
            // 2. Set new content

            ICommandBuilder builder = GetCommandBuilder();
            DbConnection connection = builder.GetConnection(connString);
            DbTransaction transaction = BeginTransaction(connection);

            DeleteContent(transaction, content.PageInfo, revision);

            bool set = SetContent(transaction, content, revision);

            if(set) CommitTransaction(transaction);
            else RollbackTransaction(transaction);

            return set;
        }
Beispiel #25
0
 /// <summary>
 /// Sets the page content in cache.
 /// </summary>
 /// <param name="page">The page to set the content of.</param>
 /// <param name="content">The content.</param>
 public static void SetPageContent(PageInfo page, PageContent content)
 {
     Provider.SetPageContent(page, content);
     if(Provider.PageCacheUsage > Settings.CacheSize) {
         Provider.CutCache(Settings.CacheCutSize);
     }
 }
Beispiel #26
0
        public void MigratePagesStorageProviderData()
        {
            MockRepository mocks = new MockRepository();

            IPagesStorageProviderV30 source = mocks.StrictMock<IPagesStorageProviderV30>();
            IPagesStorageProviderV30 destination = mocks.StrictMock<IPagesStorageProviderV30>();

            // Setup SOURCE -------------------------

            // Setup snippets
            Snippet s1 = new Snippet("S1", "Blah1", source);
            Snippet s2 = new Snippet("S2", "Blah2", source);
            Expect.Call(source.GetSnippets()).Return(new Snippet[] { s1, s2 });

            // Setup content templates
            ContentTemplate ct1 = new ContentTemplate("CT1", "Template 1", source);
            ContentTemplate ct2 = new ContentTemplate("CT2", "Template 2", source);
            Expect.Call(source.GetContentTemplates()).Return(new ContentTemplate[] { ct1, ct2 });

            // Setup namespaces
            NamespaceInfo ns1 = new NamespaceInfo("NS1", source, null);
            NamespaceInfo ns2 = new NamespaceInfo("NS2", source, null);
            Expect.Call(source.GetNamespaces()).Return(new NamespaceInfo[] { ns1, ns2 });

            // Setup pages
            PageInfo p1 = new PageInfo("Page", source, DateTime.Now);
            PageInfo p2 = new PageInfo(NameTools.GetFullName(ns1.Name, "Page"), source, DateTime.Now);
            PageInfo p3 = new PageInfo(NameTools.GetFullName(ns1.Name, "Page1"), source, DateTime.Now);
            Expect.Call(source.GetPages(null)).Return(new PageInfo[] { p1 });
            Expect.Call(source.GetPages(ns1)).Return(new PageInfo[] { p2, p3 });
            Expect.Call(source.GetPages(ns2)).Return(new PageInfo[0]);

            // Set default page for NS1
            ns1.DefaultPage = p2;

            // Setup categories/bindings
            CategoryInfo c1 = new CategoryInfo("Cat", source);
            c1.Pages = new string[] { p1.FullName };
            CategoryInfo c2 = new CategoryInfo(NameTools.GetFullName(ns1.Name, "Cat"), source);
            c2.Pages = new string[] { p2.FullName };
            CategoryInfo c3 = new CategoryInfo(NameTools.GetFullName(ns1.Name, "Cat1"), source);
            c3.Pages = new string[0];
            Expect.Call(source.GetCategories(null)).Return(new CategoryInfo[] { c1 });
            Expect.Call(source.GetCategories(ns1)).Return(new CategoryInfo[] { c2, c3 });
            Expect.Call(source.GetCategories(ns2)).Return(new CategoryInfo[0]);

            // Setup drafts
            PageContent d1 = new PageContent(p1, "Draft", "NUnit", DateTime.Now, "Comm", "Cont", new string[] { "k1", "k2" }, "Descr");
            Expect.Call(source.GetDraft(p1)).Return(d1);
            Expect.Call(source.GetDraft(p2)).Return(null);
            Expect.Call(source.GetDraft(p3)).Return(null);

            // Setup content
            PageContent ctn1 = new PageContent(p1, "Title1", "User1", DateTime.Now, "Comm1", "Cont1", null, "Descr1");
            PageContent ctn2 = new PageContent(p2, "Title2", "User2", DateTime.Now, "Comm2", "Cont2", null, "Descr2");
            PageContent ctn3 = new PageContent(p3, "Title3", "User3", DateTime.Now, "Comm3", "Cont3", null, "Descr3");
            Expect.Call(source.GetContent(p1)).Return(ctn1);
            Expect.Call(source.GetContent(p2)).Return(ctn2);
            Expect.Call(source.GetContent(p3)).Return(ctn3);

            // Setup backups
            Expect.Call(source.GetBackups(p1)).Return(new int[] { 0, 1 });
            Expect.Call(source.GetBackups(p2)).Return(new int[] { 0 });
            Expect.Call(source.GetBackups(p3)).Return(new int[0]);
            PageContent bak1_0 = new PageContent(p1, "K1_0", "U1_0", DateTime.Now, "", "Cont", null, null);
            PageContent bak1_1 = new PageContent(p1, "K1_1", "U1_1", DateTime.Now, "", "Cont", null, null);
            PageContent bak2_0 = new PageContent(p2, "K2_0", "U2_0", DateTime.Now, "", "Cont", null, null);
            Expect.Call(source.GetBackupContent(p1, 0)).Return(bak1_0);
            Expect.Call(source.GetBackupContent(p1, 1)).Return(bak1_1);
            Expect.Call(source.GetBackupContent(p2, 0)).Return(bak2_0);

            // Messages
            Message m1 = new Message(1, "User1", "Subject1", DateTime.Now, "Body1");
            m1.Replies = new Message[] { new Message(2, "User2", "Subject2", DateTime.Now, "Body2") };
            Message[] p1m = new Message[] { m1 };
            Message[] p2m = new Message[0];
            Message[] p3m = new Message[0];
            Expect.Call(source.GetMessages(p1)).Return(p1m);
            Expect.Call(source.GetMessages(p2)).Return(p2m);
            Expect.Call(source.GetMessages(p3)).Return(p3m);

            // Setup navigation paths
            NavigationPath n1 = new NavigationPath("N1", source);
            n1.Pages = new string[] { p1.FullName };
            NavigationPath n2 = new NavigationPath(NameTools.GetFullName(ns1.Name, "N1"), source);
            n2.Pages = new string[] { p2.FullName, p3.FullName };
            Expect.Call(source.GetNavigationPaths(null)).Return(new NavigationPath[] { n1 });
            Expect.Call(source.GetNavigationPaths(ns1)).Return(new NavigationPath[] { n2 });
            Expect.Call(source.GetNavigationPaths(ns2)).Return(new NavigationPath[0]);

            // Setup DESTINATION --------------------------

            // Snippets
            Expect.Call(destination.AddSnippet(s1.Name, s1.Content)).Return(new Snippet(s1.Name, s1.Content, destination));
            Expect.Call(source.RemoveSnippet(s1.Name)).Return(true);
            Expect.Call(destination.AddSnippet(s2.Name, s2.Content)).Return(new Snippet(s2.Name, s2.Content, destination));
            Expect.Call(source.RemoveSnippet(s2.Name)).Return(true);

            // Content templates
            Expect.Call(destination.AddContentTemplate(ct1.Name, ct1.Content)).Return(new ContentTemplate(ct1.Name, ct1.Name, destination));
            Expect.Call(source.RemoveContentTemplate(ct1.Name)).Return(true);
            Expect.Call(destination.AddContentTemplate(ct2.Name, ct2.Content)).Return(new ContentTemplate(ct2.Name, ct2.Name, destination));
            Expect.Call(source.RemoveContentTemplate(ct2.Name)).Return(true);

            // Namespaces
            NamespaceInfo ns1Out = new NamespaceInfo(ns1.Name, destination, null);
            NamespaceInfo ns2Out = new NamespaceInfo(ns2.Name, destination, null);
            Expect.Call(destination.AddNamespace(ns1.Name)).Return(ns1Out);
            Expect.Call(source.RemoveNamespace(ns1)).Return(true);
            Expect.Call(destination.AddNamespace(ns2.Name)).Return(ns2Out);
            Expect.Call(source.RemoveNamespace(ns2)).Return(true);

            // Pages/drafts/content/backups/messages
            PageInfo p1Out = new PageInfo(p1.FullName, destination, p1.CreationDateTime);
            Expect.Call(destination.AddPage(null, p1.FullName, p1.CreationDateTime)).Return(p1Out);
            Expect.Call(destination.ModifyPage(p1Out, ctn1.Title, ctn1.User, ctn1.LastModified, ctn1.Comment, ctn1.Content, ctn1.Keywords, ctn1.Description, SaveMode.Normal)).Return(true);
            Expect.Call(destination.ModifyPage(p1Out, d1.Title, d1.User, d1.LastModified, d1.Comment, d1.Content, d1.Keywords, d1.Description, SaveMode.Draft)).Return(true);
            Expect.Call(destination.SetBackupContent(bak1_0, 0)).Return(true);
            Expect.Call(destination.SetBackupContent(bak1_1, 1)).Return(true);
            Expect.Call(destination.BulkStoreMessages(p1Out, p1m)).Return(true);
            Expect.Call(source.RemovePage(p1)).Return(true);

            PageInfo p2Out = new PageInfo(p2.FullName, destination, p2.CreationDateTime);
            Expect.Call(destination.AddPage(NameTools.GetNamespace(p2.FullName), NameTools.GetLocalName(p2.FullName),
                p2.CreationDateTime)).Return(p2Out);
            Expect.Call(destination.ModifyPage(p2Out, ctn2.Title, ctn2.User, ctn2.LastModified, ctn2.Comment, ctn2.Content, ctn2.Keywords, ctn2.Description, SaveMode.Normal)).Return(true);
            Expect.Call(destination.SetBackupContent(bak2_0, 0)).Return(true);
            Expect.Call(destination.BulkStoreMessages(p2Out, p2m)).Return(true);
            Expect.Call(source.RemovePage(p2)).Return(true);

            PageInfo p3Out = new PageInfo(p3.FullName, destination, p3.CreationDateTime);
            Expect.Call(destination.AddPage(NameTools.GetNamespace(p3.FullName), NameTools.GetLocalName(p3.FullName),
                p3.CreationDateTime)).Return(p3Out);
            Expect.Call(destination.ModifyPage(p3Out, ctn3.Title, ctn3.User, ctn3.LastModified, ctn3.Comment, ctn3.Content, ctn3.Keywords, ctn3.Description, SaveMode.Normal)).Return(true);
            Expect.Call(destination.BulkStoreMessages(p3Out, p3m)).Return(true);
            Expect.Call(source.RemovePage(p3)).Return(true);

            // Categories/bindings
            CategoryInfo c1Out = new CategoryInfo(c1.FullName, destination);
            CategoryInfo c2Out = new CategoryInfo(c2.FullName, destination);
            CategoryInfo c3Out = new CategoryInfo(c3.FullName, destination);
            Expect.Call(destination.AddCategory(null, c1.FullName)).Return(c1Out);
            Expect.Call(destination.AddCategory(NameTools.GetNamespace(c2.FullName), NameTools.GetLocalName(c2.FullName))).Return(c2Out);
            Expect.Call(destination.AddCategory(NameTools.GetNamespace(c3.FullName), NameTools.GetLocalName(c3.FullName))).Return(c3Out);
            Expect.Call(destination.RebindPage(p1Out, new string[] { c1.FullName })).Return(true);
            Expect.Call(destination.RebindPage(p2Out, new string[] { c2.FullName })).Return(true);
            Expect.Call(destination.RebindPage(p3Out, new string[0])).Return(true);
            Expect.Call(source.RemoveCategory(c1)).Return(true);
            Expect.Call(source.RemoveCategory(c2)).Return(true);
            Expect.Call(source.RemoveCategory(c3)).Return(true);

            // Navigation paths
            NavigationPath n1Out = new NavigationPath(n1.FullName, destination);
            n1Out.Pages = n1.Pages;
            NavigationPath n2Out = new NavigationPath(n2.FullName, destination);
            n2Out.Pages = n2.Pages;

            Expect.Call(destination.AddNavigationPath(null, n1.FullName, new PageInfo[] { p1 })).Return(n1Out).Constraints(
                RMC.Is.Null(), RMC.Is.Equal(n1.FullName),
                RMC.Is.Matching<PageInfo[]>(delegate(PageInfo[] array) {
                    return array[0].FullName == p1.FullName;
                }));

            Expect.Call(destination.AddNavigationPath(NameTools.GetNamespace(n2.FullName), NameTools.GetLocalName(n2.FullName), new PageInfo[] { p2, p3 })).Return(n2Out).Constraints(
                RMC.Is.Equal(NameTools.GetNamespace(n2.FullName)), RMC.Is.Equal(NameTools.GetLocalName(n2.FullName)),
                RMC.Is.Matching<PageInfo[]>(delegate(PageInfo[] array) {
                    return array[0].FullName == p2.FullName && array[1].FullName == p3.FullName;
                }));

            Expect.Call(source.RemoveNavigationPath(n1)).Return(true);
            Expect.Call(source.RemoveNavigationPath(n2)).Return(true);

            Expect.Call(destination.SetNamespaceDefaultPage(ns1Out, p2Out)).Return(ns1Out);
            Expect.Call(destination.SetNamespaceDefaultPage(ns2Out, null)).Return(ns2Out);

            // Used for navigation paths
            Expect.Call(destination.GetPages(null)).Return(new PageInfo[] { p1Out });
            Expect.Call(destination.GetPages(ns1Out)).Return(new PageInfo[] { p2Out, p3Out });
            Expect.Call(destination.GetPages(ns2Out)).Return(new PageInfo[0]);

            mocks.Replay(source);
            mocks.Replay(destination);

            DataMigrator.MigratePagesStorageProviderData(source, destination);

            mocks.Verify(source);
            mocks.Verify(destination);
        }