Пример #1
0
        //--- Methods ---
        public virtual OldBE Copy()
        {
            OldBE old = new OldBE();

            old._Comment    = _Comment;
            old.DisplayName = DisplayName;
            old._TimeStamp  = _TimeStamp;
            old._pageId     = _pageId;
            old.ContentType = ContentType;
            old.ID          = ID;
            old.IsHidden    = IsHidden;
            old.Language    = Language;
            old.Meta        = Meta;
            old.MinorEdit   = MinorEdit;
            old.Revision    = Revision;
            old.Text        = Text;
            old.UserID      = UserID;
            return(old);
        }
Пример #2
0
        //--- Methods ---

        // TODO (brigettek): page text needs to be stored separately from the page
        public string GetText(IDekiDataSession session)
        {
            //page_text is lazy loaded if it doesn't exist.
            if (_text == null)
            {
                if (ID != 0)
                {
                    PageTextContainer pageTextContainer = session.Pages_GetContents(new List <ulong>()
                    {
                        ID
                    }).FirstOrDefault();
                    if (null != pageTextContainer)
                    {
                        // TODO (brigettek): Do we still need to go to the old table?
                        if (pageTextContainer.TimeStamp == TimeStamp)
                        {
                            _text = pageTextContainer.Text;
                        }
                        else
                        {
                            OldBE oldPage = session.Old_GetOldByTimestamp(ID, TimeStamp);
                            if (oldPage != null)
                            {
                                _text = oldPage.Text;
                            }
                            else
                            {
                                throw new OldIdNotFoundException(ID, TimeStamp);
                            }
                        }
                    }
                }
                else
                {
                    _text = string.Empty;
                }
            }
            return(_text);
        }
Пример #3
0
 //--- Methods ---
 public virtual OldBE Copy() {
     OldBE old = new OldBE();
     old._Comment = _Comment;
     old.DisplayName = DisplayName;
     old._TimeStamp = _TimeStamp;
     old._pageId = _pageId;
     old.ContentType = ContentType;
     old.ID = ID;
     old.IsHidden = IsHidden;
     old.Language = Language;
     old.Meta = Meta;
     old.MinorEdit = MinorEdit;
     old.Revision = Revision;
     old.Text = Text;
     old.UserID = UserID;
     return old;
 }
Пример #4
0
 public static void AddEditPageRecentChange(DateTime timestamp, PageBE title, UserBE user, string comment, OldBE old) {
     DbUtils.CurrentSession.RecentChanges_Insert(timestamp, title, user, comment, old.ID, RC.EDIT, 0, String.Empty, false, 0);
 }
Пример #5
0
 public static void AddEditPageRecentChange(DateTime timestamp, PageBE title, UserBE user, DekiResourceBuilder comment, OldBE old) {
     var resources = DekiContext.Current.Resources;
     DbUtils.CurrentSession.RecentChanges_Insert(timestamp, title, user, comment.Localize(resources), old.ID, RC.EDIT, 0, String.Empty, false, 0);
 }
Пример #6
0
 public static OldBE Save(PageBE page, OldBE previous, string userComment, string text, string contentType, string displayName, string language, int section, string xpath, DateTime timeStamp, ulong restoredPageId, bool loggingEnabled, bool removeIllegalElements, Title relToTitle, bool overwrite, out bool conflict) {
     return Save(page, previous, userComment, text, contentType, displayName, language, section, xpath, timeStamp, restoredPageId, loggingEnabled, removeIllegalElements, relToTitle, overwrite, DekiContext.Current.User.ID, out conflict);
 }
Пример #7
0
        public static OldBE Save(PageBE page, OldBE previous, string userComment, string text, string contentType, string displayName, string language, int section, string xpath, DateTime timeStamp, ulong restoredPageId, bool loggingEnabled, bool removeIllegalElements, Title relToTitle, bool overwrite, uint authorId, out bool conflict) {

            // NOTE (steveb):
            //  page: most recent page about to be overwritten
            //  previous: (optional) possible earlier page on which the current edit is based upon

            conflict = false;
            bool isNewForEventContext = page.ID == 0 || page.IsRedirect;

            // check save permissions
            IsAccessAllowed(page, 0 == page.ID ? Permissions.CREATE : Permissions.UPDATE, false);

            // validate the save
            if((0 == page.ID) && ((-1 != section) || (null != xpath))) {
                throw new ArgumentException(DekiResources.SECTION_EDIT_EXISTING_PAGES_ONLY);
            }

            // displaynames entered by user are trimmed
            if(displayName != null) {
                displayName = displayName.Trim();
            }

            if(!Title.FromDbPath(page.Title.Namespace, page.Title.AsUnprefixedDbPath(), displayName).IsValid) {
                throw new DreamAbortException(DreamMessage.Conflict(DekiResources.INVALID_TITLE));
            }

            // load old contents into current page when a section is edited
            ParserResult alternate = new ParserResult();
            ParserResult original = new ParserResult();
            if(previous != null) {

                // parse most recent version as alternate
                alternate = DekiXmlParser.Parse(page, ParserMode.RAW);

                // parse base version for three way diff
                string pageContentType = page.ContentType;
                string pageText = page.GetText(DbUtils.CurrentSession);
                page.ContentType = previous.ContentType;
                page.SetText(previous.Text);
                original = DekiXmlParser.Parse(page, ParserMode.RAW);
                page.ContentType = pageContentType;
                page.SetText(pageText);
            }

            // ensure the parent exists
            PageBE parent = EnsureParent(DekiXmlParser.REDIRECT_REGEX.IsMatch(text), page.Title);
            if(null != parent) {
                page.ParentID = parent.Title.IsRoot ? 0 : parent.ID;
            }

            // Explicitly setting the language of a talk page is not valid
            if(page.Title.IsTalk && !string.IsNullOrEmpty(language)) {
                throw new Exceptions.TalkPageLanguageCannotBeSet();
            }

            // Language is set in this order: explicitly given, already set, language of parent
            language = language ?? page.Language ?? (null != parent ? parent.Language : String.Empty);

            // talk pages always get their language from their corresponding front page
            if(page.Title.IsTalk) {
                PageBE frontPage = PageBL.GetPageByTitle(page.Title.AsFront());
                if(frontPage != null && frontPage.ID != 0) {
                    language = frontPage.Language;
                }
            }

            string nativeName = ValidatePageLanguage(language);

            // parse the content
            ParserResult parserResult = DekiXmlParser.ParseSave(page, contentType, language, text, section, xpath, removeIllegalElements, relToTitle);
            OldBE old = null;
            string comment = userComment ?? string.Empty;

            // check if this is a new page
            if(0 == page.ID) {
                AuthorizePage(DekiContext.Current.User, Permissions.CREATE, parent, false);

                if(0 == restoredPageId) {
                    if(!string.IsNullOrEmpty(comment)) {
                        comment += "; ";
                    }
                    comment += string.Format(DekiResources.PAGE_CREATED);
                    if((null == parserResult.RedirectsToTitle) && (null == parserResult.RedirectsToUri)) {
                        comment += string.Format(", " + DekiResources.PAGE_DIFF_SUMMARY_ADDED, Utils.GetPageWordCount(parserResult.MainBody));
                    }
                    page.MinorEdit = false;
                    page.IsNew = true;
                }
            }

            // if this is an existing page, ensure the content has changed and save the current page information 
            else {

                // prevent creating a redirect on a page that has non-redirect children
                if((null != parserResult.RedirectsToTitle) || (null != parserResult.RedirectsToUri)) {
                    IList<PageBE> children = DbUtils.CurrentSession.Pages_GetChildren((uint)page.ID, page.Title.Namespace, true);
                    if(0 < children.Count) {
                        throw new DreamAbortException(DreamMessage.Conflict(DekiResources.INVALID_REDIRECT));
                    }
                }

                bool displayNameChanged = page.Title.DisplayName != displayName && displayName != null;
                bool languageChanged = !StringUtil.EqualsInvariant(page.Language, language);
                if(parserResult.ContentType == page.ContentType) {
                    if(StringUtil.EqualsInvariant(parserResult.BodyText, page.GetText(DbUtils.CurrentSession))) {
                        if(!displayNameChanged && !languageChanged && !overwrite) {
                            return null;
                        }
                    } else {

                        // merge changes
                        if(previous != null) {
                            conflict = true;
                            try {
                                XDoc mergeBody = XDocDiff.Merge(original.MainBody, alternate.MainBody, parserResult.MainBody, Utils.MAX_DIFF_SIZE, ArrayMergeDiffPriority.Right, out conflict);
                                parserResult = DekiXmlParser.ParseSave(page, page.ContentType, page.Language, mergeBody.ToInnerXHtml(), -1, null, removeIllegalElements, relToTitle);
                            } catch(Exception e) {
                                _log.Error("Save", e);
                            }
                        }
                        if(!string.IsNullOrEmpty(comment)) {
                            comment += "; ";
                        }
                        if(page.IsRedirect) {
                            comment += string.Format(DekiResources.PAGE_DIFF_SUMMARY_ADDED, Utils.GetPageWordCount(parserResult.MainBody));
                        } else {
                            comment += Utils.GetPageDiffSummary(page, page.GetText(DbUtils.CurrentSession), page.ContentType, parserResult.BodyText, parserResult.ContentType);
                        }
                    }
                } else {
                    if(!string.IsNullOrEmpty(comment)) {
                        comment += "; ";
                    }
                    comment += string.Format(DekiResources.PAGE_CONTENTTYPE_CHANGED, parserResult.ContentType);
                }

                if(displayNameChanged) {
                    if(!string.IsNullOrEmpty(comment)) {
                        comment += "; ";
                    }
                    comment += string.Format(DekiResources.PAGE_DISPLAYNAME_CHANGED, displayName);

                }

                if(languageChanged) {
                    if(!string.IsNullOrEmpty(comment)) {
                        comment += "; ";
                    }
                    comment += string.Format(DekiResources.PAGE_LANGUAGE_CHANGED, nativeName);

                    // set the language on the talk page as well.
                    if(!page.Title.IsTalk) {
                        PageBE talkPage = PageBL.GetPageByTitle(page.Title.AsTalk());
                        if(talkPage != null && talkPage.ID != 0) {
                            SetPageLanguage(talkPage, language, true);
                        }
                    }
                }
                old = InsertOld(page, 0);
                page.MinorEdit = (page.UserID == DekiContext.Current.User.ID) && (DateTime.Now < page.TimeStamp.AddMinutes(15));
                page.IsNew = false;
            }

            // update the page information to reflect the new content
            page.Comment = comment;
            page.ContentType = parserResult.ContentType;
            page.Language = language;
            page.UserID = authorId;
            var bodyText = string.Empty;
            if(parserResult.RedirectsToTitle != null) {
                page.IsRedirect = true;
                bodyText = "#REDIRECT [[" + parserResult.RedirectsToTitle.AsPrefixedDbPath() + "]]";
            } else if(parserResult.RedirectsToUri != null) {
                page.IsRedirect = true;
                bodyText = "#REDIRECT [[" + parserResult.RedirectsToUri + "]]";
            } else {
                page.IsRedirect = false;
                bodyText = parserResult.BodyText;
            }
            page.SetText(bodyText);
            page.UseCache = !parserResult.HasScriptContent;
            page.TIP = parserResult.Summary;
            page.Touched = page.TimeStamp = timeStamp;

            // nametype and displayname logic
            if(string.IsNullOrEmpty(displayName) && (page.ID == 0)) {

                // new page created without a title: title comes from the name
                page.Title.DisplayName = page.Title.AsUserFriendlyDisplayName();
            } else if(!string.IsNullOrEmpty(displayName)){

                // title is provided: title set from provided value
                page.Title.DisplayName = displayName;
            } else {
                // preserve the display name of the page
            }

            // Note (arnec): Using Encoding.UTF8 because the default is Encoding.Unicode which produces a different md5sum than expected from ascii
            page.Etag = StringUtil.ComputeHashString(bodyText, Encoding.UTF8);

            // insert or update the page
            if(0 == page.ID) {
                if(restoredPageId == 0) {

                    // only set the revision if this isn't a restore.
                    page.Revision = 1;
                }
                ulong pageId = DbUtils.CurrentSession.Pages_Insert(page, restoredPageId);
                if(pageId != 0) {

                    //TODO Max: the existing page object is being modified with the ID instead of using the new object
                    page.ID = pageId;
                    if(loggingEnabled) {
                        RecentChangeBL.AddNewPageRecentChange(page.TimeStamp, page, DekiContext.Current.User, comment);
                    }

                    // Copy permissions from parent if the page is a child of homepage or Special:
                    ulong parentPageId = page.ParentID;
                    if((parentPageId == 0) && (parent != null) && (page.Title.IsMain || page.Title.IsSpecial)) {
                        parentPageId = parent.ID;
                    }
                    if(parentPageId > 0) {
                        DbUtils.CurrentSession.Grants_CopyToPage(parentPageId, page.ID);
                    }
                    
                    // never log creation of userhomepages to recentchanges
                    if(loggingEnabled && page.Title.IsUser && page.Title.GetParent().IsHomepage) {
                        loggingEnabled = false;
                    }
                }
            } else {
                page.Revision++;
                DbUtils.CurrentSession.Pages_Update(page);
                if(loggingEnabled) {
                    RecentChangeBL.AddEditPageRecentChange(page.TimeStamp, page, DekiContext.Current.User, comment, old);
                }
            }
            try {
                if(null != parserResult.Templates) {
                    ImportTemplatePages(page, parserResult.Templates.ToArray());
                }
                if(null != parserResult.Tags) {
                    ImportPageTags(page, parserResult.Tags.ToArray());
                }
                if(null != parserResult.Links) {
                    UpdateLinks(page, parserResult.Links.ToArray());
                }
            } finally {
                if(isNewForEventContext) {
                    DekiContext.Current.Instance.EventSink.PageCreate(DreamContext.Current.StartTime, page, DekiContext.Current.User);
                } else {
                    DekiContext.Current.Instance.EventSink.PageUpdate(DreamContext.Current.StartTime, page, DekiContext.Current.User);
                }
            }
            return old;
        }
Пример #8
0
        internal static XDoc GetOldXml(PageBE pageCurrent, OldBE old, string relation) {

            // retrieve the page xml summary
            // NOTE (maxm): The old to page copying is done for revision hiding
            PageBE pageFromOld = new PageBE();
            CopyOldToPage(old, pageFromOld, pageCurrent.Title);
            XDoc oldXml = PageBL.GetPageXml(pageFromOld, relation);

            // add revision-specific information to it
            oldXml.Attr("revision", old.Revision.ToString());
            oldXml.Attr("href", DekiContext.Current.ApiUri.At("pages", pageCurrent.ID.ToString(), "revisions").With("revision", old.Revision.ToString()).With("redirects", "0"));
            oldXml.Start("date.edited").Value(old.TimeStamp).End();
            UserBE author = UserBL.GetUserById(old.UserID);
            if(author != null)
                oldXml.Add(UserBL.GetUserXml(author, "author", Utils.ShowPrivateUserInfo(author)));


            if(!old.IsHidden || PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN)) {
                oldXml.Start("description").Value(old.Comment).End();
            } else {

                //if rev is hidden && non admin, dont show comment and add @hidden=true
                oldXml.Start("description").Attr("hidden", true).End();
            }

            oldXml.Start("contents").Attr("type", old.ContentType).Attr("href", DekiContext.Current.ApiUri.At("pages", pageCurrent.ID.ToString(), "contents").With("revision", old.Revision.ToString()).With("redirects", "0")).End();

            if(old.IsHidden) {
                uint? userIdHiddenBy = old.MetaXml[ResourceBE.META_REVHIDE_USERID].AsUInt;
                if(userIdHiddenBy != null) {
                    UserBE userHiddenBy = UserBL.GetUserById(userIdHiddenBy.Value);
                    if(userHiddenBy != null) {
                        oldXml.Add(UserBL.GetUserXml(userHiddenBy, "hiddenby", Utils.ShowPrivateUserInfo(userHiddenBy)));
                    }
                }
                oldXml.Elem("date.hidden", old.MetaXml[ResourceBE.META_REVHIDE_TS].AsDate ?? DateTime.MinValue);
                oldXml.Elem("description.hidden", old.MetaXml[ResourceBE.META_REVHIDE_COMMENT].AsText ?? string.Empty);
            }
            return oldXml;
        }
Пример #9
0
        public static OldBE InsertOld(PageBE oldPage, ulong restoredOldId) {
            OldBE old = new OldBE();
            PageBL.CopyPageToOld(oldPage, old);
            try {
                uint oldId = DbUtils.CurrentSession.Old_Insert(old, restoredOldId);
                if(oldId == 0) {
                    old = null;
                } else {
                    old.ID = oldId;
                }
            } catch(PageConcurrencyException e) {

                // TODO (arnec): Remove this once OldBE contains the page Id and the OldDA can throw this exception properly
                e.PageId = oldPage.ID;
                throw;
            }
            return old;
        }
Пример #10
0
 public static void CopyPageToOld(PageBE page, OldBE old) {
     old.Text = page.GetText(DbUtils.CurrentSession);
     old.ContentType = page.ContentType;
     old.UserID = page.UserID;
     old.TimeStamp = page.TimeStamp;
     old.MinorEdit = page.MinorEdit;
     old.Comment = page.Comment;
     old.Language = page.Language;
     old.IsHidden = page.IsHidden;
     old.Meta = page.Meta;
     old.Revision = page.Revision;
     old.PageID = page.ID;
     old.DisplayName = page.Title.DisplayName;
 }
Пример #11
0
 public static void CopyOldToPage(OldBE old, PageBE page, Title pageTitle) {
     page.SetText(old.Text);
     page.ContentType = old.ContentType;
     page.UserID = old.UserID;
     page.TimeStamp = old.TimeStamp;
     page.MinorEdit = old.MinorEdit;
     page.Comment = old.Comment;
     page.Language = old.Language;
     page.IsHidden = old.IsHidden;
     page.Meta = old.Meta;
     page.Revision = old.Revision;
     page.ID = old.PageID;
     page.Title = pageTitle;
 }
Пример #12
0
        public static OldBE GetOldRevisionForPage(PageBE page, int revision) {
            OldBE ret = null;
            ulong revisionToLookup;

            if(revision < 0) {
                if((int)page.Revision + revision <= 0) {
                    return null;
                }
                revisionToLookup = (page.Revision + (ulong)revision);
            } else if(revision > 0) {
                revisionToLookup = (ulong)revision;
            } else {
                revisionToLookup = page.Revision;
            }

            if(revisionToLookup == page.Revision) {
                ret = new OldBE();
                CopyPageToOld(page, ret);
            } else {
                ret = DbUtils.CurrentSession.Old_GetOldByRevision(page.ID, revisionToLookup);
            }
            return ret;
        }
Пример #13
0
 public void Old_Update(OldBE oldPage) {
     Stopwatch sw = Stopwatch.StartNew();
     _next.Old_Update(oldPage);
     LogQuery(CATEGORY_OLD, "Old_Update", sw, "oldPage", oldPage);
 }
Пример #14
0
 public uint Old_Insert(OldBE oldPage, ulong restoredOldID) {
     Stopwatch sw = Stopwatch.StartNew();
     var ret = _next.Old_Insert(oldPage, restoredOldID);
     LogQuery(CATEGORY_OLD, "Old_Insert", sw, "oldPage", oldPage, "restoredOldID", restoredOldID);
     return ret;
 }