From ea4da561c5e74793364b3afa6db314f6786001b5 Mon Sep 17 00:00:00 2001 From: onukura Date: Wed, 4 Nov 2020 00:51:25 +0900 Subject: [PATCH] Add syntax highlighter setting per user (#2555) --- .../resources/update/gitbucket-core_4.35.xml | 7 ++ .../core/controller/AccountController.scala | 29 +++++ .../RepositoryViewerController.scala | 15 ++- .../core/model/AccountPreference.scala | 21 ++++ .../scala/gitbucket/core/model/Profile.scala | 1 + .../core/service/AccountService.scala | 29 ++++- .../gitbucket/core/account/menu.scala.html | 5 + .../core/account/preferences.scala.html | 82 ++++++++++++ src/main/twirl/gitbucket/core/main.scala.html | 4 +- .../twirl/gitbucket/core/repo/blob.scala.html | 24 +++- .../webapp/assets/common/css/gitbucket.css | 7 +- .../atelier-cave-dark.css | 118 ++++++++++++++++++ .../atelier-cave-dark.min.css | 1 + .../atelier-cave-light.css | 118 ++++++++++++++++++ .../atelier-cave-light.min.css | 1 + .../atelier-dune-dark.css | 118 ++++++++++++++++++ .../atelier-dune-dark.min.css | 1 + .../atelier-dune-light.css | 118 ++++++++++++++++++ .../atelier-dune-light.min.css | 1 + .../atelier-estuary-dark.css | 118 ++++++++++++++++++ .../atelier-estuary-dark.min.css | 1 + .../atelier-estuary-light.css | 118 ++++++++++++++++++ .../atelier-estuary-light.min.css | 1 + .../atelier-forest-dark.css | 118 ++++++++++++++++++ .../atelier-forest-dark.min.css | 1 + .../atelier-forest-light.css | 118 ++++++++++++++++++ .../atelier-forest-light.min.css | 1 + .../atelier-heath-dark.css | 118 ++++++++++++++++++ .../atelier-heath-dark.min.css | 1 + .../atelier-heath-light.css | 118 ++++++++++++++++++ .../atelier-heath-light.min.css | 1 + .../atelier-lakeside-dark.css | 118 ++++++++++++++++++ .../atelier-lakeside-dark.min.css | 1 + .../atelier-lakeside-light.css | 118 ++++++++++++++++++ .../atelier-lakeside-light.min.css | 1 + .../atelier-plateau-dark.css | 118 ++++++++++++++++++ .../atelier-plateau-dark.min.css | 1 + .../atelier-plateau-light.css | 118 ++++++++++++++++++ .../atelier-plateau-light.min.css | 1 + .../atelier-savanna-dark.css | 118 ++++++++++++++++++ .../atelier-savanna-dark.min.css | 1 + .../atelier-savanna-light.css | 118 ++++++++++++++++++ .../atelier-savanna-light.min.css | 1 + .../atelier-seaside-dark.css | 118 ++++++++++++++++++ .../atelier-seaside-dark.min.css | 1 + .../atelier-seaside-light.css | 118 ++++++++++++++++++ .../atelier-seaside-light.min.css | 1 + .../atelier-sulphurpool-dark.css | 118 ++++++++++++++++++ .../atelier-sulphurpool-dark.min.css | 1 + .../atelier-sulphurpool-light.css | 118 ++++++++++++++++++ .../atelier-sulphurpool-light.min.css | 1 + .../github-v2.css | 118 ++++++++++++++++++ .../github-v2.min.css | 1 + .../github.css | 118 ++++++++++++++++++ .../github.min.css | 1 + .../hemisu-dark.css | 118 ++++++++++++++++++ .../hemisu-dark.min.css | 1 + .../hemisu-light.css | 118 ++++++++++++++++++ .../hemisu-light.min.css | 1 + .../tomorrow-night-blue.css | 118 ++++++++++++++++++ .../tomorrow-night-blue.min.css | 1 + .../tomorrow-night-bright.css | 118 ++++++++++++++++++ .../tomorrow-night-bright.min.css | 1 + .../tomorrow-night-eighties.css | 118 ++++++++++++++++++ .../tomorrow-night-eighties.min.css | 1 + .../tomorrow-night.css | 118 ++++++++++++++++++ .../tomorrow-night.min.css | 1 + .../tomorrow.css | 118 ++++++++++++++++++ .../tomorrow.min.css | 1 + .../vibrant-ink.css | 118 ++++++++++++++++++ .../vibrant-ink.min.css | 1 + 71 files changed, 3782 insertions(+), 12 deletions(-) create mode 100644 src/main/scala/gitbucket/core/model/AccountPreference.scala create mode 100644 src/main/twirl/gitbucket/core/account/preferences.scala.html create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-cave-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-cave-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-cave-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-cave-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-dune-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-dune-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-dune-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-dune-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-estuary-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-estuary-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-estuary-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-estuary-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-forest-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-forest-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-forest-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-forest-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-heath-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-heath-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-heath-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-heath-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-lakeside-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-lakeside-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-lakeside-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-lakeside-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-plateau-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-plateau-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-plateau-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-plateau-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-savanna-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-savanna-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-savanna-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-savanna-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-seaside-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-seaside-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-seaside-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-seaside-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-sulphurpool-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-sulphurpool-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-sulphurpool-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/atelier-sulphurpool-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/github-v2.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/github-v2.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/github.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/github.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/hemisu-dark.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/hemisu-dark.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/hemisu-light.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/hemisu-light.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-blue.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-blue.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-bright.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-bright.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-eighties.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night-eighties.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow-night.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/tomorrow.min.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/vibrant-ink.css create mode 100644 src/main/webapp/assets/vendors/color-themes-for-google-code-prettify/vibrant-ink.min.css diff --git a/src/main/resources/update/gitbucket-core_4.35.xml b/src/main/resources/update/gitbucket-core_4.35.xml index 687419ab3..bc648579f 100644 --- a/src/main/resources/update/gitbucket-core_4.35.xml +++ b/src/main/resources/update/gitbucket-core_4.35.xml @@ -11,4 +11,11 @@ + + + + + + + diff --git a/src/main/scala/gitbucket/core/controller/AccountController.scala b/src/main/scala/gitbucket/core/controller/AccountController.scala index b0aae0d88..556c717fb 100644 --- a/src/main/scala/gitbucket/core/controller/AccountController.scala +++ b/src/main/scala/gitbucket/core/controller/AccountController.scala @@ -82,6 +82,8 @@ trait AccountControllerBase extends AccountManagementControllerBase { case class PersonalTokenForm(note: String) + case class SyntaxHighlighterThemeForm(theme: String) + val newForm = mapping( "userName" -> trim(label("User name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))), "password" -> trim(label("Password", text(required, maxlength(20)))), @@ -122,6 +124,10 @@ trait AccountControllerBase extends AccountManagementControllerBase { "note" -> trim(label("Token", text(required, maxlength(100)))) )(PersonalTokenForm.apply) + val syntaxHighlighterThemeForm = mapping( + "highlighterTheme" -> trim(label("Theme", text(required))) + )(SyntaxHighlighterThemeForm.apply) + case class NewGroupForm( groupName: String, description: Option[String], @@ -442,6 +448,29 @@ trait AccountControllerBase extends AccountManagementControllerBase { redirect(s"/${userName}/_application") }) + /** + * Display the user preference settings page + */ + get("/:userName/_preferences")(oneselfOnly { + val userName = params("userName") + val currentTheme = getAccountPreference(userName) match { + case Some(accountHighlighter) => accountHighlighter.highlighterTheme + case _ => "github-v2" + } + getAccountByUserName(userName).map { x => + html.preferences(x, currentTheme) + } getOrElse NotFound() + }) + + /** + * Update the syntax highlighter setting of user + */ + post("/:userName/_preferences/highlighter", syntaxHighlighterThemeForm)(oneselfOnly { form => + val userName = params("userName") + addOrUpdateAccountPreference(userName, form.theme) + redirect(s"/${userName}/_preferences") + }) + get("/:userName/_hooks")(managersOnly { val userName = params("userName") getAccountByUserName(userName).map { account => diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala index a65b9d2db..da73ca8b2 100644 --- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala @@ -631,6 +631,7 @@ trait RepositoryViewerControllerBase extends ControllerBase { val blobRoute = get("/:owner/:repository/blob/*")(referrersOnly { repository => val (id, path) = repository.splitPath(multiParams("splat").head) val raw = params.get("raw").getOrElse("false").toBoolean + val highlighterTheme = getSyntaxHighlighterTheme() Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git => val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id)) @@ -650,13 +651,25 @@ trait RepositoryViewerControllerBase extends ControllerBase { hasWritePermission = hasDeveloperRole(repository.owner, repository.name, context.loginAccount), isBlame = request.paths(2) == "blame", isLfsFile = isLfsFile(git, objectId), - tabSize = info.tabSize + tabSize = info.tabSize, + highlighterTheme = highlighterTheme ) } } getOrElse NotFound() } }) + private def getSyntaxHighlighterTheme()(implicit context: Context): String = { + context.loginAccount match { + case Some(account) => + getAccountPreference(account.userName) match { + case Some(x) => x.highlighterTheme + case _ => "github-v2" + } + case _ => "github-v2" + } + } + private def isLfsFile(git: Git, objectId: ObjectId): Boolean = { JGitUtil.getObjectLoaderFromId(git, objectId)(JGitUtil.isLfsPointer).getOrElse(false) } diff --git a/src/main/scala/gitbucket/core/model/AccountPreference.scala b/src/main/scala/gitbucket/core/model/AccountPreference.scala new file mode 100644 index 000000000..6704fcfc7 --- /dev/null +++ b/src/main/scala/gitbucket/core/model/AccountPreference.scala @@ -0,0 +1,21 @@ +package gitbucket.core.model + +trait AccountPreferenceComponent { self: Profile => + import profile.api._ + + lazy val AccountPreferences = TableQuery[AccountPreferences] + + class AccountPreferences(tag: Tag) extends Table[AccountPreference](tag, "ACCOUNT_PREFERENCE") { + val userName = column[String]("USER_NAME", O PrimaryKey) + val highlighterTheme = column[String]("HIGHLIGHTER_THEME") + def * = + (userName, highlighterTheme) <> (AccountPreference.tupled, AccountPreference.unapply) + + def byPrimaryKey(userName: String): Rep[Boolean] = this.userName === userName.bind + } +} + +case class AccountPreference( + userName: String, + highlighterTheme: String = "prettify" +) diff --git a/src/main/scala/gitbucket/core/model/Profile.scala b/src/main/scala/gitbucket/core/model/Profile.scala index 43518085a..0226e0384 100644 --- a/src/main/scala/gitbucket/core/model/Profile.scala +++ b/src/main/scala/gitbucket/core/model/Profile.scala @@ -70,5 +70,6 @@ trait CoreProfile with ReleaseTagComponent with ReleaseAssetComponent with AccountExtraMailAddressComponent + with AccountPreferenceComponent object Profile extends CoreProfile diff --git a/src/main/scala/gitbucket/core/service/AccountService.scala b/src/main/scala/gitbucket/core/service/AccountService.scala index af75b8cba..3c256c84c 100644 --- a/src/main/scala/gitbucket/core/service/AccountService.scala +++ b/src/main/scala/gitbucket/core/service/AccountService.scala @@ -1,7 +1,7 @@ package gitbucket.core.service import org.slf4j.LoggerFactory -import gitbucket.core.model.{Account, AccountExtraMailAddress, GroupMember} +import gitbucket.core.model.{Account, AccountExtraMailAddress, AccountPreference, GroupMember} import gitbucket.core.model.Profile._ import gitbucket.core.model.Profile.profile.blockingApi._ import gitbucket.core.model.Profile.dateColumnType @@ -310,6 +310,33 @@ trait AccountService { Collaborators.filter(_.collaboratorName === userName.bind).sortBy(_.userName).map(_.userName).list.distinct } + /* + * For account preference + */ + def getAccountPreference(userName: String)( + implicit s: Session + ): Option[AccountPreference] = { + AccountPreferences filter (_.byPrimaryKey(userName)) firstOption + } + + def addAccountPreference(userName: String, highlighterTheme: String)(implicit s: Session): Unit = { + AccountPreferences insert AccountPreference(userName = userName, highlighterTheme = highlighterTheme) + } + + def updateAccountPreference(userName: String, highlighterTheme: String)(implicit s: Session): Unit = { + AccountPreferences + .filter(_.byPrimaryKey(userName)) + .map(t => t.highlighterTheme) + .update(highlighterTheme) + } + + def addOrUpdateAccountPreference(userName: String, highlighterTheme: String)(implicit s: Session): Unit = { + getAccountPreference(userName) match { + case Some(_) => updateAccountPreference(userName, highlighterTheme) + case _ => addAccountPreference(userName, highlighterTheme) + } + } + } object AccountService extends AccountService diff --git a/src/main/twirl/gitbucket/core/account/menu.scala.html b/src/main/twirl/gitbucket/core/account/menu.scala.html index b7ed72dfd..660313615 100644 --- a/src/main/twirl/gitbucket/core/account/menu.scala.html +++ b/src/main/twirl/gitbucket/core/account/menu.scala.html @@ -41,6 +41,11 @@ Service Hooks + @gitbucket.core.plugin.PluginRegistry().getAccountSettingMenus.map { menu => @menu(context).map { link =>