summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLanre Adelowo <adelowomailbox@gmail.com>2019-01-09 18:22:57 +0100
committertechknowlogick <hello@techknowlogick.com>2019-01-09 12:22:57 -0500
commit8d2c24f7f9b9bce3a806e4748623bd3b2742025b (patch)
tree2010e6ffaf542d0828c496c31afa56f816c069d5
parentea518681d95c9ef8ae5ed71d6d8cd7cfb6994a50 (diff)
downloadgitea-8d2c24f7f9b9bce3a806e4748623bd3b2742025b.tar.gz
gitea-8d2c24f7f9b9bce3a806e4748623bd3b2742025b.zip
Allow for user specific themes (#5668)
* add migration and basic UI for changing a user's theme * update user themem * use right text on button * load theme based on users' selection * load theme based on users' selection in pwa too * update sample config * delete older theme loading * implement AfterLoad to set users' theme properly * set up default theme when creating a user. This uses the installation wide theme * use flash messages for error * set default theme when creating a user from the cli * fix @lunny review
-rw-r--r--cmd/admin.go1
-rw-r--r--custom/conf/app.ini.sample2
-rw-r--r--models/migrations/migrations.go4
-rw-r--r--models/migrations/v77.go17
-rw-r--r--models/user.go15
-rw-r--r--modules/auth/user_form.go26
-rw-r--r--modules/setting/defaults.go1
-rw-r--r--modules/setting/setting.go8
-rw-r--r--options/locale/locale_en-US.ini6
-rw-r--r--routers/routes/routes.go4
-rw-r--r--routers/user/setting/account.go28
-rw-r--r--templates/base/head.tmpl8
-rw-r--r--templates/pwa/serviceworker_js.tmpl10
-rw-r--r--templates/user/settings/account.tmpl38
14 files changed, 157 insertions, 11 deletions
diff --git a/cmd/admin.go b/cmd/admin.go
index ac911f184b..0934a7364b 100644
--- a/cmd/admin.go
+++ b/cmd/admin.go
@@ -340,6 +340,7 @@ func runCreateUser(c *cli.Context) error {
IsActive: true,
IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
+ Theme: setting.UI.DefaultTheme,
}); err != nil {
return fmt.Errorf("CreateUser: %v", err)
}
diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index 0b24bf3414..31048f7857 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -85,6 +85,8 @@ MAX_DISPLAY_FILE_SIZE = 8388608
SHOW_USER_EMAIL = true
; Set the default theme for the Gitea install
DEFAULT_THEME = gitea
+; All available themes
+THEMES = gitea,arc-green
[ui.admin]
; Number of users that are displayed on one page
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 1fa94c42aa..4c6b6d64bc 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -18,7 +18,7 @@ import (
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
gouuid "github.com/satori/go.uuid"
- "gopkg.in/ini.v1"
+ ini "gopkg.in/ini.v1"
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
@@ -206,6 +206,8 @@ var migrations = []Migration{
NewMigration("clear nonused data which not deleted when user was deleted", clearNonusedData),
// v76 -> v77
NewMigration("add pull request rebase with merge commit", addPullRequestRebaseWithMerge),
+ // v77 -> v78
+ NewMigration("add theme to users", addUserDefaultTheme),
}
// Migrate database to current version
diff --git a/models/migrations/v77.go b/models/migrations/v77.go
new file mode 100644
index 0000000000..12e7456642
--- /dev/null
+++ b/models/migrations/v77.go
@@ -0,0 +1,17 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "github.com/go-xorm/xorm"
+)
+
+func addUserDefaultTheme(x *xorm.Engine) error {
+ type User struct {
+ Theme string `xorm:"VARCHAR(30)"`
+ }
+
+ return x.Sync2(new(User))
+}
diff --git a/models/user.go b/models/user.go
index 3a47346e34..764c2280d7 100644
--- a/models/user.go
+++ b/models/user.go
@@ -140,6 +140,7 @@ type User struct {
// Preferences
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
+ Theme string `xorm:"NOT NULL DEFAULT ''"`
}
// BeforeUpdate is invoked from XORM before updating this object.
@@ -165,6 +166,13 @@ func (u *User) BeforeUpdate() {
u.Description = base.TruncateString(u.Description, 255)
}
+// AfterLoad is invoked from XORM after filling all the fields of this object.
+func (u *User) AfterLoad() {
+ if u.Theme == "" {
+ u.Theme = setting.UI.DefaultTheme
+ }
+}
+
// SetLastLogin set time to last login
func (u *User) SetLastLogin() {
u.LastLoginUnix = util.TimeStampNow()
@@ -176,6 +184,12 @@ func (u *User) UpdateDiffViewStyle(style string) error {
return UpdateUserCols(u, "diff_view_style")
}
+// UpdateTheme updates a users' theme irrespective of the site wide theme
+func (u *User) UpdateTheme(themeName string) error {
+ u.Theme = themeName
+ return UpdateUserCols(u, "theme")
+}
+
// getEmail returns an noreply email, if the user has set to keep his
// email address private, otherwise the primary email address.
func (u *User) getEmail() string {
@@ -777,6 +791,7 @@ func CreateUser(u *User) (err error) {
u.HashPassword(u.Passwd)
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
u.MaxRepoCreation = -1
+ u.Theme = setting.UI.DefaultTheme
if _, err = sess.Insert(u); err != nil {
return err
diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go
index c281672fe1..f59b795b4e 100644
--- a/modules/auth/user_form.go
+++ b/modules/auth/user_form.go
@@ -12,7 +12,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"github.com/go-macaron/binding"
- "gopkg.in/macaron.v1"
+ macaron "gopkg.in/macaron.v1"
)
// InstallForm form for installation page
@@ -189,6 +189,30 @@ func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi
return validate(errs, ctx.Data, f, ctx.Locale)
}
+// UpdateThemeForm form for updating a users' theme
+type UpdateThemeForm struct {
+ Theme string `binding:"Required;MaxSize(30)"`
+}
+
+// Validate validates the field
+func (f *UpdateThemeForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
+ return validate(errs, ctx.Data, f, ctx.Locale)
+}
+
+// IsThemeExists checks if the theme is a theme available in the config.
+func (f UpdateThemeForm) IsThemeExists() bool {
+ var exists bool
+
+ for _, v := range setting.UI.Themes {
+ if strings.ToLower(v) == strings.ToLower(f.Theme) {
+ exists = true
+ break
+ }
+ }
+
+ return exists
+}
+
// ChangePasswordForm form for changing password
type ChangePasswordForm struct {
OldPassword string `form:"old_password" binding:"MaxSize(255)"`
diff --git a/modules/setting/defaults.go b/modules/setting/defaults.go
index 7630d10090..48257284c7 100644
--- a/modules/setting/defaults.go
+++ b/modules/setting/defaults.go
@@ -8,4 +8,5 @@ var (
defaultLangs = strings.Split("en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR", ",")
defaultLangNames = strings.Split("English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어", ",")
defaultPullRequestWorkInProgressPrefixes = strings.Split("WIP:,[WIP]", ",")
+ defaultThemes = strings.Split("gitea", "arc-green")
)
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 23304453d2..88101937e9 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -33,9 +33,9 @@ import (
"github.com/go-macaron/session"
_ "github.com/go-macaron/session/redis" // redis plugin for store session
"github.com/go-xorm/core"
- "github.com/kballard/go-shellquote"
- "github.com/mcuadros/go-version"
- "gopkg.in/ini.v1"
+ shellquote "github.com/kballard/go-shellquote"
+ version "github.com/mcuadros/go-version"
+ ini "gopkg.in/ini.v1"
"strk.kbt.io/projects/go/libravatar"
)
@@ -303,6 +303,7 @@ var (
MaxDisplayFileSize int64
ShowUserEmail bool
DefaultTheme string
+ Themes []string
Admin struct {
UserPagingNum int
@@ -329,6 +330,7 @@ var (
ThemeColorMetaTag: `#6cc644`,
MaxDisplayFileSize: 8388608,
DefaultTheme: `gitea`,
+ Themes: []string{`gitea`, `arc-green`},
Admin: struct {
UserPagingNum int
RepoPagingNum int
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 0835175f16..06fe12d10b 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -355,6 +355,7 @@ password_username_disabled = Non-local users are not allowed to change their use
full_name = Full Name
website = Website
location = Location
+update_theme = Update Theme
update_profile = Update Profile
update_profile_success = Your profile has been updated.
change_username = Your username has been changed.
@@ -362,6 +363,7 @@ change_username_prompt = Note: username changes also change your account URL.
continue = Continue
cancel = Cancel
language = Language
+ui = Theme
lookup_avatar_by_mail = Look Up Avatar by Email Address
federated_avatar_lookup = Federated Avatar Lookup
@@ -382,14 +384,18 @@ password_change_disabled = Non-local users can not update their password through
emails = Email Addresses
manage_emails = Manage Email Addresses
+manage_themes = Select default theme
manage_openid = Manage OpenID Addresses
email_desc = Your primary email address will be used for notifications and other operations.
+theme_desc = This will be your default theme across the site.
primary = Primary
primary_email = Make Primary
delete_email = Remove
email_deletion = Remove Email Address
email_deletion_desc = The email address and related information will be removed from your account. Git commits by this email address will remain unchanged. Continue?
email_deletion_success = The email address has been removed.
+theme_update_success = Your theme was updated.
+theme_update_error = The selected theme does not exist.
openid_deletion = Remove OpenID Address
openid_deletion_desc = Removing this OpenID address from your account will prevent you from signing in with it. Continue?
openid_deletion_success = The OpenID address has been removed.
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index b776d0c201..6011427321 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -42,7 +42,7 @@ import (
"github.com/go-macaron/toolbox"
"github.com/prometheus/client_golang/prometheus"
"github.com/tstranex/u2f"
- "gopkg.in/macaron.v1"
+ macaron "gopkg.in/macaron.v1"
)
// NewMacaron initializes Macaron instance.
@@ -243,6 +243,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/email", bindIgnErr(auth.AddEmailForm{}), userSetting.EmailPost)
m.Post("/email/delete", userSetting.DeleteEmail)
m.Post("/delete", userSetting.DeleteAccount)
+ m.Post("/theme", bindIgnErr(auth.UpdateThemeForm{}), userSetting.UpdateUIThemePost)
})
m.Group("/security", func() {
m.Get("", userSetting.Security)
@@ -292,6 +293,7 @@ func RegisterRoutes(m *macaron.Macaron) {
})
}, reqSignIn, func(ctx *context.Context) {
ctx.Data["PageIsUserSettings"] = true
+ ctx.Data["AllThemes"] = setting.UI.Themes
})
m.Group("/user", func() {
diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go
index bcf602c5ed..ff8631bf5b 100644
--- a/routers/user/setting/account.go
+++ b/routers/user/setting/account.go
@@ -168,6 +168,34 @@ func DeleteAccount(ctx *context.Context) {
}
}
+// UpdateUIThemePost is used to update users' specific theme
+func UpdateUIThemePost(ctx *context.Context, form auth.UpdateThemeForm) {
+
+ ctx.Data["Title"] = ctx.Tr("settings")
+ ctx.Data["PageIsSettingsAccount"] = true
+
+ if ctx.HasError() {
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+ return
+ }
+
+ if !form.IsThemeExists() {
+ ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+ return
+ }
+
+ if err := ctx.User.UpdateTheme(form.Theme); err != nil {
+ ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+ return
+ }
+
+ log.Trace("Update user theme: %s", ctx.User.Name)
+ ctx.Flash.Success(ctx.Tr("settings.theme_update_success"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+}
+
func loadAccountData(ctx *context.Context) {
emails, err := models.GetEmailAddresses(ctx.User.ID)
if err != nil {
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index 47c0d6b473..b6afe94bb4 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -6,7 +6,7 @@
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
<link rel="manifest" href="{{AppSubUrl}}/manifest.json">
-
+
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
@@ -147,7 +147,11 @@
<meta property="og:url" content="{{AppUrl}}" />
<meta property="og:description" content="{{MetaDescription}}">
{{end}}
-{{if ne DefaultTheme "gitea"}}
+{{if .IsSigned }}
+ {{ if ne .SignedUser.Theme "gitea" }}
+ <link rel="stylesheet" href="{{AppSubUrl}}/css/theme-{{.SignedUser.Theme}}.css">
+ {{end}}
+{{else if ne DefaultTheme "gitea"}}
<link rel="stylesheet" href="{{AppSubUrl}}/css/theme-{{DefaultTheme}}.css">
{{end}}
{{template "custom/header" .}}
diff --git a/templates/pwa/serviceworker_js.tmpl b/templates/pwa/serviceworker_js.tmpl
index 5e5860ebb0..f109d06300 100644
--- a/templates/pwa/serviceworker_js.tmpl
+++ b/templates/pwa/serviceworker_js.tmpl
@@ -32,10 +32,14 @@ var urlsToCache = [
'{{AppSubUrl}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css',
'{{AppSubUrl}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.css',
'{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.css',
-{{if ne DefaultTheme "gitea"}}
- '{{AppSubUrl}}/css/theme-{{DefaultTheme}}.css',
+{{if .IsSigned }}
+ {{ if ne .SignedUser.Theme "gitea" }}
+ '{{AppSubUrl}}/css/theme-{{.SignedUser.Theme}}.css'
+ {{end}}
+{{else if ne DefaultTheme "gitea"}}
+ '{{AppSubUrl}}/css/theme-{{DefaultTheme}}.css'
{{end}}
-
+
// img
'{{AppSubUrl}}/img/gitea-sm.png',
'{{AppSubUrl}}/img/gitea-lg.png',
diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl
index 56c3df7f84..778103e44d 100644
--- a/templates/user/settings/account.tmpl
+++ b/templates/user/settings/account.tmpl
@@ -85,6 +85,44 @@
</form>
</div>
+ <h4 class="ui top attached header">
+ {{.i18n.Tr "settings.manage_themes"}}
+ </h4>
+ <div class="ui attached segment">
+ <div class="ui email list">
+ <div class="item">
+ {{.i18n.Tr "settings.theme_desc"}}
+ </div>
+
+ <form class="ui form" action="{{.Link}}/theme" method="post">
+ {{.CsrfTokenHtml}}
+ <div class="field">
+ <label for="ui">{{.i18n.Tr "settings.ui"}}</label>
+ <div class="ui selection dropdown" id="ui">
+ <input name="theme" type="hidden" value="{{.SignedUser.Theme}}">
+ <i class="dropdown icon"></i>
+ <div class="text">
+ {{range $i,$a := .AllThemes}}
+ {{if eq $.SignedUser.Theme $a}}{{$a}}{{end}}
+ {{end}}
+ </div>
+
+ <div class="menu">
+ {{range $i,$a := .AllThemes}}
+ <div class="item{{if eq $.SignedUser.Theme $a}} active selected{{end}}" data-value="{{$a}}">
+ {{$a}}
+ </div>
+ {{end}}
+ </div>
+ </div>
+ </div>
+
+ <div class="field">
+ <button class="ui green button">{{$.i18n.Tr "settings.update_theme"}}</button>
+ </div>
+ </form>
+ </div>
+ </div>
<h4 class="ui top attached warning header">
{{.i18n.Tr "settings.delete_account"}}
</h4>