From a64741011ca391e710dd43a6fbdb1ff93d28a87f Mon Sep 17 00:00:00 2001 From: Naoki Takezoe Date: Sat, 30 Dec 2017 01:01:22 +0900 Subject: [PATCH] Implement displaying result as a scrollable table --- .../core/controller/ControllerBase.scala | 22 ++----- .../controller/SystemSettingsController.scala | 38 +++++++++++ .../servlet/CompositeScalatraFilter.scala | 2 +- .../core/servlet/TransactionFilter.scala | 2 +- .../gitbucket/core/admin/dbviewer.scala.html | 62 +++++++++++++++--- src/main/webapp/WEB-INF/web.xml | 26 +------- .../webapp/assets/common/css/gitbucket.css | 6 ++ .../webapp/assets/common/images/column.gif | Bin 0 -> 317 bytes .../webapp/assets/common/images/table.gif | Bin 0 -> 343 bytes 9 files changed, 103 insertions(+), 55 deletions(-) create mode 100644 src/main/webapp/assets/common/images/column.gif create mode 100644 src/main/webapp/assets/common/images/table.gif diff --git a/src/main/scala/gitbucket/core/controller/ControllerBase.scala b/src/main/scala/gitbucket/core/controller/ControllerBase.scala index 993f160dc..c8f9c1d81 100644 --- a/src/main/scala/gitbucket/core/controller/ControllerBase.scala +++ b/src/main/scala/gitbucket/core/controller/ControllerBase.scala @@ -43,25 +43,11 @@ abstract class ControllerBase extends ScalatraFilter } override def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain): Unit = try { - val httpRequest = request.asInstanceOf[HttpServletRequest] - val httpResponse = response.asInstanceOf[HttpServletResponse] - val context = request.getServletContext.getContextPath - val path = httpRequest.getRequestURI.substring(context.length) + val httpRequest = request.asInstanceOf[HttpServletRequest] + val context = request.getServletContext.getContextPath + val path = httpRequest.getRequestURI.substring(context.length) - if(path.startsWith("/console/")){ - val account = httpRequest.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account] - val baseUrl = this.baseUrl(httpRequest) - if(account == null){ - // Redirect to login form - httpResponse.sendRedirect(baseUrl + "/signin?redirect=" + StringUtil.urlEncode(path)) - } else if(account.isAdmin){ - // H2 Console (administrators only) - chain.doFilter(request, response) - } else { - // Redirect to dashboard - httpResponse.sendRedirect(baseUrl + "/") - } - } else if(path.startsWith("/git/") || path.startsWith("/git-lfs/")){ + if(path.startsWith("/git/") || path.startsWith("/git-lfs/")){ // Git repository chain.doFilter(request, response) } else { diff --git a/src/main/scala/gitbucket/core/controller/SystemSettingsController.scala b/src/main/scala/gitbucket/core/controller/SystemSettingsController.scala index 8518b1079..e0226ef56 100644 --- a/src/main/scala/gitbucket/core/controller/SystemSettingsController.scala +++ b/src/main/scala/gitbucket/core/controller/SystemSettingsController.scala @@ -17,6 +17,8 @@ import org.apache.commons.io.IOUtils import org.scalatra.i18n.Messages import com.github.zafarkhaja.semver.{Version => Semver} import gitbucket.core.GitBucketCoreModule +import org.scalatra._ +import org.json4s.jackson.Serialization import scala.collection.JavaConverters._ import scala.collection.mutable.ListBuffer @@ -176,6 +178,42 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase { html.dbviewer(tables) }) + post("/admin/dbviewer/_query")(adminOnly { + contentType = formats("json") + params.get("query").collectFirst { case query if query.trim.nonEmpty => + val trimmedQuery = query.trim + if(trimmedQuery.nonEmpty){ + try { + val conn = request2Session(request).conn + using(conn.prepareStatement(query)){ stmt => + if(trimmedQuery.toUpperCase.startsWith("SELECT")){ + using(stmt.executeQuery()){ rs => + val meta = rs.getMetaData + val columns = for(i <- 1 to meta.getColumnCount) yield { + meta.getColumnName(i) + } + val result = ListBuffer[Map[String, String]]() + while(rs.next()){ + val row = columns.map { columnName => + columnName -> Option(rs.getObject(columnName)).map(_.toString).getOrElse("") + }.toMap + result += row + } + Ok(Serialization.write(Map("type" -> "query", "columns" -> columns, "rows" -> result))) + } + } else { + val rows = stmt.executeUpdate() + Ok(Serialization.write(Map("type" -> "update", "rows" -> rows))) + } + } + } catch { + case e: Exception => + Ok(Serialization.write(Map("type" -> "error", "message" -> e.toString))) + } + } + } getOrElse Ok(Serialization.write(Map("type" -> "error", "message" -> "query is empty"))) + }) + get("/admin/system")(adminOnly { html.system(flash.get("info")) }) diff --git a/src/main/scala/gitbucket/core/servlet/CompositeScalatraFilter.scala b/src/main/scala/gitbucket/core/servlet/CompositeScalatraFilter.scala index 6b6ee470f..beff25d50 100644 --- a/src/main/scala/gitbucket/core/servlet/CompositeScalatraFilter.scala +++ b/src/main/scala/gitbucket/core/servlet/CompositeScalatraFilter.scala @@ -37,7 +37,7 @@ class CompositeScalatraFilter extends Filter { } if(!checkPath.startsWith("/upload/") && !checkPath.startsWith("/git/") && !checkPath.startsWith("/git-lfs/") && - !checkPath.startsWith("/plugin-assets/") && !checkPath.startsWith("/console/")){ + !checkPath.startsWith("/plugin-assets/")){ filters .filter { case (_, path) => val start = path.replaceFirst("/\\*$", "/") diff --git a/src/main/scala/gitbucket/core/servlet/TransactionFilter.scala b/src/main/scala/gitbucket/core/servlet/TransactionFilter.scala index 0911d614b..d6677d195 100644 --- a/src/main/scala/gitbucket/core/servlet/TransactionFilter.scala +++ b/src/main/scala/gitbucket/core/servlet/TransactionFilter.scala @@ -23,7 +23,7 @@ class TransactionFilter extends Filter { def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = { val servletPath = req.asInstanceOf[HttpServletRequest].getServletPath() - if(servletPath.startsWith("/assets/") || servletPath == "/console" || servletPath == "/git" || servletPath == "/git-lfs"){ + if(servletPath.startsWith("/assets/") || servletPath == "/git" || servletPath == "/git-lfs"){ // assets and git-lfs don't need transaction chain.doFilter(req, res) } else { diff --git a/src/main/twirl/gitbucket/core/admin/dbviewer.scala.html b/src/main/twirl/gitbucket/core/admin/dbviewer.scala.html index adf8d02c2..e0eab7efb 100644 --- a/src/main/twirl/gitbucket/core/admin/dbviewer.scala.html +++ b/src/main/twirl/gitbucket/core/admin/dbviewer.scala.html @@ -1,17 +1,18 @@ @(tables: Seq[gitbucket.core.controller.Table])(implicit context: gitbucket.core.controller.Context) +@import gitbucket.core.view.helpers @gitbucket.core.html.main("Database viewer") { @gitbucket.core.admin.html.menu("dbviewer") { -
+
    @tables.map { table => -
  • @table.name -
      - @table.columns.map { column => -
    • @column.name
    • - } -
    +
  • @table.name +
      + @table.columns.map { column => +
    • @column.name
    • + } +
  • }
@@ -27,19 +28,60 @@
} } - - - + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 36b904eb2..a85da9075 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -40,7 +40,7 @@ GitRepositoryServlet gitbucket.core.servlet.GitRepositoryServlet - + GitRepositoryServlet /git/* @@ -70,30 +70,6 @@ /plugin-assets/* - - - - - H2Console - org.h2.server.web.WebServlet - - webAllowOthers - - - - 1 - - - - H2Console - /console/* - - diff --git a/src/main/webapp/assets/common/css/gitbucket.css b/src/main/webapp/assets/common/css/gitbucket.css index 73fcfbb75..3aca43db3 100644 --- a/src/main/webapp/assets/common/css/gitbucket.css +++ b/src/main/webapp/assets/common/css/gitbucket.css @@ -124,6 +124,12 @@ div.content-wrapper { background-color: white; } +.table-scroll { + display: block; + position: relative; + overflow: scroll; +} + /* ======================================================================== */ /* Global Header */ /* ======================================================================== */ diff --git a/src/main/webapp/assets/common/images/column.gif b/src/main/webapp/assets/common/images/column.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6aeb357361190bc673b92c0c7f1aefeb6056804 GIT binary patch literal 317 zcmZ?wbhEHb6k-r!SZc}8*t=xKh671O{Rss<85L8yrmfy{NYquZUcHsQZLl+L5ymsX5t;1(-R&*|??pfS0VOjI!mCch^v`<^zJ!{>P z4F{HOI<#fqnG+Z97BS&av~iHtadMe)ow93pN}%f9pRsp!iSJ zxhOTUBsE2$JhLQ2AtWPJ!QIn0fI;ym3nK%AJ%bJ-10#a~5Hhei9++R?p(E9QLSD&m zMZ%;*w{t|C9H%lIe_Rs!bl<9VFB-U=gYV0{$ujcbS*ES&yK7(4)*G)^d1$ZWXlx8` LX>D_HWUvMRSH`W} literal 0 HcmV?d00001 diff --git a/src/main/webapp/assets/common/images/table.gif b/src/main/webapp/assets/common/images/table.gif new file mode 100644 index 0000000000000000000000000000000000000000..e64a80d426cead95fb076e9294521bbd3a0a5954 GIT binary patch literal 343 zcmZ?wbhEHb6k-r!SZc}8*t=xKh671O{Rss<85L8yrmfy{NYquZUcHsQZLl+L5ymsX5t;1(-R&*|??pfS0VOjI!mCch^v`<^zJ!{>P z4F{HOI<#fqnG+Z97BS&av~iHtadMe)ow93pN}%f9pRsp!k!8 zk%7UUL5GonkwE|m8Q4k=%rEfJk?MDINm5uKASTMaxa1&D{^mdphOC=5g4eiAT^MBg z-4r)pEKrzxIbiDQ-LHP^%F?rXP@q(ARBux4q*)