Use "Enable Gravatar" but not "Disable" (#36771)
* Fix #35685 * Fix #35627 * Fix #31112 Introduce "fipped" config value type, remove unused setting variables. Make DisableGravatar=true by defult, remove useless config options from the "Install" page. The legacy config options are still kept because they are still the fallback values for the system config options. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -238,9 +238,6 @@ RUN_USER = ; git
|
|||||||
;; Indicate whether to check minimum key size with corresponding type
|
;; Indicate whether to check minimum key size with corresponding type
|
||||||
;MINIMUM_KEY_SIZE_CHECK = false
|
;MINIMUM_KEY_SIZE_CHECK = false
|
||||||
;;
|
;;
|
||||||
;; Disable CDN even in "prod" mode
|
|
||||||
;OFFLINE_MODE = true
|
|
||||||
;;
|
|
||||||
;; TLS Settings: Either ACME or manual
|
;; TLS Settings: Either ACME or manual
|
||||||
;; (Other common TLS configuration are found before)
|
;; (Other common TLS configuration are found before)
|
||||||
;ENABLE_ACME = false
|
;ENABLE_ACME = false
|
||||||
@@ -1983,12 +1980,12 @@ LEVEL = Info
|
|||||||
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
||||||
;GRAVATAR_SOURCE = gravatar
|
;GRAVATAR_SOURCE = gravatar
|
||||||
;;
|
;;
|
||||||
;; This value will always be true in offline mode.
|
;; Deprecated, see Web UI Admin Panel -> Config -> Settings
|
||||||
;DISABLE_GRAVATAR = false
|
;DISABLE_GRAVATAR = false
|
||||||
;;
|
;;
|
||||||
;; Federated avatar lookup uses DNS to discover avatar associated
|
;; Federated avatar lookup uses DNS to discover avatar associated
|
||||||
;; with emails, see https://www.libravatar.org
|
;; with emails, see https://www.libravatar.org
|
||||||
;; This value will always be false in offline mode or when Gravatar is disabled.
|
;; Deprecated, see Web UI Admin Panel -> Config -> Settings
|
||||||
;ENABLE_FEDERATED_AVATAR = false
|
;ENABLE_FEDERATED_AVATAR = false
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
|
|||||||
switch {
|
switch {
|
||||||
case u.UseCustomAvatar:
|
case u.UseCustomAvatar:
|
||||||
useLocalAvatar = true
|
useLocalAvatar = true
|
||||||
case disableGravatar, setting.OfflineMode:
|
case disableGravatar:
|
||||||
useLocalAvatar = true
|
useLocalAvatar = true
|
||||||
autoGenerateAvatar = true
|
autoGenerateAvatar = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ func initDefaultConfig() {
|
|||||||
config.SetCfgSecKeyGetter(&cfgSecKeyGetter{})
|
config.SetCfgSecKeyGetter(&cfgSecKeyGetter{})
|
||||||
defaultConfig = &ConfigStruct{
|
defaultConfig = &ConfigStruct{
|
||||||
Picture: &PictureStruct{
|
Picture: &PictureStruct{
|
||||||
DisableGravatar: config.NewOption[bool]("picture.disable_gravatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "DISABLE_GRAVATAR"}),
|
DisableGravatar: config.NewOption[bool]("picture.disable_gravatar").WithDefaultSimple(true).WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "DISABLE_GRAVATAR"}),
|
||||||
EnableFederatedAvatar: config.NewOption[bool]("picture.enable_federated_avatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}),
|
EnableFederatedAvatar: config.NewOption[bool]("picture.enable_federated_avatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}),
|
||||||
},
|
},
|
||||||
Repository: &RepositoryStruct{
|
Repository: &RepositoryStruct{
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func (opt *Option[T]) ValueRevision(ctx context.Context) (v T, rev int, has bool
|
|||||||
var valStr *string
|
var valStr *string
|
||||||
if dynVal, hasDbValue := dg.GetValue(ctx, opt.dynKey); hasDbValue {
|
if dynVal, hasDbValue := dg.GetValue(ctx, opt.dynKey); hasDbValue {
|
||||||
valStr = &dynVal
|
valStr = &dynVal
|
||||||
} else if cfgVal, has := GetCfgSecKeyGetter().GetValue(opt.cfgSecKey.Sec, opt.cfgSecKey.Key); has {
|
} else if cfgVal, hasCfgValue := GetCfgSecKeyGetter().GetValue(opt.cfgSecKey.Sec, opt.cfgSecKey.Key); hasCfgValue {
|
||||||
valStr = &cfgVal
|
valStr = &cfgVal
|
||||||
}
|
}
|
||||||
if valStr == nil {
|
if valStr == nil {
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ var (
|
|||||||
RenderedSizeFactor: 2,
|
RenderedSizeFactor: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
GravatarSource string
|
GravatarSource string
|
||||||
DisableGravatar bool // Depreciated: migrated to database
|
|
||||||
EnableFederatedAvatar bool // Depreciated: migrated to database
|
|
||||||
|
|
||||||
RepoAvatar = struct {
|
RepoAvatar = struct {
|
||||||
Storage *Storage
|
Storage *Storage
|
||||||
@@ -65,29 +63,12 @@ func loadAvatarsFrom(rootCfg ConfigProvider) error {
|
|||||||
GravatarSource = source
|
GravatarSource = source
|
||||||
}
|
}
|
||||||
|
|
||||||
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar())
|
deprecatedSettingDB(rootCfg, "picture", "DISABLE_GRAVATAR")
|
||||||
deprecatedSettingDB(rootCfg, "", "DISABLE_GRAVATAR")
|
deprecatedSettingDB(rootCfg, "picture", "ENABLE_FEDERATED_AVATAR")
|
||||||
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar))
|
|
||||||
deprecatedSettingDB(rootCfg, "", "ENABLE_FEDERATED_AVATAR")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultDisableGravatar() bool {
|
|
||||||
return OfflineMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool {
|
|
||||||
v := !InstallLock
|
|
||||||
if OfflineMode {
|
|
||||||
v = false
|
|
||||||
}
|
|
||||||
if disableGravatar {
|
|
||||||
v = false
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadRepoAvatarFrom(rootCfg ConfigProvider) error {
|
func loadRepoAvatarFrom(rootCfg ConfigProvider) error {
|
||||||
sec := rootCfg.Section("picture")
|
sec := rootCfg.Section("picture")
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ var (
|
|||||||
RedirectOtherPort bool
|
RedirectOtherPort bool
|
||||||
RedirectorUseProxyProtocol bool
|
RedirectorUseProxyProtocol bool
|
||||||
PortToRedirect string
|
PortToRedirect string
|
||||||
OfflineMode bool
|
|
||||||
CertFile string
|
CertFile string
|
||||||
KeyFile string
|
KeyFile string
|
||||||
StaticRootPath string
|
StaticRootPath string
|
||||||
@@ -346,7 +345,6 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
|||||||
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
|
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
|
||||||
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
|
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
|
||||||
RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol)
|
RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol)
|
||||||
OfflineMode = sec.Key("OFFLINE_MODE").MustBool(true)
|
|
||||||
if len(StaticRootPath) == 0 {
|
if len(StaticRootPath) == 0 {
|
||||||
StaticRootPath = AppWorkPath
|
StaticRootPath = AppWorkPath
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,12 +285,6 @@
|
|||||||
"install.register_confirm": "Require Email Confirmation to Register",
|
"install.register_confirm": "Require Email Confirmation to Register",
|
||||||
"install.mail_notify": "Enable Email Notifications",
|
"install.mail_notify": "Enable Email Notifications",
|
||||||
"install.server_service_title": "Server and Third-Party Service Settings",
|
"install.server_service_title": "Server and Third-Party Service Settings",
|
||||||
"install.offline_mode": "Enable Local Mode",
|
|
||||||
"install.offline_mode_popup": "Disable third-party content delivery networks and serve all resources locally.",
|
|
||||||
"install.disable_gravatar": "Disable Gravatar",
|
|
||||||
"install.disable_gravatar_popup": "Disable Gravatar and third-party avatar sources. A default avatar will be used unless a user locally uploads an avatar.",
|
|
||||||
"install.federated_avatar_lookup": "Enable Federated Avatars",
|
|
||||||
"install.federated_avatar_lookup_popup": "Enable federated avatar lookup using Libravatar.",
|
|
||||||
"install.disable_registration": "Disable Self-Registration",
|
"install.disable_registration": "Disable Self-Registration",
|
||||||
"install.disable_registration_popup": "Disable user self-registration. Only administrators will be able to create new user accounts.",
|
"install.disable_registration_popup": "Disable user self-registration. Only administrators will be able to create new user accounts.",
|
||||||
"install.allow_only_external_registration_popup": "Allow Registration Only Through External Services",
|
"install.allow_only_external_registration_popup": "Allow Registration Only Through External Services",
|
||||||
@@ -3193,7 +3187,6 @@
|
|||||||
"admin.config.custom_conf": "Configuration File Path",
|
"admin.config.custom_conf": "Configuration File Path",
|
||||||
"admin.config.custom_file_root_path": "Custom File Root Path",
|
"admin.config.custom_file_root_path": "Custom File Root Path",
|
||||||
"admin.config.domain": "Server Domain",
|
"admin.config.domain": "Server Domain",
|
||||||
"admin.config.offline_mode": "Local Mode",
|
|
||||||
"admin.config.disable_router_log": "Disable Router Log",
|
"admin.config.disable_router_log": "Disable Router Log",
|
||||||
"admin.config.run_user": "Run As Username",
|
"admin.config.run_user": "Run As Username",
|
||||||
"admin.config.run_mode": "Run Mode",
|
"admin.config.run_mode": "Run Mode",
|
||||||
@@ -3296,7 +3289,7 @@
|
|||||||
"admin.config.cookie_life_time": "Cookie Life Time",
|
"admin.config.cookie_life_time": "Cookie Life Time",
|
||||||
"admin.config.picture_config": "Picture and Avatar Configuration",
|
"admin.config.picture_config": "Picture and Avatar Configuration",
|
||||||
"admin.config.picture_service": "Picture Service",
|
"admin.config.picture_service": "Picture Service",
|
||||||
"admin.config.disable_gravatar": "Disable Gravatar",
|
"admin.config.enable_gravatar": "Enable Gravatar",
|
||||||
"admin.config.enable_federated_avatar": "Enable Federated Avatars",
|
"admin.config.enable_federated_avatar": "Enable Federated Avatars",
|
||||||
"admin.config.open_with_editor_app_help": "The \"Open with\" editors for the clone menu. If left empty, the default will be used. Expand to see the default.",
|
"admin.config.open_with_editor_app_help": "The \"Open with\" editors for the clone menu. If left empty, the default will be used. Expand to see the default.",
|
||||||
"admin.config.git_guide_remote_name": "Repository remote name for git commands in the guide",
|
"admin.config.git_guide_remote_name": "Repository remote name for git commands in the guide",
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
db_install "code.gitea.io/gitea/models/db/install"
|
db_install "code.gitea.io/gitea/models/db/install"
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
"code.gitea.io/gitea/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
@@ -114,11 +113,6 @@ func Install(ctx *context.Context) {
|
|||||||
form.RegisterConfirm = setting.Service.RegisterEmailConfirm
|
form.RegisterConfirm = setting.Service.RegisterEmailConfirm
|
||||||
form.MailNotify = setting.Service.EnableNotifyMail
|
form.MailNotify = setting.Service.EnableNotifyMail
|
||||||
|
|
||||||
// Server and other services settings
|
|
||||||
form.OfflineMode = setting.OfflineMode
|
|
||||||
form.DisableGravatar = setting.DisableGravatar // when installing, there is no database connection so that given a default value
|
|
||||||
form.EnableFederatedAvatar = setting.EnableFederatedAvatar // when installing, there is no database connection so that given a default value
|
|
||||||
|
|
||||||
form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn
|
form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn
|
||||||
form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp
|
form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp
|
||||||
form.DisableRegistration = setting.Service.DisableRegistration
|
form.DisableRegistration = setting.Service.DisableRegistration
|
||||||
@@ -405,15 +399,6 @@ func SubmitInstall(ctx *context.Context) {
|
|||||||
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(strconv.FormatBool(form.RegisterConfirm))
|
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(strconv.FormatBool(form.RegisterConfirm))
|
||||||
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(strconv.FormatBool(form.MailNotify))
|
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(strconv.FormatBool(form.MailNotify))
|
||||||
|
|
||||||
cfg.Section("server").Key("OFFLINE_MODE").SetValue(strconv.FormatBool(form.OfflineMode))
|
|
||||||
if err := system_model.SetSettings(ctx, map[string]string{
|
|
||||||
setting.Config().Picture.DisableGravatar.DynKey(): strconv.FormatBool(form.DisableGravatar),
|
|
||||||
setting.Config().Picture.EnableFederatedAvatar.DynKey(): strconv.FormatBool(form.EnableFederatedAvatar),
|
|
||||||
}); err != nil {
|
|
||||||
ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(strconv.FormatBool(form.EnableOpenIDSignIn))
|
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(strconv.FormatBool(form.EnableOpenIDSignIn))
|
||||||
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(strconv.FormatBool(form.EnableOpenIDSignUp))
|
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(strconv.FormatBool(form.EnableOpenIDSignUp))
|
||||||
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(strconv.FormatBool(form.DisableRegistration))
|
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(strconv.FormatBool(form.DisableRegistration))
|
||||||
|
|||||||
@@ -126,7 +126,6 @@ func Config(ctx *context.Context) {
|
|||||||
ctx.Data["AppUrl"] = setting.AppURL
|
ctx.Data["AppUrl"] = setting.AppURL
|
||||||
ctx.Data["AppBuiltWith"] = setting.AppBuiltWith
|
ctx.Data["AppBuiltWith"] = setting.AppBuiltWith
|
||||||
ctx.Data["Domain"] = setting.Domain
|
ctx.Data["Domain"] = setting.Domain
|
||||||
ctx.Data["OfflineMode"] = setting.OfflineMode
|
|
||||||
ctx.Data["RunUser"] = setting.RunUser
|
ctx.Data["RunUser"] = setting.RunUser
|
||||||
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
|
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
|
||||||
ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo()
|
ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo()
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ type InstallForm struct {
|
|||||||
RegisterConfirm bool
|
RegisterConfirm bool
|
||||||
MailNotify bool
|
MailNotify bool
|
||||||
|
|
||||||
OfflineMode bool
|
|
||||||
DisableGravatar bool
|
|
||||||
EnableFederatedAvatar bool
|
|
||||||
EnableOpenIDSignIn bool
|
EnableOpenIDSignIn bool
|
||||||
EnableOpenIDSignUp bool
|
EnableOpenIDSignUp bool
|
||||||
DisableRegistration bool
|
DisableRegistration bool
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
<dd>{{.AppUrl}}</dd>
|
<dd>{{.AppUrl}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.domain"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.domain"}}</dt>
|
||||||
<dd>{{.Domain}}</dd>
|
<dd>{{.Domain}}</dd>
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.offline_mode"}}</dt>
|
|
||||||
<dd>{{svg (Iif .OfflineMode "octicon-check" "octicon-x")}}</dd>
|
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.disable_router_log"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.disable_router_log"}}</dt>
|
||||||
<dd>{{svg (Iif .DisableRouterLog "octicon-check" "octicon-x")}}</dd>
|
<dd>{{svg (Iif .DisableRouterLog "octicon-check" "octicon-x")}}</dd>
|
||||||
|
|
||||||
|
|||||||
@@ -3,17 +3,21 @@
|
|||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached table segment">
|
<div class="ui attached table segment">
|
||||||
<dl class="admin-dl-horizontal">
|
<dl class="admin-dl-horizontal">
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.disable_gravatar"}}</dt>
|
{{$cfgOpt := .SystemConfig.Picture.DisableGravatar}}
|
||||||
|
<dt>{{ctx.Locale.Tr "admin.config.enable_gravatar"}}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.disable_gravatar"}}">
|
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.enable_gravatar"}}">
|
||||||
<input type="checkbox" data-config-dyn-key="picture.disable_gravatar" {{if .SystemConfig.Picture.DisableGravatar.Value ctx}}checked{{end}}><label></label>
|
<input type="checkbox" data-config-dyn-key="{{$cfgOpt.DynKey}}" data-config-value-type="flipped" {{if not ($cfgOpt.Value ctx)}}checked{{end}}><label></label>
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
{{$cfgOpt = .SystemConfig.Picture.EnableFederatedAvatar}}
|
||||||
<dt>{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
<dt>{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}">
|
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}">
|
||||||
<input type="checkbox" data-config-dyn-key="picture.enable_federated_avatar" {{if .SystemConfig.Picture.EnableFederatedAvatar.Value ctx}}checked{{end}}><label></label>
|
<input type="checkbox" data-config-dyn-key="{{$cfgOpt.DynKey}}" data-config-value-type="boolean" {{if $cfgOpt.Value ctx}}checked{{end}}><label></label>
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
@@ -203,24 +203,6 @@
|
|||||||
<summary class="right-content tw-py-2{{if .Err_Services}} tw-text-red{{end}}">
|
<summary class="right-content tw-py-2{{if .Err_Services}} tw-text-red{{end}}">
|
||||||
{{ctx.Locale.Tr "install.server_service_title"}}
|
{{ctx.Locale.Tr "install.server_service_title"}}
|
||||||
</summary>
|
</summary>
|
||||||
<div class="inline field">
|
|
||||||
<div class="ui checkbox" id="offline-mode">
|
|
||||||
<label data-tooltip-content="{{ctx.Locale.Tr "install.offline_mode_popup"}}">{{ctx.Locale.Tr "install.offline_mode"}}</label>
|
|
||||||
<input name="offline_mode" type="checkbox" {{if .offline_mode}}checked{{end}}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline field">
|
|
||||||
<div class="ui checkbox" id="disable-gravatar">
|
|
||||||
<label data-tooltip-content="{{ctx.Locale.Tr "install.disable_gravatar_popup"}}">{{ctx.Locale.Tr "install.disable_gravatar"}}</label>
|
|
||||||
<input name="disable_gravatar" type="checkbox" {{if .disable_gravatar}}checked{{end}}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline field">
|
|
||||||
<div class="ui checkbox" id="federated-avatar-lookup">
|
|
||||||
<label data-tooltip-content="{{ctx.Locale.Tr "install.federated_avatar_lookup_popup"}}">{{ctx.Locale.Tr "install.federated_avatar_lookup"}}</label>
|
|
||||||
<input name="enable_federated_avatar" type="checkbox" {{if .enable_federated_avatar}}checked{{end}}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<div class="ui checkbox" id="enable-openid-signin">
|
<div class="ui checkbox" id="enable-openid-signin">
|
||||||
<label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signin_popup"}}">{{ctx.Locale.Tr "install.openid_signin"}}</label>
|
<label data-tooltip-content="{{ctx.Locale.Tr "install.openid_signin_popup"}}">{{ctx.Locale.Tr "install.openid_signin"}}</label>
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ SSH_LISTEN_HOST = localhost
|
|||||||
SSH_PORT = 2201
|
SSH_PORT = 2201
|
||||||
START_SSH_SERVER = true
|
START_SSH_SERVER = true
|
||||||
LFS_START_SERVER = true
|
LFS_START_SERVER = true
|
||||||
OFFLINE_MODE = false
|
|
||||||
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
||||||
BUILTIN_SSH_SERVER_USER = git
|
BUILTIN_SSH_SERVER_USER = git
|
||||||
SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE=
|
SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE=
|
||||||
@@ -62,10 +61,6 @@ DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
|||||||
NO_REPLY_ADDRESS = noreply.example.org
|
NO_REPLY_ADDRESS = noreply.example.org
|
||||||
ENABLE_NOTIFY_MAIL = true
|
ENABLE_NOTIFY_MAIL = true
|
||||||
|
|
||||||
[picture]
|
|
||||||
DISABLE_GRAVATAR = false
|
|
||||||
ENABLE_FEDERATED_AVATAR = false
|
|
||||||
|
|
||||||
[session]
|
[session]
|
||||||
PROVIDER = file
|
PROVIDER = file
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ SSH_LISTEN_HOST = localhost
|
|||||||
SSH_PORT = 2201
|
SSH_PORT = 2201
|
||||||
BUILTIN_SSH_SERVER_USER = git
|
BUILTIN_SSH_SERVER_USER = git
|
||||||
START_SSH_SERVER = true
|
START_SSH_SERVER = true
|
||||||
OFFLINE_MODE = false
|
|
||||||
|
|
||||||
LFS_START_SERVER = true
|
LFS_START_SERVER = true
|
||||||
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
||||||
@@ -65,10 +64,6 @@ DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
|||||||
NO_REPLY_ADDRESS = noreply.example.org
|
NO_REPLY_ADDRESS = noreply.example.org
|
||||||
ENABLE_NOTIFY_MAIL = true
|
ENABLE_NOTIFY_MAIL = true
|
||||||
|
|
||||||
[picture]
|
|
||||||
DISABLE_GRAVATAR = false
|
|
||||||
ENABLE_FEDERATED_AVATAR = false
|
|
||||||
|
|
||||||
[session]
|
[session]
|
||||||
PROVIDER = file
|
PROVIDER = file
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ SSH_LISTEN_HOST = localhost
|
|||||||
SSH_PORT = 2202
|
SSH_PORT = 2202
|
||||||
START_SSH_SERVER = true
|
START_SSH_SERVER = true
|
||||||
LFS_START_SERVER = true
|
LFS_START_SERVER = true
|
||||||
OFFLINE_MODE = false
|
|
||||||
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
||||||
BUILTIN_SSH_SERVER_USER = git
|
BUILTIN_SSH_SERVER_USER = git
|
||||||
SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE=
|
SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE=
|
||||||
@@ -63,10 +62,6 @@ DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
|||||||
NO_REPLY_ADDRESS = noreply.example.org
|
NO_REPLY_ADDRESS = noreply.example.org
|
||||||
ENABLE_NOTIFY_MAIL = true
|
ENABLE_NOTIFY_MAIL = true
|
||||||
|
|
||||||
[picture]
|
|
||||||
DISABLE_GRAVATAR = false
|
|
||||||
ENABLE_FEDERATED_AVATAR = false
|
|
||||||
|
|
||||||
[session]
|
[session]
|
||||||
PROVIDER = file
|
PROVIDER = file
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ SSH_LISTEN_HOST = localhost
|
|||||||
SSH_PORT = 2203
|
SSH_PORT = 2203
|
||||||
START_SSH_SERVER = true
|
START_SSH_SERVER = true
|
||||||
LFS_START_SERVER = true
|
LFS_START_SERVER = true
|
||||||
OFFLINE_MODE = false
|
|
||||||
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
||||||
ENABLE_GZIP = true
|
ENABLE_GZIP = true
|
||||||
BUILTIN_SSH_SERVER_USER = git
|
BUILTIN_SSH_SERVER_USER = git
|
||||||
@@ -59,10 +58,6 @@ DEFAULT_KEEP_EMAIL_PRIVATE = false
|
|||||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||||
NO_REPLY_ADDRESS = noreply.example.org
|
NO_REPLY_ADDRESS = noreply.example.org
|
||||||
|
|
||||||
[picture]
|
|
||||||
DISABLE_GRAVATAR = false
|
|
||||||
ENABLE_FEDERATED_AVATAR = false
|
|
||||||
|
|
||||||
[session]
|
[session]
|
||||||
PROVIDER = file
|
PROVIDER = file
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,15 @@ test('ConfigFormValueMapper', () => {
|
|||||||
|
|
||||||
<!-- top-level key -->
|
<!-- top-level key -->
|
||||||
<input name="k1" type="checkbox" value="v-key-only" data-config-dyn-key="k1" data-config-value-json="true" data-config-value-type="boolean">
|
<input name="k1" type="checkbox" value="v-key-only" data-config-dyn-key="k1" data-config-value-json="true" data-config-value-type="boolean">
|
||||||
|
|
||||||
<input type="hidden" data-config-dyn-key="k2" data-config-value-json='"k2-val"'>
|
<input type="hidden" data-config-dyn-key="k2" data-config-value-json='"k2-val"'>
|
||||||
<input name="k2">
|
<input name="k2">
|
||||||
|
|
||||||
<textarea name="repository.open-with.editor-apps"> a = b\n</textarea>
|
<textarea name="repository.open-with.editor-apps"> a = b\n</textarea>
|
||||||
|
|
||||||
|
<input name="k-flipped-true" type="checkbox" data-config-value-type="flipped">
|
||||||
|
<input name="k-flipped-false" type="checkbox" checked data-config-value-type="flipped">
|
||||||
|
|
||||||
<!-- sub key -->
|
<!-- sub key -->
|
||||||
<input type="hidden" data-config-dyn-key="struct" data-config-value-json='{"SubBoolean": true, "SubTimestamp": 123456789, "OtherKey": "other-value"}'>
|
<input type="hidden" data-config-dyn-key="struct" data-config-value-json='{"SubBoolean": true, "SubTimestamp": 123456789, "OtherKey": "other-value"}'>
|
||||||
<input name="struct.SubBoolean" type="checkbox" data-config-value-type="boolean">
|
<input name="struct.SubBoolean" type="checkbox" data-config-value-type="boolean">
|
||||||
@@ -35,6 +40,8 @@ test('ConfigFormValueMapper', () => {
|
|||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
'k1': 'true',
|
'k1': 'true',
|
||||||
'k2': '"k2-val"',
|
'k2': '"k2-val"',
|
||||||
|
'k-flipped-false': 'false',
|
||||||
|
'k-flipped-true': 'true',
|
||||||
'repository.open-with.editor-apps': '[{"DisplayName":"a","OpenURL":"b"}]', // TODO: OPEN-WITH-EDITOR-APP-JSON: it must match backend
|
'repository.open-with.editor-apps': '[{"DisplayName":"a","OpenURL":"b"}]', // TODO: OPEN-WITH-EDITOR-APP-JSON: it must match backend
|
||||||
'struct': '{"SubBoolean":true,"SubTimestamp":123456780,"OtherKey":"other-value","NewKey":"new-value"}',
|
'struct': '{"SubBoolean":true,"SubTimestamp":123456780,"OtherKey":"other-value","NewKey":"new-value"}',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,14 +6,23 @@ import {submitFormFetchAction} from '../common-fetch-action.ts';
|
|||||||
|
|
||||||
const {appSubUrl} = window.config;
|
const {appSubUrl} = window.config;
|
||||||
|
|
||||||
|
function collectCheckboxBooleanValue(el: HTMLInputElement): boolean {
|
||||||
|
const valType = el.getAttribute('data-config-value-type') as ConfigValueType;
|
||||||
|
if (valType === 'boolean') return el.checked;
|
||||||
|
if (valType === 'flipped') return !el.checked;
|
||||||
|
requireExplicitValueType(el);
|
||||||
|
}
|
||||||
|
|
||||||
function initSystemConfigAutoCheckbox(el: HTMLInputElement) {
|
function initSystemConfigAutoCheckbox(el: HTMLInputElement) {
|
||||||
el.addEventListener('change', async () => {
|
el.addEventListener('change', async () => {
|
||||||
// if the checkbox is inside a form, we assume it's handled by the form submit and do not send an individual request
|
// if the checkbox is inside a form, we assume it's handled by the form submit and do not send an individual request
|
||||||
if (el.closest('form')) return;
|
if (el.closest('form')) return;
|
||||||
try {
|
try {
|
||||||
const resp = await POST(`${appSubUrl}/-/admin/config`, {
|
const data = new URLSearchParams({
|
||||||
data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key')!, value: String(el.checked)}),
|
key: el.getAttribute('data-config-dyn-key')!,
|
||||||
|
value: String(collectCheckboxBooleanValue(el)),
|
||||||
});
|
});
|
||||||
|
const resp = await POST(`${appSubUrl}/-/admin/config`, {data});
|
||||||
const json: Record<string, any> = await resp.json();
|
const json: Record<string, any> = await resp.json();
|
||||||
if (json.errorMessage) throw new Error(json.errorMessage);
|
if (json.errorMessage) throw new Error(json.errorMessage);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -47,7 +56,7 @@ function extractElemConfigSubKey(el: GeneralFormFieldElement, dynKey: string): s
|
|||||||
|
|
||||||
// Due to the different design between HTML form elements and the JSON struct of the config values, we need to explicitly define some types.
|
// Due to the different design between HTML form elements and the JSON struct of the config values, we need to explicitly define some types.
|
||||||
// * checkbox can be used for boolean value, it can also be used for multiple values (array)
|
// * checkbox can be used for boolean value, it can also be used for multiple values (array)
|
||||||
type ConfigValueType = 'boolean' | 'string' | 'number' | 'timestamp'; // TODO: support more types like array, not used at the moment.
|
type ConfigValueType = 'boolean' | 'flipped' | 'string' | 'number' | 'timestamp'; // TODO: support more types like array, not used at the moment.
|
||||||
|
|
||||||
function toDatetimeLocalValue(unixSeconds: number) {
|
function toDatetimeLocalValue(unixSeconds: number) {
|
||||||
const d = new Date(unixSeconds * 1000);
|
const d = new Date(unixSeconds * 1000);
|
||||||
@@ -102,13 +111,14 @@ export class ConfigFormValueMapper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
collectConfigValueFromElement(el: GeneralFormFieldElement, _oldVal: any = null) {
|
collectConfigValueFromElement(el: GeneralFormFieldElement) {
|
||||||
let val: any;
|
let val: any;
|
||||||
const valType = this.presetValueTypes[el.name];
|
const valType = this.presetValueTypes[el.name];
|
||||||
if (el.matches('[type="checkbox"]')) {
|
if (el.matches('[type="checkbox"]')) {
|
||||||
if (valType !== 'boolean') requireExplicitValueType(el);
|
// TODO: if it needs to support array values in the future,
|
||||||
val = el.checked;
|
// it needs to iterate the "namedElems" to find all the checkboxes with the same name and collect values accordingly,
|
||||||
// oldVal: for future use when we support array value with checkbox
|
// and set the namedElems[matchedIdx] to null to avoid duplicate processing.
|
||||||
|
val = collectCheckboxBooleanValue(el);
|
||||||
} else if (el.matches('[type="datetime-local"]')) {
|
} else if (el.matches('[type="datetime-local"]')) {
|
||||||
if (valType !== 'timestamp') requireExplicitValueType(el);
|
if (valType !== 'timestamp') requireExplicitValueType(el);
|
||||||
val = Math.floor(new Date(el.value).getTime() / 1000) ?? 0; // NaN is fine to JSON.stringify, it becomes null.
|
val = Math.floor(new Date(el.value).getTime() / 1000) ?? 0; // NaN is fine to JSON.stringify, it becomes null.
|
||||||
@@ -128,7 +138,7 @@ export class ConfigFormValueMapper {
|
|||||||
if (!el) continue;
|
if (!el) continue;
|
||||||
const subKey = extractElemConfigSubKey(el, dynKey);
|
const subKey = extractElemConfigSubKey(el, dynKey);
|
||||||
if (!subKey) continue; // if not match, skip
|
if (!subKey) continue; // if not match, skip
|
||||||
cfgVal[subKey] = this.collectConfigValueFromElement(el, cfgVal[subKey]);
|
cfgVal[subKey] = this.collectConfigValueFromElement(el);
|
||||||
namedElems[idx] = null;
|
namedElems[idx] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,6 +190,7 @@ export class ConfigFormValueMapper {
|
|||||||
|
|
||||||
// now, the namedElems should only contain the config options without sub values,
|
// now, the namedElems should only contain the config options without sub values,
|
||||||
// directly store the value in formData with key as the element name, for example:
|
// directly store the value in formData with key as the element name, for example:
|
||||||
|
// "foo.enabled" => "true"
|
||||||
for (const el of namedElems) {
|
for (const el of namedElems) {
|
||||||
if (!el) continue;
|
if (!el) continue;
|
||||||
const dynKey = el.name;
|
const dynKey = el.name;
|
||||||
|
|||||||
@@ -60,25 +60,6 @@ function initPreInstall() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better handling of exclusive relations.
|
// TODO: better handling of exclusive relations.
|
||||||
document.querySelector<HTMLInputElement>('#offline-mode input')!.addEventListener('change', function () {
|
|
||||||
if (this.checked) {
|
|
||||||
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.checked = true;
|
|
||||||
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.checked = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.addEventListener('change', function () {
|
|
||||||
if (this.checked) {
|
|
||||||
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.checked = false;
|
|
||||||
} else {
|
|
||||||
document.querySelector<HTMLInputElement>('#offline-mode input')!.checked = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input')!.addEventListener('change', function () {
|
|
||||||
if (this.checked) {
|
|
||||||
document.querySelector<HTMLInputElement>('#disable-gravatar input')!.checked = false;
|
|
||||||
document.querySelector<HTMLInputElement>('#offline-mode input')!.checked = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.querySelector<HTMLInputElement>('#enable-openid-signin input')!.addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#enable-openid-signin input')!.addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
if (!document.querySelector<HTMLInputElement>('#disable-registration input')!.checked) {
|
if (!document.querySelector<HTMLInputElement>('#disable-registration input')!.checked) {
|
||||||
|
|||||||
Reference in New Issue
Block a user