diff --git a/build.sbt b/build.sbt index e0c7236..35aebe6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ val Organization = "gitbucket" val Name = "gitbucket" -val GitBucketVersion = "4.2.1" +val GitBucketVersion = "4.3.0-SNAPSHOT" val ScalatraVersion = "2.4.1" val JettyVersion = "9.3.9.v20160517" diff --git a/src/main/scala/gitbucket/core/plugin/Plugin.scala b/src/main/scala/gitbucket/core/plugin/Plugin.scala index caaf726..6f04ec9 100644 --- a/src/main/scala/gitbucket/core/plugin/Plugin.scala +++ b/src/main/scala/gitbucket/core/plugin/Plugin.scala @@ -150,6 +150,16 @@ def dashboardTabs(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(Context) => Option[Link]] = Nil /** + * Override to add assets mappings. + */ + val assetsMappings: Seq[(String, String)] = Nil + + /** + * Override to add assets mappings. + */ + def assetsMappings(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, String)] = Nil + + /** * This method is invoked in initialization of plugin system. * Register plugin functionality to PluginRegistry. */ @@ -193,6 +203,9 @@ (dashboardTabs ++ dashboardTabs(registry, context, settings)).foreach { dashboardTab => registry.addDashboardTab(dashboardTab) } + (assetsMappings ++ assetsMappings(registry, context, settings)).foreach { assetMapping => + registry.addAssetsMapping((assetMapping._1, assetMapping._2, getClass.getClassLoader)) + } } /** diff --git a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala index 849fbc3..81f228f 100644 --- a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala +++ b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala @@ -41,6 +41,7 @@ private val systemSettingMenus = new ListBuffer[(Context) => Option[Link]] private val accountSettingMenus = new ListBuffer[(Context) => Option[Link]] private val dashboardTabs = new ListBuffer[(Context) => Option[Link]] + private val assetsMappings = new ListBuffer[(String, String, ClassLoader)] def addPlugin(pluginInfo: PluginInfo): Unit = { plugins += pluginInfo @@ -158,6 +159,12 @@ def getDashboardTabs: Seq[(Context) => Option[Link]] = dashboardTabs.toSeq + def addAssetsMapping(assetsMapping: (String, String, ClassLoader)): Unit = { + assetsMappings += assetsMapping + } + + def getAssetsMappings: Seq[(String, String, ClassLoader)] = assetsMappings.toSeq + } /** diff --git a/src/main/scala/gitbucket/core/servlet/PluginAssetsServlet.scala b/src/main/scala/gitbucket/core/servlet/PluginAssetsServlet.scala new file mode 100644 index 0000000..0b59881 --- /dev/null +++ b/src/main/scala/gitbucket/core/servlet/PluginAssetsServlet.scala @@ -0,0 +1,39 @@ +package gitbucket.core.servlet + +import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} + +import gitbucket.core.plugin.PluginRegistry +import gitbucket.core.util.FileUtil +import org.apache.commons.io.IOUtils + +/** + * Supply assets which are provided by plugins. + */ +class PluginAssetsServlet extends HttpServlet { + + override def doGet(req: HttpServletRequest, resp: HttpServletResponse): Unit = { + val assetsMappings = PluginRegistry().getAssetsMappings + val path = req.getRequestURI.substring(req.getContextPath.length) + + assetsMappings + .find { case (prefix, _, _) => path.startsWith("/plugin-assets" + prefix) } + .flatMap { case (prefix, resourcePath, classLoader) => + val resourceName = path.substring(("/plugin-assets" + prefix).length) + Option(classLoader.getResourceAsStream(resourcePath + resourceName)) + } + .map { in => + try { + val bytes = IOUtils.toByteArray(in) + resp.setContentLength(bytes.length) + resp.setContentType(FileUtil.getContentType(path, bytes)) + resp.getOutputStream.write(bytes) + } finally { + in.close() + } + } + .getOrElse { + resp.setStatus(404) + } + } + +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 37bca8f..e8ee9e9 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -45,7 +45,20 @@ GitRepositoryServlet /git/* - + + + + + + PluginAssetsServlet + gitbucket.core.servlet.PluginAssetsServlet + + + + PluginAssetsServlet + /plugin-assets/* + +