/** * Given a topic, if that topic is a redirect find the target topic of the redirection. * * @param parent The topic being queried. If this topic is a redirect then the redirect target * will be returned, otherwise the topic itself is returned. * @param attempts The maximum number of child topics to follow. This parameter prevents infinite * loops if topics redirect back to one another. * @return If the parent topic is a redirect then this method returns the target topic that is * being redirected to, otherwise the parent topic is returned. * @throws DataAccessException Thrown if any error occurs while retrieving data. */ public static Topic findRedirectedTopic(Topic parent, int attempts) throws DataAccessException { int count = attempts; String target = parent.getRedirectTo(); if (parent.getTopicType() != TopicType.REDIRECT || StringUtils.isBlank(target)) { logger.error("getRedirectTarget() called for non-redirect topic " + parent.getName()); return parent; } // avoid infinite redirection count++; if (count > 10) { // TODO throw new WikiException(new WikiMessage("topic.redirect.infinite")); return parent; } String virtualWiki = parent.getVirtualWiki(); WikiLink wikiLink = LinkUtil.parseWikiLink(virtualWiki, target); if (wikiLink.getVirtualWiki() != null) { virtualWiki = wikiLink.getVirtualWiki().getName(); } // get the topic that is being redirected to Topic child = WikiBase.getDataHandler().lookupTopic(virtualWiki, wikiLink.getDestination(), false, null); if (child == null) { // child being redirected to doesn't exist, return parent return parent; } if (StringUtils.isBlank(child.getRedirectTo())) { // found a topic that is not a redirect, return return child; } // child is a redirect, keep looking return findRedirectedTopic(child, count); }
@Test(expected = IllegalArgumentException.class) public void testSetNamespace2() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); wikiLink.setNamespace(null); assertEquals( "wikiLink.getNamespace()", Namespace.namespace(Namespace.FILE_ID), wikiLink.getNamespace()); }
@Test public void testSetNamespace() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); wikiLink.setNamespace(Namespace.namespace(Namespace.FILE_ID)); assertEquals( "wikiLink.getNamespace()", Namespace.namespace(Namespace.FILE_ID), wikiLink.getNamespace()); }
/** * Given a topic name, determine if that name corresponds to a comments page. * * @param virtualWiki The current virtual wiki. * @param topicName The topic name (non-null) to examine to determine if it is a comments page or * not. * @return <code>true</code> if the page is a comments page, <code>false</code> otherwise. */ public static boolean isCommentsPage(String virtualWiki, String topicName) { WikiLink wikiLink = LinkUtil.parseWikiLink(virtualWiki, topicName); if (wikiLink.getNamespace().getId().equals(Namespace.SPECIAL_ID)) { return false; } try { return (Namespace.findCommentsNamespace(wikiLink.getNamespace()) != null); } catch (DataAccessException e) { throw new IllegalStateException("Database error while retrieving comments namespace", e); } }
/** * Utility method for building a URL link to a wiki edit page for a specified topic. * * @param context The servlet context for the link that is being created. * @param virtualWiki The virtual wiki for the link that is being created. * @param topic The name of the topic for which an edit link is being created. * @param query Any existing query parameters to append to the edit link. This value may be either * <code>null</code> or empty. * @param section The section defined by the name parameter within the HTML page for the topic * being edited. If provided then the edit link will allow editing of only the specified * section. * @return A url that links to the edit page for the specified topic. Note that this method * returns only the URL, not a fully-formed HTML anchor tag. * @throws DataAccessException Thrown if any error occurs while builing the link URL. */ public static String buildEditLinkUrl( String context, String virtualWiki, String topic, String query, int section) throws DataAccessException { query = LinkUtil.appendQueryParam(query, "topic", topic); if (section > 0) { query += "&section=" + section; } WikiLink wikiLink = new WikiLink(); // FIXME - hard coding wikiLink.setDestination("Special:Edit"); wikiLink.setQuery(query); return LinkUtil.buildTopicUrl(context, virtualWiki, wikiLink); }
/** * Given an article name, extract an appropriate topic article name. For example, if the article * name is "Comments:Topic" then the return value is "Topic". * * @param virtualWiki The current virtual wiki. * @param name The article name from which a topic article name is to be constructed. * @return The topic article name for the article name. */ public static String extractTopicLink(String virtualWiki, String name) { if (StringUtils.isBlank(name)) { throw new IllegalArgumentException("Topic name must not be empty in extractTopicLink"); } WikiLink wikiLink = LinkUtil.parseWikiLink(virtualWiki, name); Namespace mainNamespace = Namespace.findMainNamespace(wikiLink.getNamespace()); if (mainNamespace == null) { throw new IllegalArgumentException("Topic " + name + " does not have a main namespace"); } return (!StringUtils.isBlank(mainNamespace.getLabel(virtualWiki))) ? mainNamespace.getLabel(virtualWiki) + Namespace.SEPARATOR + wikiLink.getArticle() : wikiLink.getArticle(); }
/** * Build the HTML anchor link to a topic page for a given WikLink object. * * @param context The servlet context for the link that is being created. * @param virtualWiki The virtual wiki for the link that is being created. * @param wikiLink The WikiLink object containing all relevant information about the link being * generated. * @param text The text to display as the link content. * @param style The CSS class to use with the anchor HTML tag. This value can be <code>null</code> * or empty if no custom style is used. * @param target The anchor link target, or <code>null</code> or empty if no target is needed. * @param escapeHtml Set to <code>true</code> if the link caption should be HTML escaped. This * value should be <code>true</code> in any case where the caption is not guaranteed to be * free from potentially malicious HTML code. * @return An HTML anchor link that matches the given input parameters. * @throws DataAccessException Thrown if any error occurs while retrieving topic information. */ public static String buildInternalLinkHtml( String context, String virtualWiki, WikiLink wikiLink, String text, String style, String target, boolean escapeHtml) throws DataAccessException { String url = LinkUtil.buildTopicUrl(context, virtualWiki, wikiLink); String topic = wikiLink.getDestination(); if (StringUtils.isBlank(text)) { text = topic; } if (!StringUtils.isBlank(topic) && StringUtils.isBlank(style)) { if (!StringUtils.isEmpty(virtualWiki) && InterWikiHandler.isInterWiki(virtualWiki)) { style = "interwiki"; } else if (!LinkUtil.isExistingArticle(virtualWiki, topic)) { style = "edit"; } } if (!StringUtils.isBlank(style)) { style = " class=\"" + style + "\""; } else { style = ""; } if (!StringUtils.isBlank(target)) { target = " target=\"" + target + "\""; } else { target = ""; } if (StringUtils.isBlank(topic) && !StringUtils.isBlank(wikiLink.getSection())) { topic = wikiLink.getSection(); } StringBuffer html = new StringBuffer(); html.append("<a href=\"").append(url).append('\"').append(style); html.append(" title=\"") .append(StringEscapeUtils.escapeHtml(topic)) .append('\"') .append(target) .append('>'); if (escapeHtml) { html.append(StringEscapeUtils.escapeHtml(text)); } else { html.append(text); } html.append("</a>"); return html.toString(); }
/** * Build a URL to the topic page for a given topic. * * @param context The servlet context path. If this value is <code>null</code> then the resulting * URL will NOT include context path, which breaks HTML links but is useful for servlet * redirection URLs. * @param virtualWiki The virtual wiki for the link that is being created. * @param wikiLink The WikiLink object containing all relevant information about the link being * generated. * @throws DataAccessException Thrown if any error occurs while retrieving topic information. */ public static String buildTopicUrl(String context, String virtualWiki, WikiLink wikiLink) throws DataAccessException { String topic = wikiLink.getDestination(); String section = wikiLink.getSection(); String query = wikiLink.getQuery(); String url = LinkUtil.buildTopicUrlNoEdit(context, virtualWiki, topic, section, query); if (StringUtils.isBlank(topic) && !StringUtils.isBlank(section)) { // do not check existence for section links return url; } if (!LinkUtil.isExistingArticle(virtualWiki, topic)) { url = LinkUtil.buildEditLinkUrl(context, virtualWiki, topic, query, -1); } return url; }
/** * Build a URL to the topic page for a given topic. * * @param context The servlet context path. If this value is <code>null</code> then the resulting * URL will NOT include context path, which breaks HTML links but is useful for servlet * redirection URLs. * @param virtualWiki The virtual wiki for the link that is being created. * @param topic The topic name for the URL that is being generated. * @param validateTopic Set to <code>true</code> if the topic must exist and must not be a * "Special:" page. If the topic does not exist then a link to an edit page will be returned. * @throws DataAccessException Thrown if any error occurs while retrieving topic information. */ public static String buildTopicUrl( String context, String virtualWiki, String topic, boolean validateTopic) throws DataAccessException { if (StringUtils.isBlank(topic)) { return null; } WikiLink wikiLink = LinkUtil.parseWikiLink(topic); if (validateTopic) { return LinkUtil.buildTopicUrl(context, virtualWiki, wikiLink); } else { return LinkUtil.buildTopicUrlNoEdit( context, virtualWiki, wikiLink.getDestination(), wikiLink.getSection(), wikiLink.getQuery()); } }
/** * Given an article name, return the appropriate comments topic article name. For example, if the * article name is "Topic" then the return value is "Comments:Topic". * * @param virtualWiki The current virtual wiki. * @param name The article name from which a comments article name is to be constructed. * @return The comments article name for the article name. */ public static String extractCommentsLink(String virtualWiki, String name) { if (StringUtils.isBlank(name)) { throw new IllegalArgumentException("Topic name must not be empty in extractCommentsLink"); } WikiLink wikiLink = LinkUtil.parseWikiLink(virtualWiki, name); Namespace commentsNamespace = null; try { commentsNamespace = Namespace.findCommentsNamespace(wikiLink.getNamespace()); } catch (DataAccessException e) { throw new IllegalStateException("Database error while retrieving comments namespace", e); } if (commentsNamespace == null) { throw new IllegalArgumentException("Topic " + name + " does not have a comments namespace"); } return (!StringUtils.isBlank(commentsNamespace.getLabel(virtualWiki))) ? commentsNamespace.getLabel(virtualWiki) + Namespace.SEPARATOR + wikiLink.getArticle() : wikiLink.getArticle(); }
@Test public void testConstructor() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); assertNull("wikiLink.getQuery()", wikiLink.getQuery()); assertNull("wikiLink.getSection()", wikiLink.getSection()); assertNull("wikiLink.getText()", wikiLink.getText()); assertNull("wikiLink.getArticle()", wikiLink.getArticle()); assertEquals( "wikiLink.getNamespace()", Namespace.namespace(Namespace.MAIN_ID), wikiLink.getNamespace()); assertNull("wikiLink.getDestination()", wikiLink.getDestination()); assertFalse("wikiLink.getColon()", wikiLink.getColon()); }
/** * Utility method for determining if a topic name is valid for use on the Wiki, meaning that it is * not empty and does not contain any invalid characters. * * @param virtualWiki The current virtual wiki. * @param name The topic name to validate. * @throws WikiException Thrown if the user name is invalid. */ public static void validateTopicName(String virtualWiki, String name) throws WikiException { if (StringUtils.isBlank(virtualWiki)) { throw new WikiException(new WikiMessage("common.exception.novirtualwiki")); } if (StringUtils.isBlank(name)) { throw new WikiException(new WikiMessage("common.exception.notopic")); } if (PseudoTopicHandler.isPseudoTopic(name)) { throw new WikiException(new WikiMessage("common.exception.pseudotopic", name)); } WikiLink wikiLink = LinkUtil.parseWikiLink(virtualWiki, name); String article = StringUtils.trimToNull(wikiLink.getArticle()); if (StringUtils.startsWith(article, "/")) { throw new WikiException(new WikiMessage("common.exception.name", name)); } if (wikiLink.getNamespace().getId().equals(Namespace.SPECIAL_ID)) { throw new WikiException(new WikiMessage("common.exception.name", name)); } Matcher m = WikiUtil.INVALID_TOPIC_NAME_PATTERN.matcher(name); if (m.find()) { throw new WikiException(new WikiMessage("common.exception.name", name)); } }
/** * Generate the HTML for an interwiki anchor link. * * @param wikiLink The WikiLink object containing all relevant information about the link being * generated. * @return The HTML anchor tag for the interwiki link. */ public static String interWiki(WikiLink wikiLink) { // remove namespace from link destination String destination = wikiLink.getDestination(); String namespace = wikiLink.getNamespace(); destination = destination.substring( wikiLink.getNamespace().length() + NamespaceHandler.NAMESPACE_SEPARATOR.length()); String url = InterWikiHandler.formatInterWiki(namespace, destination); String text = (!StringUtils.isBlank(wikiLink.getText())) ? wikiLink.getText() : wikiLink.getDestination(); return "<a class=\"interwiki\" rel=\"nofollow\" title=\"" + text + "\" href=\"" + url + "\">" + text + "</a>"; }
/** * Parse a wiki topic link and return a <code>WikiLink</code> object representing the link. Wiki * topic links are of the form "Topic?Query#Section". * * @param raw The raw topic link text. * @return A WikiLink object that represents the link. */ public static WikiLink parseWikiLink(String raw) { // note that this functionality was previously handled with a regular // expression, but the expression caused CPU usage to spike to 100% // with topics such as "Urnordisch oder Nordwestgermanisch?" String processed = raw.trim(); WikiLink wikiLink = new WikiLink(); if (StringUtils.isBlank(processed)) { return new WikiLink(); } // first look for a section param - "#..." int sectionPos = processed.indexOf('#'); if (sectionPos != -1 && sectionPos < processed.length()) { String sectionString = processed.substring(sectionPos + 1); wikiLink.setSection(sectionString); if (sectionPos == 0) { // link is of the form #section, no more to process return wikiLink; } processed = processed.substring(0, sectionPos); } // now see if the link ends with a query param - "?..." int queryPos = processed.indexOf('?', 1); if (queryPos != -1 && queryPos < processed.length()) { String queryString = processed.substring(queryPos + 1); wikiLink.setQuery(queryString); processed = processed.substring(0, queryPos); } // since we're having so much fun, let's find a namespace (default empty). String namespaceString = ""; int namespacePos = processed.indexOf(':', 1); if (namespacePos != -1 && namespacePos < processed.length()) { namespaceString = processed.substring(0, namespacePos); } wikiLink.setNamespace(namespaceString); String topic = processed; if (namespacePos > 0 && (namespacePos + 1) < processed.length()) { // get namespace, unless topic ends with a colon topic = processed.substring(namespacePos + 1); } wikiLink.setArticle(Utilities.decodeTopicName(topic, true)); // destination is namespace + topic wikiLink.setDestination(Utilities.decodeTopicName(processed, true)); return wikiLink; }
@Test public void testParseWikiLink() throws Throwable { WikiLink result = LinkUtil.parseWikiLink("en", "testLinkUtilRaw"); assertEquals("result.getArticle()", "testLinkUtilRaw", result.getArticle()); }
@Test public void testParseWikiLink1() throws Throwable { WikiLink result = LinkUtil.parseWikiLink(null, ""); assertNull("result.getArticle()", result.getArticle()); }
@Test public void testSetSection() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); wikiLink.setSection("testWikiLinkSection"); assertEquals("wikiLink.getSection()", "testWikiLinkSection", wikiLink.getSection()); }
@Test public void testSetDestination() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", "testWikiLinkDestination"); assertEquals("wikiLink.getDestination()", "testWikiLinkDestination", wikiLink.getDestination()); }
@Test public void testSetColon() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); wikiLink.setColon(true); assertTrue("wikiLink.getColon()", wikiLink.getColon()); }
@Test public void testSetArticle() throws Throwable { WikiLink wikiLink = new WikiLink("/wiki", "en", null); wikiLink.setArticle("testWikiLinkArticle"); assertEquals("wikiLink.getArticle()", "testWikiLinkArticle", wikiLink.getArticle()); }