mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-01-10 09:32:19 +01:00
Merge remote-tracking branch 'origin/plugin-system' into plugin-system
This commit is contained in:
@@ -5,6 +5,7 @@ import SystemSettingsService._
|
||||
import util.AdminAuthenticator
|
||||
import jp.sf.amateras.scalatra.forms._
|
||||
import ssh.SshServer
|
||||
import org.scalatra.Ok
|
||||
|
||||
class SystemSettingsController extends SystemSettingsControllerBase
|
||||
with AccountService with AdminAuthenticator
|
||||
@@ -71,4 +72,13 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
||||
redirect("/admin/system")
|
||||
})
|
||||
|
||||
get("/admin/script")(adminOnly {
|
||||
admin.html.script()
|
||||
})
|
||||
|
||||
post("/admin/script")(adminOnly {
|
||||
val script = request.getParameter("script")
|
||||
val result = plugin.PluginSystem.evaluateJavaScript(script)
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,37 +2,48 @@ package plugin
|
||||
|
||||
import app.Context
|
||||
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
|
||||
import javax.script.ScriptEngineManager
|
||||
|
||||
/**
|
||||
* Provides extension points to plug-ins.
|
||||
*/
|
||||
object PluginSystem {
|
||||
|
||||
private val repositoryMenuList = scala.collection.mutable.ListBuffer[Menu]()
|
||||
private val globalMenuList = scala.collection.mutable.ListBuffer[Menu]()
|
||||
private val repositoryMenuList = scala.collection.mutable.ListBuffer[RepositoryMenu]()
|
||||
private val globalMenuList = scala.collection.mutable.ListBuffer[GlobalMenu]()
|
||||
private val actionList = scala.collection.mutable.ListBuffer[Action]()
|
||||
|
||||
case class Menu(label: String, url: String, icon: String, condition: Context => Boolean)
|
||||
case class GlobalMenu(label: String, url: String, icon: String, condition: Context => Boolean)
|
||||
case class RepositoryMenu(label: String, name: String, url: String, icon: String, condition: Context => Boolean)
|
||||
case class Action(path: String, function: (HttpServletRequest, HttpServletResponse) => Any)
|
||||
|
||||
def addRepositoryMenu(label: String, url: String, icon: String = "")(condition: Context => Boolean): Unit = {
|
||||
repositoryMenuList += Menu(label, url, icon, condition)
|
||||
def addRepositoryMenu(label: String, name: String, url: String, icon: String = "")(condition: Context => Boolean): Unit = {
|
||||
repositoryMenuList += RepositoryMenu(label, name, url, icon, condition)
|
||||
}
|
||||
|
||||
def addGlobalMenu(label: String, url: String, icon: String = "")(condition: Context => Boolean): Unit = {
|
||||
globalMenuList += Menu(label, url, icon, condition)
|
||||
globalMenuList += GlobalMenu(label, url, icon, condition)
|
||||
}
|
||||
|
||||
def addAction(path: String)(function: (HttpServletRequest, HttpServletResponse) => Any): Unit = {
|
||||
actionList += Action(path, function)
|
||||
}
|
||||
|
||||
lazy val repositoryMenus: List[Menu] = repositoryMenuList.toList
|
||||
lazy val globalMenus: List[Menu] = globalMenuList.toList
|
||||
def evaluateJavaScript(script: String): Any = {
|
||||
val engine = new ScriptEngineManager().getEngineByName("JavaScript")
|
||||
engine.eval(script)
|
||||
}
|
||||
|
||||
lazy val repositoryMenus: List[RepositoryMenu] = repositoryMenuList.toList
|
||||
lazy val globalMenus: List[GlobalMenu] = globalMenuList.toList
|
||||
lazy val actions: List[Action] = actionList.toList
|
||||
|
||||
// TODO This is a test
|
||||
addGlobalMenu("Google", "http://www.google.co.jp/"){ context => context.loginAccount.isDefined }
|
||||
addGlobalMenu("Google", "http://www.google.co.jp/", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEvwAABL8BkeKJvAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIgSURBVEiJtdZNiI1hFAfw36ORhSFFPgYLszOKJAsWRLGzks1gYyFZKFs7C7K2Y2XDRiwmq9kIJWQjJR9Tk48xRtTIRwjH4p473nm99yLNqdNTz/mf//+555x7ektEmEmbNaPs6OkUKKX0YBmWp6/IE8bwIs8xjEfEt0aiiJBl6sEuXMRLfEf8pX/PnIvJ0TPFWxE4+w+Ef/Kzbd5qDx5l8H8tkku7LG17gH7sxWatevdhEUoXsjda5RnDTZzH6jagtMe0lHIa23AJw3iOiSRZlmJ9mfcyfTzFl2AldmI3rkbEkbrAYKrX7S1eVRyWVnxhQ87eiLjQ+o2/mtyve+PuYy3W4+EfsP2/TVGKTHRI+Iz9Fdx8XOmAnZjGWRMYqoF/4ESW4hpOYk1iZ2WsLjDUTeBYBfgeuyux2XiNT5hXud+DD5W8Y90EtifoSfultfjx7MVtrKzcr8No5m7vJtCLx1hQJ8/4IZzClpyoy5ibsYUYQW81Z9o2jYgPeKr15+poEXE9+1XF9WIkOaasaV2P4k4pZUdDbEm+VEQcjIgtEfGxlLIVd/Gs6TX1MhzQquU3HK1t23f4IsuS94fxNXMO/MbXIDBg+tidw5yMbcCmylSdqWEH/kagYLKWeAt9Fcxi3KhhJuXq6SqQBMO15NDalvswmLWux4cbuToIbMS9BpJOfg8bm7imtmmTlVJWaa3hpnU9nufziBjtyDHTny0/AaA7Qnb4AM4aAAAAAElFTkSuQmCC")
|
||||
{ context => context.loginAccount.isDefined }
|
||||
|
||||
addRepositoryMenu("Board", "board", "/board", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEvwAABL8BkeKJvAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIgSURBVEiJtdZNiI1hFAfw36ORhSFFPgYLszOKJAsWRLGzks1gYyFZKFs7C7K2Y2XDRiwmq9kIJWQjJR9Tk48xRtTIRwjH4p473nm99yLNqdNTz/mf//+555x7ektEmEmbNaPs6OkUKKX0YBmWp6/IE8bwIs8xjEfEt0aiiJBl6sEuXMRLfEf8pX/PnIvJ0TPFWxE4+w+Ef/Kzbd5qDx5l8H8tkku7LG17gH7sxWatevdhEUoXsjda5RnDTZzH6jagtMe0lHIa23AJw3iOiSRZlmJ9mfcyfTzFl2AldmI3rkbEkbrAYKrX7S1eVRyWVnxhQ87eiLjQ+o2/mtyve+PuYy3W4+EfsP2/TVGKTHRI+Iz9Fdx8XOmAnZjGWRMYqoF/4ESW4hpOYk1iZ2WsLjDUTeBYBfgeuyux2XiNT5hXud+DD5W8Y90EtifoSfultfjx7MVtrKzcr8No5m7vJtCLx1hQJ8/4IZzClpyoy5ibsYUYQW81Z9o2jYgPeKr15+poEXE9+1XF9WIkOaasaV2P4k4pZUdDbEm+VEQcjIgtEfGxlLIVd/Gs6TX1MhzQquU3HK1t23f4IsuS94fxNXMO/MbXIDBg+tidw5yMbcCmylSdqWEH/kagYLKWeAt9Fcxi3KhhJuXq6SqQBMO15NDalvswmLWux4cbuToIbMS9BpJOfg8bm7imtmmTlVJWaa3hpnU9nufziBjtyDHTny0/AaA7Qnb4AM4aAAAAAElFTkSuQmCC")
|
||||
{ context => true}
|
||||
|
||||
addAction("/hello"){ (request, response) =>
|
||||
"Hello World!"
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
<li@if(active=="system"){ class="active"}>
|
||||
<a href="@path/admin/system">System Settings</a>
|
||||
</li>
|
||||
<li@if(active=="script"){ class="active"}>
|
||||
<a href="@path/admin/script">JavaScript Console</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="@path/console/login.jsp">H2 Console</a>
|
||||
</li>
|
||||
|
||||
33
src/main/twirl/admin/script.scala.html
Normal file
33
src/main/twirl/admin/script.scala.html
Normal file
@@ -0,0 +1,33 @@
|
||||
@()(implicit context: app.Context)
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
@html.main("JavaScript Console"){
|
||||
@menu("script"){
|
||||
<form action="@path/admin/script" method="POST">
|
||||
<div class="box">
|
||||
<div class="box-header">JavaScript Console</div>
|
||||
<div class="box-content">
|
||||
<div id="editor" style="width: 100%; height: 600px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset>
|
||||
<input type="submit" id="evaluate" class="btn btn-success" value="Evaluate"/>
|
||||
</fieldset>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
<script src="@assets/ace/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
var editor = ace.edit("editor");
|
||||
editor.setTheme("ace/theme/monokai");
|
||||
|
||||
$('#evaluate').click(function(){
|
||||
$.post('@path/admin/script', {
|
||||
script: editor.getValue()
|
||||
}, function(data){
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -62,7 +62,7 @@
|
||||
<a href="@url(loginAccount.get.userName)/_edit" class="menu" data-toggle="tooltip" data-placement="bottom" title="Account settings"><i class="icon-user"></i></a>
|
||||
@plugin.PluginSystem.globalMenus.map { menu =>
|
||||
@if(menu.condition(context)){
|
||||
<a href="@menu.url" class="menu" data-toggle="tooltip" data-placement="bottom" title="@menu.label">@menu.label</a>
|
||||
<a href="@menu.url" class="menu" data-toggle="tooltip" data-placement="bottom" title="@menu.label">@if(menu.icon.nonEmpty){<img src="@menu.icon" class="plugin-global-menu"/>} else {@menu.label}</a>
|
||||
}
|
||||
}
|
||||
@if(loginAccount.get.isAdmin){
|
||||
@@ -72,7 +72,7 @@
|
||||
} else {
|
||||
@plugin.PluginSystem.globalMenus.map { menu =>
|
||||
@if(menu.condition(context)){
|
||||
<a href="@menu.url" class="menu" data-toggle="tooltip" data-placement="bottom" title="@menu.label">@menu.label</a>
|
||||
<a href="@menu.url" class="menu" data-toggle="tooltip" data-placement="bottom" title="@menu.label">@if(menu.icon.nonEmpty){<img src="@menu.icon" class="plugin-global-menu"/>} else {@menu.label}</a>
|
||||
}
|
||||
}
|
||||
<a href="@path/signin?redirect=@urlEncode(currentPath)" class="btn btn-last" id="signin">Sign in</a>
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
</li>
|
||||
}
|
||||
|
||||
@sidemenuPlugin(path: String, name: String, label: String, icon: String) = {
|
||||
<li @if(active == name){class="active"}>
|
||||
<div class="@if(active == name){margin} else {gradient} pull-left"></div>
|
||||
<a href="@url(repository)@path"><img src="@icon"/>@if(expand){ @label}</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
@if(repository.commitCount > 0){
|
||||
<div class="pull-right">
|
||||
@@ -54,6 +61,11 @@
|
||||
@sidemenu("/issues", "issues", "Issues", repository.issueCount)
|
||||
@sidemenu("/pulls" , "pulls" , "Pull Requests", repository.pullCount)
|
||||
@sidemenu("/wiki" , "wiki" , "Wiki")
|
||||
@plugin.PluginSystem.repositoryMenus.map { menu =>
|
||||
@if(menu.condition(context)){
|
||||
@sidemenuPlugin(menu.url, menu.label, menu.label, menu.icon)
|
||||
}
|
||||
}
|
||||
@if(loginAccount.isDefined && (loginAccount.get.isAdmin || repository.managers.contains(loginAccount.get.userName))){
|
||||
@sidemenu("/settings", "settings", "Settings")
|
||||
}
|
||||
|
||||
@@ -98,6 +98,13 @@ div.input-prepend span.count {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
img.plugin-global-menu {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
/* General Styles */
|
||||
/* ======================================================================== */
|
||||
|
||||
Reference in New Issue
Block a user