Esempio n. 1
0
        private void ProcessInternalLink(Regex fileRegex, XDoc addr, Title baseTitle, IList<Title> linksKnown, IList<string> linksBroken, List<Title> linksFound, List<Title> templates, DekiContext deki, out Title lookupLink) {
            lookupLink = null;
            XmlElement current = (XmlElement)addr.AsXmlNode;
            string template = current.GetAttribute("template");
            bool isTemplate = !String.IsNullOrEmpty(template);

            // if this is a link to an anchor on the current page, stop processing
            string href = current.GetAttribute("href").Trim();
            if((href.StartsWithInvariant("#") && !isTemplate) || (href.StartsWithInvariant("{{") && href.EndsWithInvariant("}}"))) {
                return;
            }

            // if this is a link to a subpage from an imported template, process it
            if((ParserMode.SAVE == _mode) && isTemplate) {
                addr.RemoveAttr("template");
                addr.RemoveAttr("class");
                Title templateTitle = Title.FromUIUri(baseTitle, template, false);
                templates.Add(templateTitle);

                // update the link to be relative to the current page instead of the template
                string[] segments = templateTitle.AsUnprefixedDbSegments();
                segments[0] = ".";
                template = String.Join("/", segments);
                addr.Attr("href", template);
                href = template;
            }
            List<string> css = new List<string>();
            bool containsImage = !addr[".//img"].IsEmpty;
            uint fileid;
            Title title;

            // Extract the fileid and title information
            // If the link is of the form "@api/deki/files/{fileid}/={filename}, extract the fileid and filename from it.
            // Otherwise, use the full URL as the title.
            Match m = fileRegex.Match(XUri.Decode(href));
            if(m.Success) {
                UInt32.TryParse(m.Groups["fileid"].Value, out fileid);
                title = Title.FromUIUri(null, "File:/" + m.Groups["filename"].Value);
            } else {
                uint.TryParse(current.GetAttribute("fileid"), out fileid);
                title = Title.FromUIUri(baseTitle, href);
            }

            // If the link has no text provide a default value
            if(addr.Contents.Length == 0) {
                addr.Value(title.IsFile ? title.Filename : Title.FromUIUri(null, href).AsUserFriendlyName());
            }

            // add the db encoded title to the list of links to lookup
            if(!title.IsFile && title.IsEditable) {
                linksFound.Add(title);
            }
            switch(_mode) {
            case ParserMode.EDIT:

                // if the title is a file, return a link in the form @api/deki/files/{fileid}/={filename}
                // TODO (brigettek):  Append the query param
                if(title.IsFile) {
                    if(null != _relToTitle) {

                        // Normalize file link if needed (for import/export)
                        Title fileTitle = GetTitleFromFileId(fileid);
                        if(null != fileTitle) {
                            addr.RemoveAttr("href");
                            addr.Attr("href.path", fileTitle.AsRelativePath(_relToTitle));
                            addr.Attr("href.filename", fileTitle.Filename);
                        }
                    } else {
                        if(0 == fileid) {
                            addr.Attr("href", title.AsEditorUriPath());
                        } else {
                            addr.Attr("href", deki.ApiUri.At("files", fileid.ToString(), Title.AsApiParam(title.Filename)).ToString());
                        }
                    }
                } else {

                    // TODO (brigettek):  Prevent resolving redirects for pages with many links to improve performance
                    // TODO (brigettek):  potential vulnerability.  The title is resolved without verifying that the user has browse permission to it. 
                    PageBE redirectedPage = PageBL.ResolveRedirects(PageBL.GetPageByTitle(title));
                    redirectedPage.Title.Anchor = title.Anchor;
                    redirectedPage.Title.Query = title.Query;
                    title = redirectedPage.Title;
                    if(null != _relToTitle) {

                        // Normalize link if needed (for import/export)
                        addr.RemoveAttr("href");
                        addr.Attr("href.path", title.AsRelativePath(_relToTitle));
                        addr.Attr("href.anchor", title.Anchor);
                        addr.Attr("href.query", title.Query);
                    } else {
                        addr.Attr("href", title.AsEditorUriPath());
                    }
                }
                if(string.IsNullOrEmpty(current.GetAttribute("title"))) {
                    addr.Attr("title", title.IsFile ? title.Filename : title.AsPrefixedUserFriendlyPath());
                }
                addr.RemoveAttr("fileid");
                break;
            case ParserMode.VIEW_NO_EXECUTE:
            case ParserMode.VIEW: {
                    string rel = addr["@rel"].AsText;
                    addr.Attr("rel", "internal");

                    // check if path was generated, if so, keep it as it is
                    if(string.IsNullOrEmpty(rel)) {

                        // check if path is a reference to current page and, if so, make it bold
                        ParserState parseState = GetParseState();
                        foreach(PageBE includingPage in parseState.ProcessingStack) {
                            XDoc item;
                            if((includingPage.Title == title && parseState.ProcessedPages.TryGetValue(GetParserCacheKey(includingPage, _mode), out item) && (item == null))) {
                                XDoc strong = new XDoc("strong");
                                foreach(XmlNode node in addr.AsXmlNode.ChildNodes) {
                                    strong.AsXmlNode.AppendChild(strong.AsXmlNode.OwnerDocument.ImportNode(node, true));
                                }
                                addr.Replace(strong);
                                return;
                            }
                        }
                    }
                }

                // check if link goes to a file attachment
                if(title.IsFile) {

                    // if the file does not exist, display a message accordingly
                    if(0 == fileid) {
                        css.Add("new");
                        if(!containsImage) {
                            var resources = DekiContext.Current.Resources;
                            addr.AddNodesBefore(DekiScriptRuntime.CreateWarningElement(null, "(" + resources.Localize(DekiResources.MISSING_FILE(title.AsPrefixedUserFriendlyPath()) + ")"), null));
                        }
                    } else {
                        if(!containsImage) {
                            css.Add("iconitext-16");
                            css.Add("ext-" + title.Extension);
                        }
                        addr.Attr("href", deki.ApiUri.At("files", fileid.ToString(), Title.AsApiParam(title.Filename)));
                    }
                } else {

                    // check if page exists by first inspecting the links table and, if not found, searching for the page title
                    if(title.IsEditable && !linksKnown.Contains(Title.FromDbPath(title.Namespace, title.Path, null))) {
                        if(linksBroken.Contains(title.AsPrefixedDbPath().ToLowerInvariant())) {
                            css.Add("new");
                        } else {
                            lookupLink = title;
                        }
                    }

                    // check if link goes to a user's page
                    if((title.IsUser) && (1 == title.AsUnprefixedDbSegments().Length)) {
                        css.Add("link-user");
                    }

                    // Update the link to use the site uri
                    addr.Attr("href", Utils.AsPublicUiUri(title));
                }

                if(css.Count > 0 && !containsImage) {
                    css.Add(current.GetAttribute("class"));
                    addr.Attr("class", string.Join(" ", css.ToArray()));
                }
                if(string.IsNullOrEmpty(current.GetAttribute("title"))) {
                    addr.Attr("title", title.IsFile ? title.Filename : title.AsPrefixedUserFriendlyPath());
                }
                addr.RemoveAttr("fileid");
                break;
            }
        }