+
+-
+ @if(isAdmin) {
+
- + + Settings + + + } +
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a283220 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +*.class +*.log +*~ + +# sbt specific +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.classpath +.project +.cache +.settings + +# IntelliJ specific +.idea/ +.idea_modules/ + +# Ensime +.ensime +.ensime_cache/ \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..c73a009 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,11 @@ +project.git = true + +maxColumn = 120 +docstrings = JavaDoc + +align.tokens = ["%", "%%", {code = "=>", owner = "Case"}] +align.openParenCallSite = false +align.openParenDefnSite = false +continuationIndent.callSite = 2 +continuationIndent.defnSite = 2 +danglingParentheses = true \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..6b8c96a --- /dev/null +++ b/build.sbt @@ -0,0 +1,12 @@ +name := "gitbucket-navlink-plugin" +organization := "com.github.sikebe" +version := "0.0.1-SNAPSHOT" +scalaVersion := "2.12.4" +gitbucketVersion := "4.22.0" +scalacOptions := Seq("-deprecation") +javacOptions in compile ++= Seq("-source", + "1.8", + "-target", + "1.8", + "-encoding", + "UTF-8") \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..c4dc11b --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.1.0 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..b37642f --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,3 @@ +addSbtPlugin("io.github.gitbucket" % "sbt-gitbucket-plugin" % "1.2.0") +addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.4.0") +addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.1") diff --git a/src/main/scala/Plugin.scala b/src/main/scala/Plugin.scala new file mode 100644 index 0000000..5c9ef2d --- /dev/null +++ b/src/main/scala/Plugin.scala @@ -0,0 +1,26 @@ +import com.github.sikebe.navlink.controller.NavLinkSettingsController +import com.github.sikebe.navlink.service.NavLinkSettingsService +import gitbucket.core.controller.Context +import gitbucket.core.plugin.Link +import io.github.gitbucket.solidbase.model.Version + +class Plugin extends gitbucket.core.plugin.Plugin with NavLinkSettingsService { + override val pluginId: String = "navlink" + override val pluginName: String = "NavLink Plugin" + override val description: String = "Adding NavLinks" + override val versions: List[Version] = List(new Version("1.0.0")) + + override val controllers = Seq( + "/*" -> new NavLinkSettingsController() + ) + + override val globalMenus = Seq( + (_: Context) => Some(Link("navlink", navLinkSettings.globalMenuName, navLinkSettings.globalMenuPath)) + ) + + override val systemSettingMenus = Seq( + (_: Context) => Some(Link("navlink", "NavLink", "navlink/settings")) + ) + + val navLinkSettings = loadNavLinkSettings() +} diff --git a/src/main/scala/com/github/sikebe/navlink/controller/NavLinkSettingsController.scala b/src/main/scala/com/github/sikebe/navlink/controller/NavLinkSettingsController.scala new file mode 100644 index 0000000..bd1906a --- /dev/null +++ b/src/main/scala/com/github/sikebe/navlink/controller/NavLinkSettingsController.scala @@ -0,0 +1,40 @@ +package com.github.sikebe.navlink.controller + +import gitbucket.core.controller.ControllerBase +import gitbucket.core.util.AdminAuthenticator +import org.scalatra.forms._ +import sikebe.gitbucket.navlink.html +import com.github.sikebe.navlink.service.NavLinkSettingsService +import com.github.sikebe.navlink.service.NavLinkSettingsService._ +import gitbucket.core.plugin.PluginRegistry._ +import gitbucket.core.util.Implicits._ + +class NavLinkSettingsController + extends NavLinkSettingsControllerBase + with NavLinkSettingsService + with AdminAuthenticator + +trait NavLinkSettingsControllerBase extends ControllerBase { + self: NavLinkSettingsService with AdminAuthenticator => + + val settingsForm: MappingValueType[NavLinkSettings] = mapping( + "globalMenuName" -> text(required, maxlength(200)), + "globalMenuPath" -> text(required, maxlength(200)) + )(NavLinkSettings.apply) + + get("/navlink/settings")(adminOnly { + val settings = loadNavLinkSettings() + html.settings(settings.globalMenuName, settings.globalMenuPath, isAdmin = true) + }) + + post("/navlink/settings", settingsForm)(adminOnly { form => + assert(form.globalMenuName != null) + assert(!form.globalMenuName.isEmpty) + assert(form.globalMenuPath != null) + assert(!form.globalMenuPath.isEmpty) + + saveNavLinkSettings(form) + reload(request.getServletContext(), loadSystemSettings(), request2Session(request).conn) + redirect("/navlink/settings") + }) +} diff --git a/src/main/scala/com/github/sikebe/navlink/service/NavLinkSettingsService.scala b/src/main/scala/com/github/sikebe/navlink/service/NavLinkSettingsService.scala new file mode 100644 index 0000000..459328b --- /dev/null +++ b/src/main/scala/com/github/sikebe/navlink/service/NavLinkSettingsService.scala @@ -0,0 +1,56 @@ +package com.github.sikebe.navlink.service + +import java.io.File + +import gitbucket.core.util.Directory._ +import gitbucket.core.util.SyntaxSugars._ +import NavLinkSettingsService._ + +trait NavLinkSettingsService { + + val NavLinkConf = new File(GitBucketHome, "navlink.conf") + + def saveNavLinkSettings(settings: NavLinkSettings): Unit = + defining(new java.util.Properties()) { props => + props.setProperty(GlobalMenuName, settings.globalMenuName) + props.setProperty(GlobalMenuPath, settings.globalMenuPath) + using(new java.io.FileOutputStream(NavLinkConf)) { out => + props.store(out, null) + } + } + + def loadNavLinkSettings(): NavLinkSettings = + defining(new java.util.Properties()) { props => + if (NavLinkConf.exists) { + using(new java.io.FileInputStream(NavLinkConf)) { in => + props.load(in) + } + } + NavLinkSettings( + getValue[String](props, GlobalMenuName, ""), + getValue[String](props, GlobalMenuPath, "") + ) + } +} + +object NavLinkSettingsService { + import scala.reflect.ClassTag + + case class NavLinkSettings(globalMenuName: String, globalMenuPath: String) + + private val GlobalMenuName = "global_menu_name" + private val GlobalMenuPath = "global_menu_path" + + private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = + defining(props.getProperty(key)) { value => + if (value == null || value.isEmpty) default + else convertType(value).asInstanceOf[A] + } + + private def convertType[A: ClassTag](value: String) = + defining(implicitly[ClassTag[A]].runtimeClass) { c => + if (c == classOf[Boolean]) value.toBoolean + else if (c == classOf[Int]) value.toInt + else value + } +} diff --git a/src/main/twirl/sikebe/gitbucket/navlink/settings.scala.html b/src/main/twirl/sikebe/gitbucket/navlink/settings.scala.html new file mode 100644 index 0000000..f75d1c3 --- /dev/null +++ b/src/main/twirl/sikebe/gitbucket/navlink/settings.scala.html @@ -0,0 +1,26 @@ +@(name: String, path: String, isAdmin: Boolean)(implicit context: gitbucket.core.controller.Context) +@gitbucket.core.html.main("NavLink Setting", None){ +@sikebe.gitbucket.navlink.html.sidebar("settings", isAdmin){ +