Move some service configuration from app.ini to database

pull/35607/head
Lunny Xiao 2025-10-08 14:20:54 +07:00
parent 03fce8f3d0
commit 82067ba731
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
35 changed files with 311 additions and 125 deletions

@ -844,13 +844,16 @@ LEVEL = Info
;; ;;
;; Default value for KeepEmailPrivate ;; Default value for KeepEmailPrivate
;; Each new user will get the value of this setting copied into their profile ;; Each new user will get the value of this setting copied into their profile
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_KEEP_EMAIL_PRIVATE = false ;DEFAULT_KEEP_EMAIL_PRIVATE = false
;; ;;
;; Default value for AllowCreateOrganization ;; Default value for AllowCreateOrganization
;; Every new user will have rights set to create organizations depending on this setting ;; Every new user will have rights set to create organizations depending on this setting
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_ALLOW_CREATE_ORGANIZATION = true ;DEFAULT_ALLOW_CREATE_ORGANIZATION = true
;; Default value for IsRestricted ;; Default value for IsRestricted
;; Every new user will have restricted permissions depending on this setting ;; Every new user will have restricted permissions depending on this setting
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_USER_IS_RESTRICTED = false ;DEFAULT_USER_IS_RESTRICTED = false
;; ;;
;; Either "public", "limited" or "private", default is "public" ;; Either "public", "limited" or "private", default is "public"
@ -870,13 +873,16 @@ LEVEL = Info
;; ;;
;; Default value for DefaultOrgMemberVisible ;; Default value for DefaultOrgMemberVisible
;; True will make the membership of the users visible when added to the organisation ;; True will make the membership of the users visible when added to the organisation
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_ORG_MEMBER_VISIBLE = false ;DEFAULT_ORG_MEMBER_VISIBLE = false
;; ;;
;; Default value for EnableDependencies ;; Default value for EnableDependencies
;; Repositories will use dependencies by default depending on this setting ;; Repositories will use dependencies by default depending on this setting
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_ENABLE_DEPENDENCIES = true ;DEFAULT_ENABLE_DEPENDENCIES = true
;; ;;
;; Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting. ;; Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting.
;; Deprecated: Moved to database based configuration which can be set from UI
;ALLOW_CROSS_REPOSITORY_DEPENDENCIES = true ;ALLOW_CROSS_REPOSITORY_DEPENDENCIES = true
;; ;;
;; Default map service. No external API support has been included. A service has to allow ;; Default map service. No external API support has been included. A service has to allow
@ -889,17 +895,21 @@ LEVEL = Info
; USER_LOCATION_MAP_URL = ; USER_LOCATION_MAP_URL =
;; ;;
;; Enable heatmap on users profiles. ;; Enable heatmap on users profiles.
;; Deprecated: Moved to database based configuration which can be set from UI
;ENABLE_USER_HEATMAP = true ;ENABLE_USER_HEATMAP = true
;; ;;
;; Enable Timetracking ;; Enable Timetracking
;; Deprecated: Moved to database based configuration which can be set from UI
;ENABLE_TIMETRACKING = true ;ENABLE_TIMETRACKING = true
;; ;;
;; Default value for EnableTimetracking ;; Default value for EnableTimetracking
;; Repositories will use timetracking by default depending on this setting ;; Repositories will use timetracking by default depending on this setting
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_ENABLE_TIMETRACKING = true ;DEFAULT_ENABLE_TIMETRACKING = true
;; ;;
;; Default value for AllowOnlyContributorsToTrackTime ;; Default value for AllowOnlyContributorsToTrackTime
;; Only users with write permissions can track time if this is true ;; Only users with write permissions can track time if this is true
;; Deprecated: Moved to database based configuration which can be set from UI
;DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true ;DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true
;; ;;
;; Value for the domain part of the user's email address in the git log if user ;; Value for the domain part of the user's email address in the git log if user
@ -918,10 +928,12 @@ LEVEL = Info
;; Default value for AutoWatchNewRepos ;; Default value for AutoWatchNewRepos
;; When adding a repo to a team or creating a new repo all team members will watch the ;; When adding a repo to a team or creating a new repo all team members will watch the
;; repo automatically if enabled ;; repo automatically if enabled
;; Deprecated: Moved to database based configuration which can be set from UI
;AUTO_WATCH_NEW_REPOS = true ;AUTO_WATCH_NEW_REPOS = true
;; ;;
;; Default value for AutoWatchOnChanges ;; Default value for AutoWatchOnChanges
;; Make the user watch a repository When they commit for the first time ;; Make the user watch a repository When they commit for the first time
;; Deprecated: Moved to database based configuration which can be set from UI
;AUTO_WATCH_ON_CHANGES = false ;AUTO_WATCH_ON_CHANGES = false
;; ;;
;; Minimum amount of time a user must exist before comments are kept when the user is deleted. ;; Minimum amount of time a user must exist before comments are kept when the user is deleted.

@ -7,8 +7,10 @@ import (
"testing" "testing"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -32,7 +34,11 @@ func TestIssueList_LoadRepositories(t *testing.T) {
func TestIssueList_LoadAttributes(t *testing.T) { func TestIssueList_LoadAttributes(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
setting.Service.EnableTimetracking = true system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.EnableTimeTracking.DynKey(): "true",
})
config.GetDynGetter().InvalidateCache()
issueList := issues_model.IssueList{ issueList := issues_model.IssueList{
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}),
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}), unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}),

@ -14,9 +14,11 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"xorm.io/builder" "xorm.io/builder"
@ -384,7 +386,10 @@ func TestCountIssues(t *testing.T) {
func TestIssueLoadAttributes(t *testing.T) { func TestIssueLoadAttributes(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
setting.Service.EnableTimetracking = true system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.EnableTimeTracking.DynKey(): "true",
})
config.GetDynGetter().InvalidateCache()
issueList := issues_model.IssueList{ issueList := issues_model.IssueList{
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}),

@ -4,6 +4,7 @@
package v1_6 package v1_6
import ( import (
"context"
"fmt" "fmt"
"time" "time"
@ -99,7 +100,7 @@ func AddIssueDependencies(x *xorm.Engine) (err error) {
unit.Config = make(map[string]any) unit.Config = make(map[string]any)
} }
if _, ok := unit.Config["EnableDependencies"]; !ok { if _, ok := unit.Config["EnableDependencies"]; !ok {
unit.Config["EnableDependencies"] = setting.Service.DefaultEnableDependencies unit.Config["EnableDependencies"] = setting.Config().Service.DefaultEnableDependencies.Value(context.Background())
} }
if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil { if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil {
return err return err

@ -326,7 +326,7 @@ func CreateOrganization(ctx context.Context, org *Organization, owner *user_mode
if err = db.Insert(ctx, &OrgUser{ if err = db.Insert(ctx, &OrgUser{
UID: owner.ID, UID: owner.ID,
OrgID: org.ID, OrgID: org.ID,
IsPublic: setting.Service.DefaultOrgMemberVisible, IsPublic: setting.Config().Service.DefaultOrgMemberVisible.Value(ctx),
}); err != nil { }); err != nil {
return fmt.Errorf("insert org-user relation: %w", err) return fmt.Errorf("insert org-user relation: %w", err)
} }
@ -504,7 +504,7 @@ func AddOrgUser(ctx context.Context, orgID, uid int64) error {
ou := &OrgUser{ ou := &OrgUser{
UID: uid, UID: uid,
OrgID: orgID, OrgID: orgID,
IsPublic: setting.Service.DefaultOrgMemberVisible, IsPublic: setting.Config().Service.DefaultOrgMemberVisible.Value(ctx),
} }
if err := db.Insert(ctx, ou); err != nil { if err := db.Insert(ctx, ou); err != nil {

@ -8,9 +8,11 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -141,12 +143,19 @@ func TestAddOrgUser(t *testing.T) {
assert.Equal(t, expectedNumMembers, org.NumMembers) assert.Equal(t, expectedNumMembers, org.NumMembers)
} }
setting.Service.DefaultOrgMemberVisible = false system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.DefaultOrgMemberVisible.DynKey(): "false",
})
config.GetDynGetter().InvalidateCache()
testSuccess(3, 5, false) testSuccess(3, 5, false)
testSuccess(3, 5, false) testSuccess(3, 5, false)
testSuccess(6, 2, false) testSuccess(6, 2, false)
setting.Service.DefaultOrgMemberVisible = true system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.DefaultOrgMemberVisible.DynKey(): "true",
})
config.GetDynGetter().InvalidateCache()
testSuccess(6, 3, true) testSuccess(6, 3, true)
unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{})

@ -11,29 +11,22 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
) )
// ___________.__ ___________ __
// \__ ___/|__| _____ ___\__ ___/___________ ____ | | __ ___________
// | | | |/ \_/ __ \| | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \
// | | | | Y Y \ ___/| | | | \// __ \\ \___| <\ ___/| | \/
// |____| |__|__|_| /\___ >____| |__| (____ /\___ >__|_ \\___ >__|
// \/ \/ \/ \/ \/ \/
// CanEnableTimetracker returns true when the server admin enabled time tracking // CanEnableTimetracker returns true when the server admin enabled time tracking
// This overrules IsTimetrackerEnabled // This overrules IsTimetrackerEnabled
func (repo *Repository) CanEnableTimetracker() bool { func (repo *Repository) CanEnableTimetracker(ctx context.Context) bool {
return setting.Service.EnableTimetracking return setting.Config().Service.EnableTimeTracking.Value(ctx)
} }
// IsTimetrackerEnabled returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs. // IsTimetrackerEnabled returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs.
func (repo *Repository) IsTimetrackerEnabled(ctx context.Context) bool { func (repo *Repository) IsTimetrackerEnabled(ctx context.Context) bool {
if !setting.Service.EnableTimetracking { if !setting.Config().Service.EnableTimeTracking.Value(ctx) {
return false return false
} }
var u *RepoUnit var u *RepoUnit
var err error var err error
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
return setting.Service.DefaultEnableTimetracking return setting.Config().Service.DefaultEnableTimeTracking.Value(ctx)
} }
return u.IssuesConfig().EnableTimetracker return u.IssuesConfig().EnableTimetracker
} }
@ -43,7 +36,7 @@ func (repo *Repository) AllowOnlyContributorsToTrackTime(ctx context.Context) bo
var u *RepoUnit var u *RepoUnit
var err error var err error
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
return setting.Service.DefaultAllowOnlyContributorsToTrackTime return setting.Config().Service.DefaultAllowOnlyContributorsToTrackTime.Value(ctx)
} }
return u.IssuesConfig().AllowOnlyContributorsToTrackTime return u.IssuesConfig().AllowOnlyContributorsToTrackTime
} }
@ -54,7 +47,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool {
var err error var err error
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
log.Trace("IsDependenciesEnabled: %v", err) log.Trace("IsDependenciesEnabled: %v", err)
return setting.Service.DefaultEnableDependencies return setting.Config().Service.DefaultEnableDependencies.Value(ctx)
} }
return u.IssuesConfig().EnableDependencies return u.IssuesConfig().EnableDependencies
} }

@ -164,7 +164,7 @@ func GetRepoWatchers(ctx context.Context, repoID int64, opts db.ListOptions) ([]
// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set // WatchIfAuto subscribes to repo if AutoWatchOnChanges is set
func WatchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error { func WatchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error {
if !isWrite || !setting.Service.AutoWatchOnChanges { if !isWrite || !setting.Config().Service.AutoWatchOnChanges.Value(ctx) {
return nil return nil
} }
watch, err := GetWatch(ctx, userID, repoID) watch, err := GetWatch(ctx, userID, repoID)

@ -8,9 +8,11 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -71,7 +73,10 @@ func TestWatchIfAuto(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, watchers, repo.NumWatches) assert.Len(t, watchers, repo.NumWatches)
setting.Service.AutoWatchOnChanges = false assert.NoError(t, system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.AutoWatchOnChanges.DynKey(): "false",
}))
config.GetDynGetter().InvalidateCache()
prevCount := repo.NumWatches prevCount := repo.NumWatches
@ -87,7 +92,10 @@ func TestWatchIfAuto(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, watchers, prevCount) assert.Len(t, watchers, prevCount)
setting.Service.AutoWatchOnChanges = true assert.NoError(t, system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.AutoWatchOnChanges.DynKey(): "true",
}))
config.GetDynGetter().InvalidateCache()
// Must not add watch // Must not add watch
assert.NoError(t, repo_model.WatchIfAuto(t.Context(), 8, 1, true)) assert.NoError(t, repo_model.WatchIfAuto(t.Context(), 8, 1, true))

@ -658,13 +658,13 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o
} }
// set system defaults // set system defaults
u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate u.KeepEmailPrivate = setting.Config().Service.DefaultKeepEmailPrivate.Value(ctx)
u.Visibility = setting.Service.DefaultUserVisibilityMode u.Visibility = setting.Service.DefaultUserVisibilityMode
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation u.AllowCreateOrganization = setting.Config().Service.DefaultAllowCreateOrganization.Value(ctx) && !setting.Admin.DisableRegularOrgCreation
u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
u.MaxRepoCreation = -1 u.MaxRepoCreation = -1
u.Theme = setting.UI.DefaultTheme u.Theme = setting.UI.DefaultTheme
u.IsRestricted = setting.Service.DefaultUserIsRestricted u.IsRestricted = setting.Config().Service.DefaultUserIsRestricted.Value(ctx)
u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm) u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
// Ensure consistency of the dates. // Ensure consistency of the dates.

@ -83,7 +83,7 @@ loop:
} }
then = now then = now
if setting.Service.EnableTimetracking { if setting.Config().Service.EnableTimeTracking.Value(ctx) {
usersStopwatches, err := issues_model.GetUIDsAndStopwatch(ctx) usersStopwatches, err := issues_model.GetUIDsAndStopwatch(ctx)
if err != nil { if err != nil {
log.Error("Unable to get GetUIDsAndStopwatch: %v", err) log.Error("Unable to get GetUIDsAndStopwatch: %v", err)

@ -52,9 +52,25 @@ type RepositoryStruct struct {
GitGuideRemoteName *config.Value[string] GitGuideRemoteName *config.Value[string]
} }
type ServiceStruct struct {
DefaultKeepEmailPrivate *config.Value[bool]
DefaultAllowCreateOrganization *config.Value[bool]
DefaultUserIsRestricted *config.Value[bool]
EnableTimeTracking *config.Value[bool]
DefaultEnableTimeTracking *config.Value[bool]
DefaultEnableDependencies *config.Value[bool]
AllowCrossRepositoryDependencies *config.Value[bool]
DefaultAllowOnlyContributorsToTrackTime *config.Value[bool]
EnableUserHeatmap *config.Value[bool]
AutoWatchNewRepos *config.Value[bool]
AutoWatchOnChanges *config.Value[bool]
DefaultOrgMemberVisible *config.Value[bool]
}
type ConfigStruct struct { type ConfigStruct struct {
Picture *PictureStruct Picture *PictureStruct
Repository *RepositoryStruct Repository *RepositoryStruct
Service *ServiceStruct
} }
var ( var (
@ -73,6 +89,20 @@ func initDefaultConfig() {
OpenWithEditorApps: config.ValueJSON[OpenWithEditorAppsType]("repository.open-with.editor-apps"), OpenWithEditorApps: config.ValueJSON[OpenWithEditorAppsType]("repository.open-with.editor-apps"),
GitGuideRemoteName: config.ValueJSON[string]("repository.git-guide-remote-name").WithDefault("origin"), GitGuideRemoteName: config.ValueJSON[string]("repository.git-guide-remote-name").WithDefault("origin"),
}, },
Service: &ServiceStruct{
DefaultKeepEmailPrivate: config.ValueJSON[bool]("service.default_keep_email_private").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_KEEP_EMAIL_PRIVATE"}).WithDefault(false),
DefaultAllowCreateOrganization: config.ValueJSON[bool]("service.default_allow_create_organization").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_ALLOW_CREATE_ORGANIZATION"}).WithDefault(true),
DefaultUserIsRestricted: config.ValueJSON[bool]("service.default_user_is_restricted").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_USER_IS_RESTRICTED"}).WithDefault(false),
EnableTimeTracking: config.ValueJSON[bool]("service.enable_time_tracking").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "ENABLE_TIMETRACKING"}).WithDefault(true),
DefaultEnableTimeTracking: config.ValueJSON[bool]("service.default_enable_time_tracking").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_ENABLE_TIMETRACKING"}).WithDefault(true),
DefaultEnableDependencies: config.ValueJSON[bool]("service.default_enable_dependencies").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_ENABLE_DEPENDENCIES"}).WithDefault(true),
AllowCrossRepositoryDependencies: config.ValueJSON[bool]("service.allow_cross_repository_dependencies").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "ALLOW_CROSS_REPOSITORY_DEPENDENCIES"}).WithDefault(true),
DefaultAllowOnlyContributorsToTrackTime: config.ValueJSON[bool]("service.default_allow_only_contributors_to_track_time").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME"}).WithDefault(true),
EnableUserHeatmap: config.ValueJSON[bool]("service.enable_user_heatmap").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "ENABLE_USER_HEATMAP"}).WithDefault(true),
AutoWatchNewRepos: config.ValueJSON[bool]("service.auto_watch_new_repos").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "AUTO_WATCH_NEW_REPOS"}).WithDefault(true),
AutoWatchOnChanges: config.ValueJSON[bool]("service.auto_watch_on_changes").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "AUTO_WATCH_ON_CHANGES"}).WithDefault(false),
DefaultOrgMemberVisible: config.ValueJSON[bool]("service.default_org_member_visible").WithFileConfig(config.CfgSecKey{Sec: "service", Key: "DEFAULT_ORG_MEMBER_VISIBLE"}).WithDefault(false),
},
} }
} }

@ -68,20 +68,8 @@ var Service = struct {
McaptchaSecret string McaptchaSecret string
McaptchaSitekey string McaptchaSitekey string
McaptchaURL string McaptchaURL string
DefaultKeepEmailPrivate bool
DefaultAllowCreateOrganization bool
DefaultUserIsRestricted bool
EnableTimetracking bool
DefaultEnableTimetracking bool
DefaultEnableDependencies bool
AllowCrossRepositoryDependencies bool
DefaultAllowOnlyContributorsToTrackTime bool
NoReplyAddress string NoReplyAddress string
UserLocationMapURL string UserLocationMapURL string
EnableUserHeatmap bool
AutoWatchNewRepos bool
AutoWatchOnChanges bool
DefaultOrgMemberVisible bool
UserDeleteWithCommentsMaxTime time.Duration UserDeleteWithCommentsMaxTime time.Duration
ValidSiteURLSchemes []string ValidSiteURLSchemes []string
@ -202,21 +190,9 @@ func loadServiceFrom(rootCfg ConfigProvider) {
Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/") Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/")
Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("") Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("")
Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("") Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("")
Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false)
Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true)
if Service.EnableTimetracking {
Service.DefaultEnableTimetracking = sec.Key("DEFAULT_ENABLE_TIMETRACKING").MustBool(true)
}
Service.DefaultEnableDependencies = sec.Key("DEFAULT_ENABLE_DEPENDENCIES").MustBool(true)
Service.AllowCrossRepositoryDependencies = sec.Key("ALLOW_CROSS_REPOSITORY_DEPENDENCIES").MustBool(true)
Service.DefaultAllowOnlyContributorsToTrackTime = sec.Key("DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME").MustBool(true)
Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply." + Domain) Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply." + Domain)
Service.UserLocationMapURL = sec.Key("USER_LOCATION_MAP_URL").String() Service.UserLocationMapURL = sec.Key("USER_LOCATION_MAP_URL").String()
Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true)
Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true)
Service.AutoWatchOnChanges = sec.Key("AUTO_WATCH_ON_CHANGES").MustBool(false)
modes := sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",") modes := sec.Key("ALLOWED_USER_VISIBILITY_MODES").Strings(",")
if len(modes) != 0 { if len(modes) != 0 {
Service.AllowedUserVisibilityModes = []string{} Service.AllowedUserVisibilityModes = []string{}
@ -246,7 +222,6 @@ func loadServiceFrom(rootCfg ConfigProvider) {
Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility] Service.DefaultUserVisibilityMode = structs.VisibilityModes[Service.DefaultUserVisibility]
Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes))
Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility]
Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool()
Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0) Service.UserDeleteWithCommentsMaxTime = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_TIME").MustDuration(0)
sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https") sec.Key("VALID_SITE_URL_SCHEMES").MustString("http,https")
Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",") Service.ValidSiteURLSchemes = sec.Key("VALID_SITE_URL_SCHEMES").Strings(",")

@ -5,6 +5,7 @@
package templates package templates
import ( import (
"context"
"fmt" "fmt"
"html/template" "html/template"
"net/url" "net/url"
@ -124,8 +125,8 @@ func NewFuncMap() template.FuncMap {
"MetaKeywords": func() string { "MetaKeywords": func() string {
return setting.UI.Meta.Keywords return setting.UI.Meta.Keywords
}, },
"EnableTimetracking": func() bool { "EnableTimeTracking": func(ctx context.Context) bool {
return setting.Service.EnableTimetracking return setting.Config().Service.EnableTimeTracking.Value(ctx)
}, },
"DisableWebhooks": func() bool { "DisableWebhooks": func() bool {
return setting.DisableWebhooks return setting.DisableWebhooks

@ -3383,7 +3383,29 @@ config.default_enable_timetracking = Enable Time Tracking by Default
config.default_allow_only_contributors_to_track_time = Let Only Contributors Track Time config.default_allow_only_contributors_to_track_time = Let Only Contributors Track Time
config.no_reply_address = Hidden Email Domain config.no_reply_address = Hidden Email Domain
config.default_visibility_organization = Default visibility for new Organizations config.default_visibility_organization = Default visibility for new Organizations
config.default_enable_dependencies = Enable Issue Dependencies by Default config.service_default_keep_email_private = Default value for KeepEmailPrivate
config.service_default_keep_email_private_desc = Each new user will get the value of this setting copied into their profile
config.service_default_allow_create_organization = Default value for AllowCreateOrganization
config.service_default_allow_create_organization_desc = Every new user will have rights set to create organizations depending on this setting
config.service_default_user_is_restricted = Default value for IsRestricted
config.service_default_user_is_restricted_desc = Every new user will have restricted permissions depending on this setting
config.service_enable_time_tracking = Enable Time Tracking
config.service_default_enable_time_tracking = Default value for EnableTimetracking
config.service_default_enable_time_tracking_desc = Repositories will use timetracking by default depending on this setting
config.service_default_enable_dependencies = Enable Issue Dependencies by Default
config.service_default_enable_dependencies_desc = Repositories will use dependencies by default depending on this setting
config.service_allow_cross_repository_dependencies = Allow Cross Repository Issue Dependencies
config.service_allow_cross_repository_dependencies_desc = Dependencies can be added from any repository where the user is granted access or only from the current repository depending on this setting.
config.service_default_allow_only_contributors_to_track_time = Default value for AllowOnlyContributorsToTrackTime
config.service_default_allow_only_contributors_to_track_time_desc = Only users with write permissions can track time if this is true
config.service_enable_user_heatmap = Enable User Heatmap
config.service_enable_user_heatmap_desc = Show a heatmap of user activity on user profiles
config.service_auto_watch_new_repos = Enable Auto Watch for New Repositories
config.service_auto_watch_new_repos_desc = When adding a repo to a team or creating a new repo all team members will watch the repo automatically if enabled
config.service_auto_watch_on_changes = Enable Auto Watch for Repositories Push
config.service_auto_watch_on_changes_desc = Make the user watch a repository When they commit for the first time
config.service_default_org_member_visible = Default value for DefaultOrgMemberVisible
config.service_default_org_member_visible_desc = True will make the membership of the users visible when added to the organisation
config.webhook_config = Webhook Configuration config.webhook_config = Webhook Configuration
config.queue_length = Queue Length config.queue_length = Queue Length

@ -1010,7 +1010,7 @@ func Routes() *web.Router {
m.Group("/{username}", func() { m.Group("/{username}", func() {
m.Get("", reqExploreSignIn(), user.GetInfo) m.Get("", reqExploreSignIn(), user.GetInfo)
if setting.Service.EnableUserHeatmap { if setting.Config().Service.EnableUserHeatmap.Value(gocontext.Background()) {
m.Get("/heatmap", user.GetUserHeatmapData) m.Get("/heatmap", user.GetUserHeatmapData)
} }

@ -509,7 +509,7 @@ func getParamsIssue(ctx *context.APIContext) *issues_model.Issue {
func getFormIssue(ctx *context.APIContext, form *api.IssueMeta) *issues_model.Issue { func getFormIssue(ctx *context.APIContext, form *api.IssueMeta) *issues_model.Issue {
var repo *repo_model.Repository var repo *repo_model.Repository
if form.Owner != ctx.Repo.Repository.OwnerName || form.Name != ctx.Repo.Repository.Name { if form.Owner != ctx.Repo.Repository.OwnerName || form.Name != ctx.Repo.Repository.Name {
if !setting.Service.AllowCrossRepositoryDependencies { if !setting.Config().Service.AllowCrossRepositoryDependencies.Value(ctx) {
ctx.JSON(http.StatusBadRequest, "CrossRepositoryDependencies not enabled") ctx.JSON(http.StatusBadRequest, "CrossRepositoryDependencies not enabled")
return nil return nil
} }

@ -62,7 +62,7 @@ func GetGeneralRepoSettings(ctx *context.APIContext) {
HTTPGitDisabled: setting.Repository.DisableHTTPGit, HTTPGitDisabled: setting.Repository.DisableHTTPGit,
MigrationsDisabled: setting.Repository.DisableMigrations, MigrationsDisabled: setting.Repository.DisableMigrations,
StarsDisabled: setting.Repository.DisableStars, StarsDisabled: setting.Repository.DisableStars,
TimeTrackingDisabled: !setting.Service.EnableTimetracking, TimeTrackingDisabled: !setting.Config().Service.EnableTimeTracking.Value(ctx),
LFSDisabled: !setting.LFS.StartServer, LFSDisabled: !setting.LFS.StartServer,
}) })
} }

@ -145,9 +145,9 @@ func Install(ctx *context.Context) {
form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration
form.EnableCaptcha = setting.Service.EnableCaptcha form.EnableCaptcha = setting.Service.EnableCaptcha
form.RequireSignInView = setting.Service.RequireSignInViewStrict form.RequireSignInView = setting.Service.RequireSignInViewStrict
form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate form.DefaultKeepEmailPrivate = setting.Config().Service.DefaultKeepEmailPrivate.Value(ctx)
form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization form.DefaultAllowCreateOrganization = setting.Config().Service.DefaultAllowCreateOrganization.Value(ctx)
form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking form.DefaultEnableTimetracking = setting.Config().Service.DefaultEnableTimeTracking.Value(ctx)
form.NoReplyAddress = setting.Service.NoReplyAddress form.NoReplyAddress = setting.Service.NoReplyAddress
form.PasswordAlgorithm = hash.ConfigHashAlgorithm(setting.PasswordHashAlgo) form.PasswordAlgorithm = hash.ConfigHashAlgorithm(setting.PasswordHashAlgo)

@ -233,6 +233,20 @@ func ChangeConfig(ctx *context.Context) {
marshallers := map[string]func(string) ([]byte, error){ marshallers := map[string]func(string) ([]byte, error){
cfg.Picture.DisableGravatar.DynKey(): marshalBool, cfg.Picture.DisableGravatar.DynKey(): marshalBool,
cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool, cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool,
cfg.Service.DefaultKeepEmailPrivate.DynKey(): marshalBool,
cfg.Service.DefaultAllowCreateOrganization.DynKey(): marshalBool,
cfg.Service.DefaultUserIsRestricted.DynKey(): marshalBool,
cfg.Service.EnableTimeTracking.DynKey(): marshalBool,
cfg.Service.DefaultEnableTimeTracking.DynKey(): marshalBool,
cfg.Service.DefaultEnableDependencies.DynKey(): marshalBool,
cfg.Service.AllowCrossRepositoryDependencies.DynKey(): marshalBool,
cfg.Service.DefaultAllowOnlyContributorsToTrackTime.DynKey(): marshalBool,
cfg.Service.EnableUserHeatmap.DynKey(): marshalBool,
cfg.Service.AutoWatchNewRepos.DynKey(): marshalBool,
cfg.Service.AutoWatchOnChanges.DynKey(): marshalBool,
cfg.Service.DefaultOrgMemberVisible.DynKey(): marshalBool,
cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps, cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps,
cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()), cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()),
} }

@ -191,7 +191,7 @@ func SignInOAuthCallback(ctx *context.Context) {
isAdmin, isRestricted := getUserAdminAndRestrictedFromGroupClaims(source, &gothUser) isAdmin, isRestricted := getUserAdminAndRestrictedFromGroupClaims(source, &gothUser)
u.IsAdmin = isAdmin.ValueOrDefault(user_service.UpdateOptionField[bool]{FieldValue: false}).FieldValue u.IsAdmin = isAdmin.ValueOrDefault(user_service.UpdateOptionField[bool]{FieldValue: false}).FieldValue
u.IsRestricted = isRestricted.ValueOrDefault(setting.Service.DefaultUserIsRestricted) u.IsRestricted = isRestricted.ValueOrDefault(setting.Config().Service.DefaultUserIsRestricted.Value(ctx))
linkAccountData := &LinkAccountData{authSource.ID, gothUser} linkAccountData := &LinkAccountData{authSource.ID, gothUser}
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingDisabled { if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingDisabled {

@ -46,7 +46,7 @@ func AddDependency(ctx *context.Context) {
// Check if both issues are in the same repo if cross repository dependencies is not enabled // Check if both issues are in the same repo if cross repository dependencies is not enabled
if issue.RepoID != dep.RepoID { if issue.RepoID != dep.RepoID {
if !setting.Service.AllowCrossRepositoryDependencies { if !setting.Config().Service.AllowCrossRepositoryDependencies.Value(ctx) {
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_same_repo")) ctx.Flash.Error(ctx.Tr("repo.issues.dependency.add_error_dep_not_same_repo"))
return return
} }

@ -464,7 +464,7 @@ func prepareIssueViewSidebarDependency(ctx *context.Context, issue *issues_model
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx, ctx.Doer, issue.IsPull) ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx, ctx.Doer, issue.IsPull)
// check if dependencies can be created across repositories // check if dependencies can be created across repositories
ctx.Data["AllowCrossRepositoryDependencies"] = setting.Service.AllowCrossRepositoryDependencies ctx.Data["AllowCrossRepositoryDependencies"] = setting.Config().Service.AllowCrossRepositoryDependencies.Value(ctx)
// Get Dependencies // Get Dependencies
blockedBy, err := issue.BlockedByDependencies(ctx, db.ListOptions{}) blockedBy, err := issue.BlockedByDependencies(ctx, db.ListOptions{})

@ -109,7 +109,7 @@ func Dashboard(ctx *context.Context) {
"uid": uid, "uid": uid,
} }
if setting.Service.EnableUserHeatmap { if setting.Config().Service.EnableUserHeatmap.Value(ctx) {
data, err := activities_model.GetUserHeatmapDataByUserTeam(ctx, ctxUser, ctx.Org.Team, ctx.Doer) data, err := activities_model.GetUserHeatmapDataByUserTeam(ctx, ctxUser, ctx.Org.Team, ctx.Doer)
if err != nil { if err != nil {
ctx.ServerError("GetUserHeatmapDataByUserTeam", err) ctx.ServerError("GetUserHeatmapDataByUserTeam", err)

@ -162,7 +162,7 @@ func prepareUserProfileTabData(ctx *context.Context, profileDbRepo *repo_model.R
total = int(numFollowing) total = int(numFollowing)
case "activity": case "activity":
// prepare heatmap data // prepare heatmap data
if setting.Service.EnableUserHeatmap { if setting.Config().Service.EnableUserHeatmap.Value(ctx) {
data, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer) data, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer)
if err != nil { if err != nil {
ctx.ServerError("GetUserHeatmapDataByUser", err) ctx.ServerError("GetUserHeatmapDataByUser", err)

@ -251,7 +251,7 @@ func AddTeamMember(ctx context.Context, team *organization.Team, user *user_mode
// this behaviour may spend much time so run it in a goroutine // this behaviour may spend much time so run it in a goroutine
// FIXME: Update watch repos batchly // FIXME: Update watch repos batchly
if setting.Service.AutoWatchNewRepos { if setting.Config().Service.AutoWatchNewRepos.Value(ctx) {
// Get team and its repositories. // Get team and its repositories.
repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{ repos, err := repo_model.GetTeamRepositories(ctx, &repo_model.SearchTeamRepoOptions{
TeamID: team.ID, TeamID: team.ID,

@ -376,9 +376,9 @@ func createRepositoryInDB(ctx context.Context, doer, u *user_model.User, repo *r
RepoID: repo.ID, RepoID: repo.ID,
Type: tp, Type: tp,
Config: &repo_model.IssuesConfig{ Config: &repo_model.IssuesConfig{
EnableTimetracker: setting.Service.DefaultEnableTimetracking, EnableTimetracker: setting.Config().Service.DefaultEnableTimeTracking.Value(ctx),
AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime, AllowOnlyContributorsToTrackTime: setting.Config().Service.DefaultAllowOnlyContributorsToTrackTime.Value(ctx),
EnableDependencies: setting.Service.DefaultEnableDependencies, EnableDependencies: setting.Config().Service.DefaultEnableDependencies.Value(ctx),
}, },
}) })
case unit.TypePullRequests: case unit.TypePullRequests:
@ -447,7 +447,7 @@ func createRepositoryInDB(ctx context.Context, doer, u *user_model.User, repo *r
return fmt.Errorf("RecalculateAccesses: %w", err) return fmt.Errorf("RecalculateAccesses: %w", err)
} }
if setting.Service.AutoWatchNewRepos { if setting.Config().Service.AutoWatchNewRepos.Value(ctx) {
if err = repo_model.WatchRepo(ctx, doer, repo, true); err != nil { if err = repo_model.WatchRepo(ctx, doer, repo, true); err != nil {
return fmt.Errorf("WatchRepo: %w", err) return fmt.Errorf("WatchRepo: %w", err)
} }

@ -45,7 +45,7 @@ func addRepositoryToTeam(ctx context.Context, t *organization.Team, repo *repo_m
} }
// Make all team members watch this repo if enabled in global settings // Make all team members watch this repo if enabled in global settings
if setting.Service.AutoWatchNewRepos { if setting.Config().Service.AutoWatchNewRepos.Value(ctx) {
if err = t.LoadMembers(ctx); err != nil { if err = t.LoadMembers(ctx); err != nil {
return fmt.Errorf("getMembers: %w", err) return fmt.Errorf("getMembers: %w", err)
} }

@ -13,9 +13,11 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
org_service "code.gitea.io/gitea/services/org" org_service "code.gitea.io/gitea/services/org"
@ -170,7 +172,10 @@ func TestCreateUser_Issue5882(t *testing.T) {
{&user_model.User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true}, {&user_model.User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true},
} }
setting.Service.DefaultAllowCreateOrganization = true system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.DefaultAllowCreateOrganization.DynKey(): "true",
})
config.GetDynGetter().InvalidateCache()
for _, v := range tt { for _, v := range tt {
setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation

@ -4,4 +4,6 @@
{{template "admin/config_settings/repository" .}} {{template "admin/config_settings/repository" .}}
{{template "admin/config_settings/service" .}}
{{template "admin/layout_footer" .}} {{template "admin/layout_footer" .}}

@ -0,0 +1,90 @@
<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.config.service_config"}}
</h4>
<div class="ui attached table segment">
<dl class="admin-dl-horizontal">
<dt>{{ctx.Locale.Tr "admin.config.service_default_keep_email_private"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_keep_email_private_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_keep_email_private" {{if .SystemConfig.Service.DefaultKeepEmailPrivate.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_allow_create_organization"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_allow_create_organization_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_allow_create_organization" {{if .SystemConfig.Service.DefaultAllowCreateOrganization.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_user_is_restricted"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_user_is_restricted_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_user_is_restricted" {{if .SystemConfig.Service.DefaultUserIsRestricted.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_enable_time_tracking"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_enable_time_tracking_desc"}}">
<input type="checkbox" data-config-dyn-key="service.enable_time_tracking" {{if .SystemConfig.Service.EnableTimeTracking.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_enable_time_tracking"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_enable_time_tracking_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_enable_time_tracking" {{if .SystemConfig.Service.DefaultEnableTimeTracking.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_enable_dependencies"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_enable_dependencies_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_enable_dependencies" {{if .SystemConfig.Service.DefaultEnableDependencies.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_allow_cross_repository_dependencies"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_allow_cross_repository_dependencies_desc"}}">
<input type="checkbox" data-config-dyn-key="service.allow_cross_repository_dependencies" {{if .SystemConfig.Service.AllowCrossRepositoryDependencies.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_allow_only_contributors_to_track_time"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_allow_only_contributors_to_track_time_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_allow_only_contributors_to_track_time" {{if .SystemConfig.Service.DefaultAllowOnlyContributorsToTrackTime.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_enable_user_heatmap"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_enable_user_heatmap_desc"}}">
<input type="checkbox" data-config-dyn-key="service.enable_user_heatmap" {{if .SystemConfig.Service.EnableUserHeatmap.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_auto_watch_new_repos"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_auto_watch_new_repos_desc"}}">
<input type="checkbox" data-config-dyn-key="service.auto_watch_new_repos" {{if .SystemConfig.Service.AutoWatchNewRepos.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_auto_watch_on_changes"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_auto_watch_on_changes_desc"}}">
<input type="checkbox" data-config-dyn-key="service.auto_watch_on_changes" {{if .SystemConfig.Service.AutoWatchOnChanges.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
<div class="divider"></div>
<dt>{{ctx.Locale.Tr "admin.config.service_default_org_member_visible"}}</dt>
<dd>
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.service_default_org_member_visible_desc"}}">
<input type="checkbox" data-config-dyn-key="service.default_org_member_visible" {{if .SystemConfig.Service.DefaultOrgMemberVisible.Value ctx}}checked{{end}}><label></label>
</div>
</dd>
</dl>
</div>

@ -16,7 +16,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
csrfToken: '{{.CsrfToken}}', csrfToken: '{{.CsrfToken}}',
pageData: {{.PageData}}, pageData: {{.PageData}},
notificationSettings: {{NotificationSettings}}, {{/*a map provided by NewFuncMap in helper.go*/}} notificationSettings: {{NotificationSettings}}, {{/*a map provided by NewFuncMap in helper.go*/}}
enableTimeTracking: {{EnableTimetracking}}, enableTimeTracking: {{EnableTimeTracking ctx}},
{{if or .Participants .Assignees .MentionableTeams}} {{if or .Participants .Assignees .MentionableTeams}}
mentionValues: Array.from(new Map([ mentionValues: Array.from(new Map([
{{- range .Participants -}} {{- range .Participants -}}

@ -44,7 +44,7 @@
{{end}} {{end}}
</a> </a>
{{end}} {{end}}
{{if and EnableTimetracking .IsOrganizationOwner}} {{if and (EnableTimeTracking ctx) .IsOrganizationOwner}}
<a class="{{if $.PageIsOrgTimes}}active{{end}} item" href="{{$.OrgLink}}/worktime"> <a class="{{if $.PageIsOrgTimes}}active{{end}} item" href="{{$.OrgLink}}/worktime">
{{svg "octicon-clock"}} {{ctx.Locale.Tr "org.worktime"}} {{svg "octicon-clock"}} {{ctx.Locale.Tr "org.worktime"}}
</a> </a>

@ -8,14 +8,22 @@ import (
"testing" "testing"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"github.com/stretchr/testify/assert"
) )
func TestRepoWatch(t *testing.T) { func TestRepoWatch(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
// Test round-trip auto-watch // Test round-trip auto-watch
setting.Service.AutoWatchOnChanges = true
assert.NoError(t, system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.AutoWatchOnChanges.DynKey(): "true",
}))
config.GetDynGetter().InvalidateCache()
session := loginUser(t, "user2") session := loginUser(t, "user2")
unittest.AssertNotExistsBean(t, &repo_model.Watch{UserID: 2, RepoID: 3}) unittest.AssertNotExistsBean(t, &repo_model.Watch{UserID: 2, RepoID: 3})
testEditFile(t, session, "org3", "repo3", "master", "README.md", "Hello, World (Edited for watch)\n") testEditFile(t, session, "org3", "repo3", "master", "README.md", "Hello, World (Edited for watch)\n")

@ -10,9 +10,11 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
@ -40,7 +42,10 @@ func TestSignup(t *testing.T) {
func TestSignupAsRestricted(t *testing.T) { func TestSignupAsRestricted(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)() defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
defer test.MockVariableValue(&setting.Service.DefaultUserIsRestricted, true)() system.SetSettings(t.Context(), map[string]string{
setting.Config().Service.DefaultUserIsRestricted.DynKey(): "true",
})
config.GetDynGetter().InvalidateCache()
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
"user_name": "restrictedUser", "user_name": "restrictedUser",