diff --git a/pom.xml b/pom.xml index 8a723a8..2a27901 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ http://www.atlassian.com/ confluence-markdown-macro - This plugin provides a Markdown render macro for Confluence. + This plugin provides macros to render markdown for Confluence. atlassian-plugin @@ -90,6 +90,8 @@ ${confluence.version} ${confluence.data.version} + true + false @@ -104,7 +106,7 @@ 6.9.0 6.9.0 - 6.2.11 + 6.3.0 1.1 2.1.7 diff --git a/src/main/java/com/atlassian/plugins/confluence/markdown/MarkdownFromURLMacro.java b/src/main/java/com/atlassian/plugins/confluence/markdown/MarkdownFromURLMacro.java new file mode 100644 index 0000000..0b6a390 --- /dev/null +++ b/src/main/java/com/atlassian/plugins/confluence/markdown/MarkdownFromURLMacro.java @@ -0,0 +1,181 @@ +package com.atlassian.plugins.confluence.markdown; + +import com.atlassian.confluence.content.render.xhtml.ConversionContext; +import com.atlassian.confluence.content.render.xhtml.DefaultConversionContext; +import com.atlassian.confluence.content.render.xhtml.XhtmlException; +import com.atlassian.confluence.macro.Macro; +import com.atlassian.confluence.macro.MacroExecutionException; +import com.atlassian.confluence.xhtml.api.MacroDefinition; +import com.atlassian.confluence.xhtml.api.MacroDefinitionHandler; +import com.atlassian.confluence.xhtml.api.XhtmlContent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import com.atlassian.renderer.RenderContext; +import com.atlassian.renderer.v2.RenderMode; +import com.atlassian.renderer.v2.macro.BaseMacro; +import com.atlassian.renderer.v2.macro.MacroException; + +//import com.atlassian.plugin.spring.scanner.annotation.component.Scanned; +import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; +import com.atlassian.webresource.api.assembler.PageBuilderService; +import org.springframework.beans.factory.annotation.Autowired; + + +import com.vladsch.flexmark.ast.Node; +import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughSubscriptExtension; +import com.vladsch.flexmark.ext.tables.TablesExtension; +import com.vladsch.flexmark.ext.ins.InsExtension; +import com.vladsch.flexmark.ext.definition.DefinitionExtension; +import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension; +import com.vladsch.flexmark.ext.footnotes.FootnoteExtension; +import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension; +import com.vladsch.flexmark.ext.autolink.AutolinkExtension; +import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension; +import com.vladsch.flexmark.superscript.SuperscriptExtension; +import com.vladsch.flexmark.ext.youtube.embedded.YouTubeLinkExtension; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.options.MutableDataSet; + + +import java.net.*; +import java.io.*; + +//@Scanned +public class MarkdownFromURLMacro extends BaseMacro implements Macro +{ + + private final XhtmlContent xhtmlUtils; + + private PageBuilderService pageBuilderService; + + @Autowired + public MarkdownFromURLMacro(@ComponentImport PageBuilderService pageBuilderService, XhtmlContent xhtmlUtils) { + this.pageBuilderService = pageBuilderService; + this.xhtmlUtils = xhtmlUtils; + } + +// public MarkdownFromURLMacro(XhtmlContent xhtmlUtils) +// { +// this.xhtmlUtils = xhtmlUtils; +// } + + @Override + public BodyType getBodyType() + { + return BodyType.PLAIN_TEXT; + } + + @Override + public OutputType getOutputType() + { + return OutputType.BLOCK; + } + + @Override + public String execute(Map parameters, String bodyContent, ConversionContext conversionContext) throws MacroExecutionException + { + + if (bodyContent != null) { + pageBuilderService.assembler().resources().requireWebResource("com.atlassian.plugins.confluence.markdown.confluence-markdown-macro:highlightjs"); + + MutableDataSet options = new MutableDataSet(); + + options.set(Parser.EXTENSIONS, Arrays.asList( + TablesExtension.create(), + StrikethroughSubscriptExtension.create(), + InsExtension.create(), + TaskListExtension.create(), + FootnoteExtension.create(), + WikiLinkExtension.create(), + DefinitionExtension.create(), + AnchorLinkExtension.create(), + AutolinkExtension.create(), + SuperscriptExtension.create(), + YouTubeLinkExtension.create() + + )); + + + String highlightjs = ""; + + class privateRepositoryException extends Exception { + public privateRepositoryException(String message) { + super(message); + } + } + + Parser parser = Parser.builder(options).build(); + HtmlRenderer renderer = HtmlRenderer.builder(options).build(); + + String exceptionsToReturn = ""; + String html = ""; + String toParse = ""; + try { + URL importFrom = new URL(bodyContent); + BufferedReader in = new BufferedReader( + new InputStreamReader(importFrom.openStream()) + ); + String inputLine; + while ((inputLine = in.readLine()) != null) { + toParse = toParse + "\n" + inputLine; + } + in.close(); + toParse = toParse.trim(); + if (toParse.startsWith("\n\n OpenID transaction in progress")) { + throw new privateRepositoryException("Cannot import from private repository."); + }else { + Node document = parser.parse(toParse); + html = renderer.render(document) + highlightjs; + } + } + catch (MalformedURLException u) { + exceptionsToReturn = exceptionsToReturn + "Error with Markdown From URL macro: Invalid URL.
Please enter a valid URL. If you are not trying to import markdown from a URL, use the Markdown macro instead of the Markdown from URL macro.
For support visit our Q&A in the Atlassian Community. You can ask a new question by clicking the \"Create\" button on the top right of the Q&A.
"; + } + catch (privateRepositoryException p) { + exceptionsToReturn = exceptionsToReturn + "Error with Markdown From URL macro: Importing from private Bitbucket repositories is not supported.
Please make your repository public before importing. Alternatively, you can copy and paste your markdown into the Markdown macro.
If you are allowed access, you can find the markdown file here.
For support visit our Q&A in the Atlassian Community. You can ask a new question by clicking the \"Create\" button on the top right of the Q&A.
"; + } + catch (FileNotFoundException f) { + exceptionsToReturn = exceptionsToReturn + "Error with Markdown From URL macro: URL does not exist.
" + bodyContent + "
Please double check your URL. Perhaps you made a typo or perhaps the page has been moved.
This can also be caused by changing the Github repository containing the file from public to private. If this is the case go back to the raw file and re-copy the link.
For support visit our Q&A in the Atlassian Community. You can ask a new question by clicking the \"Create\" button on the top right of the Q&A.
"; + } + catch (IOException e) { + exceptionsToReturn = exceptionsToReturn + "Error with Markdown From URL macro: Unexpected error.
" + e.toString() + "
For support visit our Q&A in the Atlassian Community. You can ask a new question by clicking the \"Create\" button on the top right of the Q&A.
"; + } + finally { + if (exceptionsToReturn != "") { + html = "

" + exceptionsToReturn + "

"; + } + return html; + } + }else { + return ""; + } + } + + @Override + public boolean hasBody() { + return true; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public RenderMode getBodyRenderMode() { + return RenderMode.NO_RENDER; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String execute(Map map, String s, RenderContext renderContext) throws MacroException { + try { + return execute(map, s, new DefaultConversionContext(renderContext)); + } catch (MacroExecutionException e) { + throw new MacroException(e.getMessage(),e); + } + } +} \ No newline at end of file diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index 22d2b2e..49b1e8d 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -8,15 +8,14 @@ true compatible - - - - + - - + + + + + + + + + + diff --git a/src/main/resources/markdown-from-url-properties/markdown-from-url.properties b/src/main/resources/markdown-from-url-properties/markdown-from-url.properties new file mode 100644 index 0000000..503e17c --- /dev/null +++ b/src/main/resources/markdown-from-url-properties/markdown-from-url.properties @@ -0,0 +1,2 @@ +com.atlassian.plugins.confluence.markdown.confluence-markdown-macro.markdown-from-url.label=Markdown From URL +com.atlassian.plugins.confluence.markdown.confluence-markdown-macro.markdown-from-url.desc=This macro dynamically imports Markdown from a URL and renders it into HTML. \ No newline at end of file