Add system setting table with cache and also add cache supports for user setting (#18058)
This commit is contained in:
parent
5d3dbffa15
commit
f860a6d2e4
59 changed files with 1117 additions and 436 deletions
|
@ -14,7 +14,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
@ -62,11 +61,7 @@ func runPR() {
|
||||||
}
|
}
|
||||||
setting.AppWorkPath = curDir
|
setting.AppWorkPath = curDir
|
||||||
setting.StaticRootPath = curDir
|
setting.StaticRootPath = curDir
|
||||||
setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/")
|
setting.GravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("url.Parse: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
setting.AppURL = "http://localhost:8080/"
|
setting.AppURL = "http://localhost:8080/"
|
||||||
setting.HTTPPort = "8080"
|
setting.HTTPPort = "8080"
|
||||||
setting.SSH.Domain = "localhost"
|
setting.SSH.Domain = "localhost"
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
// Copyright 2017 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 admin_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/admin"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNotice_TrStr(t *testing.T) {
|
|
||||||
notice := &admin.Notice{
|
|
||||||
Type: admin.NoticeRepository,
|
|
||||||
Description: "test description",
|
|
||||||
}
|
|
||||||
assert.Equal(t, "admin.notices.type_1", notice.TrStr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateNotice(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
noticeBean := &admin.Notice{
|
|
||||||
Type: admin.NoticeRepository,
|
|
||||||
Description: "test description",
|
|
||||||
}
|
|
||||||
unittest.AssertNotExistsBean(t, noticeBean)
|
|
||||||
assert.NoError(t, admin.CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, noticeBean)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateRepositoryNotice(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
noticeBean := &admin.Notice{
|
|
||||||
Type: admin.NoticeRepository,
|
|
||||||
Description: "test description",
|
|
||||||
}
|
|
||||||
unittest.AssertNotExistsBean(t, noticeBean)
|
|
||||||
assert.NoError(t, admin.CreateRepositoryNotice(noticeBean.Description))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, noticeBean)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO TestRemoveAllWithNotice
|
|
||||||
|
|
||||||
func TestCountNotices(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
assert.Equal(t, int64(3), admin.CountNotices())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotices(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
notices, err := admin.Notices(1, 2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, notices, 2) {
|
|
||||||
assert.Equal(t, int64(3), notices[0].ID)
|
|
||||||
assert.Equal(t, int64(2), notices[1].ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
notices, err = admin.Notices(2, 2)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, notices, 1) {
|
|
||||||
assert.Equal(t, int64(1), notices[0].ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteNotice(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
assert.NoError(t, admin.DeleteNotice(3))
|
|
||||||
unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteNotices(t *testing.T) {
|
|
||||||
// delete a non-empty range
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
assert.NoError(t, admin.DeleteNotices(1, 2))
|
|
||||||
unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertNotExistsBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteNotices2(t *testing.T) {
|
|
||||||
// delete an empty range
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
assert.NoError(t, admin.DeleteNotices(3, 2))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteNoticesByIDs(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
|
|
||||||
assert.NoError(t, admin.DeleteNoticesByIDs([]int64{1, 3}))
|
|
||||||
unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
|
|
||||||
unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
|
|
||||||
}
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -72,7 +73,7 @@ func GetEmailForHash(md5Sum string) (string, error) {
|
||||||
// LibravatarURL returns the URL for the given email. Slow due to the DNS lookup.
|
// LibravatarURL returns the URL for the given email. Slow due to the DNS lookup.
|
||||||
// This function should only be called if a federated avatar service is enabled.
|
// This function should only be called if a federated avatar service is enabled.
|
||||||
func LibravatarURL(email string) (*url.URL, error) {
|
func LibravatarURL(email string) (*url.URL, error) {
|
||||||
urlStr, err := setting.LibravatarService.FromEmail(email)
|
urlStr, err := system_model.LibravatarService.FromEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
log.Error("LibravatarService.FromEmail(email=%s): error %v", email, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -149,8 +150,10 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
|
||||||
return DefaultAvatarLink()
|
return DefaultAvatarLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableFederatedAvatar, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
|
if enableFederatedAvatar != nil && enableFederatedAvatar.GetValueBool() && system_model.LibravatarService != nil {
|
||||||
emailHash := saveEmailHash(email)
|
emailHash := saveEmailHash(email)
|
||||||
if final {
|
if final {
|
||||||
// for final link, we can spend more time on slow external query
|
// for final link, we can spend more time on slow external query
|
||||||
|
@ -166,12 +169,16 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
|
||||||
urlStr += "?size=" + strconv.Itoa(size)
|
urlStr += "?size=" + strconv.Itoa(size)
|
||||||
}
|
}
|
||||||
return urlStr
|
return urlStr
|
||||||
} else if !setting.DisableGravatar {
|
}
|
||||||
|
|
||||||
|
disableGravatar, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
|
||||||
|
if disableGravatar != nil && !disableGravatar.GetValueBool() {
|
||||||
// copy GravatarSourceURL, because we will modify its Path.
|
// copy GravatarSourceURL, because we will modify its Path.
|
||||||
avatarURLCopy := *setting.GravatarSourceURL
|
avatarURLCopy := *system_model.GravatarSourceURL
|
||||||
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))
|
||||||
return generateRecognizedAvatarURL(avatarURLCopy, size)
|
return generateRecognizedAvatarURL(avatarURLCopy, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefaultAvatarLink()
|
return DefaultAvatarLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package avatars
|
package avatars_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
avatars_model "code.gitea.io/gitea/models/avatars"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -15,40 +16,43 @@ import (
|
||||||
|
|
||||||
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
const gravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
|
|
||||||
func disableGravatar() {
|
func disableGravatar(t *testing.T) {
|
||||||
setting.EnableFederatedAvatar = false
|
err := system_model.SetSettingNoVersion(system_model.KeyPictureEnableFederatedAvatar, "false")
|
||||||
setting.LibravatarService = nil
|
assert.NoError(t, err)
|
||||||
setting.DisableGravatar = true
|
err = system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "true")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
system_model.LibravatarService = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func enableGravatar(t *testing.T) {
|
func enableGravatar(t *testing.T) {
|
||||||
setting.DisableGravatar = false
|
err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "false")
|
||||||
var err error
|
assert.NoError(t, err)
|
||||||
setting.GravatarSourceURL, err = url.Parse(gravatarSource)
|
setting.GravatarSource = gravatarSource
|
||||||
|
err = system_model.Init()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHashEmail(t *testing.T) {
|
func TestHashEmail(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"d41d8cd98f00b204e9800998ecf8427e",
|
"d41d8cd98f00b204e9800998ecf8427e",
|
||||||
HashEmail(""),
|
avatars_model.HashEmail(""),
|
||||||
)
|
)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"353cbad9b58e69c96154ad99f92bedc7",
|
"353cbad9b58e69c96154ad99f92bedc7",
|
||||||
HashEmail("gitea@example.com"),
|
avatars_model.HashEmail("gitea@example.com"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSizedAvatarLink(t *testing.T) {
|
func TestSizedAvatarLink(t *testing.T) {
|
||||||
setting.AppSubURL = "/testsuburl"
|
setting.AppSubURL = "/testsuburl"
|
||||||
|
|
||||||
disableGravatar()
|
disableGravatar(t)
|
||||||
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
|
assert.Equal(t, "/testsuburl/assets/img/avatar_default.png",
|
||||||
GenerateEmailAvatarFastLink("gitea@example.com", 100))
|
avatars_model.GenerateEmailAvatarFastLink("gitea@example.com", 100))
|
||||||
|
|
||||||
enableGravatar(t)
|
enableGravatar(t)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
|
"https://secure.gravatar.com/avatar/353cbad9b58e69c96154ad99f92bedc7?d=identicon&s=100",
|
||||||
GenerateEmailAvatarFastLink("gitea@example.com", 100),
|
avatars_model.GenerateEmailAvatarFastLink("gitea@example.com", 100),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package admin_test
|
package avatars_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
15
models/fixtures/system_setting.yml
Normal file
15
models/fixtures/system_setting.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
-
|
||||||
|
id: 1
|
||||||
|
setting_key: 'disable_gravatar'
|
||||||
|
setting_value: 'false'
|
||||||
|
version: 1
|
||||||
|
created: 1653533198
|
||||||
|
updated: 1653533198
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2
|
||||||
|
setting_key: 'enable_federated_avatar'
|
||||||
|
setting_value: 'false'
|
||||||
|
version: 1
|
||||||
|
created: 1653533198
|
||||||
|
updated: 1653533198
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/foreignreference"
|
"code.gitea.io/gitea/models/foreignreference"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
|
@ -21,6 +20,7 @@ import (
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
project_model "code.gitea.io/gitea/models/project"
|
project_model "code.gitea.io/gitea/models/project"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
@ -2470,7 +2470,7 @@ func DeleteOrphanedIssues() error {
|
||||||
|
|
||||||
// Remove issue attachment files.
|
// Remove issue attachment files.
|
||||||
for i := range attachmentPaths {
|
for i := range attachmentPaths {
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i])
|
system_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i])
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
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/models/system"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -415,6 +415,8 @@ var migrations = []Migration{
|
||||||
NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", alterPublicGPGKeyContentFieldsToMediumText),
|
NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", alterPublicGPGKeyContentFieldsToMediumText),
|
||||||
// v226 -> v227
|
// v226 -> v227
|
||||||
NewMigration("Conan and generic packages do not need to be semantically versioned", fixPackageSemverField),
|
NewMigration("Conan and generic packages do not need to be semantically versioned", fixPackageSemverField),
|
||||||
|
// v227 -> v228
|
||||||
|
NewMigration("Create key/value table for system settings", createSystemSettingsTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
64
models/migrations/v227.go
Normal file
64
models/migrations/v227.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2022 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 (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SystemSetting struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
SettingKey string `xorm:"varchar(255) unique"` // ensure key is always lowercase
|
||||||
|
SettingValue string `xorm:"text"`
|
||||||
|
Version int `xorm:"version"` // prevent to override
|
||||||
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertSettingsIfNotExist(x *xorm.Engine, sysSettings []*SystemSetting) error {
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, setting := range sysSettings {
|
||||||
|
exist, err := sess.Table("system_setting").Where("setting_key=?", setting.SettingKey).Exist()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
if _, err := sess.Insert(setting); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSystemSettingsTable(x *xorm.Engine) error {
|
||||||
|
if err := x.Sync2(new(SystemSetting)); err != nil {
|
||||||
|
return fmt.Errorf("sync2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrate xx to database
|
||||||
|
sysSettings := []*SystemSetting{
|
||||||
|
{
|
||||||
|
SettingKey: "picture.disable_gravatar",
|
||||||
|
SettingValue: strconv.FormatBool(setting.DisableGravatar),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SettingKey: "picture.enable_federated_avatar",
|
||||||
|
SettingValue: strconv.FormatBool(setting.EnableFederatedAvatar),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return insertSettingsIfNotExist(x, sysSettings)
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import (
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
project_model "code.gitea.io/gitea/models/project"
|
project_model "code.gitea.io/gitea/models/project"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
|
@ -32,9 +33,13 @@ import (
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRepoContext creates a new repository context
|
// ItemsPerPage maximum items per page in forks, watchers and stars of a repo
|
||||||
func NewRepoContext() {
|
var ItemsPerPage = 40
|
||||||
|
|
||||||
|
// Init initialize model
|
||||||
|
func Init() error {
|
||||||
unit.LoadUnitConfig()
|
unit.LoadUnitConfig()
|
||||||
|
return system_model.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRepository deletes a repository for a user or organization.
|
// DeleteRepository deletes a repository for a user or organization.
|
||||||
|
@ -267,36 +272,36 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
|
|
||||||
// Remove repository files.
|
// Remove repository files.
|
||||||
repoPath := repo.RepoPath()
|
repoPath := repo.RepoPath()
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository files", repoPath)
|
system_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository files", repoPath)
|
||||||
|
|
||||||
// Remove wiki files
|
// Remove wiki files
|
||||||
if repo.HasWiki() {
|
if repo.HasWiki() {
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository wiki", repo.WikiPath())
|
system_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository wiki", repo.WikiPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove archives
|
// Remove archives
|
||||||
for _, archive := range archivePaths {
|
for _, archive := range archivePaths {
|
||||||
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.RepoArchives, "Delete repo archive file", archive)
|
system_model.RemoveStorageWithNotice(db.DefaultContext, storage.RepoArchives, "Delete repo archive file", archive)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove lfs objects
|
// Remove lfs objects
|
||||||
for _, lfsObj := range lfsPaths {
|
for _, lfsObj := range lfsPaths {
|
||||||
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.LFS, "Delete orphaned LFS file", lfsObj)
|
system_model.RemoveStorageWithNotice(db.DefaultContext, storage.LFS, "Delete orphaned LFS file", lfsObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove issue attachment files.
|
// Remove issue attachment files.
|
||||||
for _, attachment := range attachmentPaths {
|
for _, attachment := range attachmentPaths {
|
||||||
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachment)
|
system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove release attachment files.
|
// Remove release attachment files.
|
||||||
for _, releaseAttachment := range releaseAttachments {
|
for _, releaseAttachment := range releaseAttachments {
|
||||||
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete release attachment", releaseAttachment)
|
system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete release attachment", releaseAttachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove attachment with no issue_id and release_id.
|
// Remove attachment with no issue_id and release_id.
|
||||||
for _, newAttachment := range newAttachmentPaths {
|
for _, newAttachment := range newAttachmentPaths {
|
||||||
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", newAttachment)
|
system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", newAttachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(repo.Avatar) > 0 {
|
if len(repo.Avatar) > 0 {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package appstate
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
21
models/system/main_test.go
Normal file
21
models/system/main_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2020 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 system_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
_ "code.gitea.io/gitea/models" // register models
|
||||||
|
_ "code.gitea.io/gitea/models/system" // register models of system
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
|
GiteaRootPath: filepath.Join("..", ".."),
|
||||||
|
})
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package admin
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
117
models/system/notice_test.go
Normal file
117
models/system/notice_test.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright 2017 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 system_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/system"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNotice_TrStr(t *testing.T) {
|
||||||
|
notice := &system.Notice{
|
||||||
|
Type: system.NoticeRepository,
|
||||||
|
Description: "test description",
|
||||||
|
}
|
||||||
|
assert.Equal(t, "admin.notices.type_1", notice.TrStr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateNotice(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
noticeBean := &system.Notice{
|
||||||
|
Type: system.NoticeRepository,
|
||||||
|
Description: "test description",
|
||||||
|
}
|
||||||
|
unittest.AssertNotExistsBean(t, noticeBean)
|
||||||
|
assert.NoError(t, system.CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, noticeBean)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateRepositoryNotice(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
noticeBean := &system.Notice{
|
||||||
|
Type: system.NoticeRepository,
|
||||||
|
Description: "test description",
|
||||||
|
}
|
||||||
|
unittest.AssertNotExistsBean(t, noticeBean)
|
||||||
|
assert.NoError(t, system.CreateRepositoryNotice(noticeBean.Description))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, noticeBean)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO TestRemoveAllWithNotice
|
||||||
|
|
||||||
|
func TestCountNotices(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
assert.Equal(t, int64(3), system.CountNotices())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotices(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
notices, err := system.Notices(1, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, notices, 2) {
|
||||||
|
assert.Equal(t, int64(3), notices[0].ID)
|
||||||
|
assert.Equal(t, int64(2), notices[1].ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
notices, err = system.Notices(2, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, notices, 1) {
|
||||||
|
assert.Equal(t, int64(1), notices[0].ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNotice(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
assert.NoError(t, system.DeleteNotice(3))
|
||||||
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNotices(t *testing.T) {
|
||||||
|
// delete a non-empty range
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
assert.NoError(t, system.DeleteNotices(1, 2))
|
||||||
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNotices2(t *testing.T) {
|
||||||
|
// delete an empty range
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
assert.NoError(t, system.DeleteNotices(3, 2))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteNoticesByIDs(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
|
||||||
|
assert.NoError(t, system.DeleteNoticesByIDs([]int64{1, 3}))
|
||||||
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
|
||||||
|
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
|
||||||
|
}
|
261
models/system/setting.go
Normal file
261
models/system/setting.go
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
// Copyright 2021 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 system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
"strk.kbt.io/projects/go/libravatar"
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Setting is a key value store of user settings
|
||||||
|
type Setting struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
SettingKey string `xorm:"varchar(255) unique"` // ensure key is always lowercase
|
||||||
|
SettingValue string `xorm:"text"`
|
||||||
|
Version int `xorm:"version"` // prevent to override
|
||||||
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName sets the table name for the settings struct
|
||||||
|
func (s *Setting) TableName() string {
|
||||||
|
return "system_setting"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Setting) GetValueBool() bool {
|
||||||
|
b, _ := strconv.ParseBool(s.SettingValue)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(Setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrSettingIsNotExist represents an error that a setting is not exist with special key
|
||||||
|
type ErrSettingIsNotExist struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error
|
||||||
|
func (err ErrSettingIsNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("System setting[%s] is not exist", err.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrSettingIsNotExist return true if err is ErrSettingIsNotExist
|
||||||
|
func IsErrSettingIsNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrSettingIsNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDataExpired represents an error that update a record which has been updated by another thread
|
||||||
|
type ErrDataExpired struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error
|
||||||
|
func (err ErrDataExpired) Error() string {
|
||||||
|
return fmt.Sprintf("System setting[%s] has been updated by another thread", err.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrDataExpired return true if err is ErrDataExpired
|
||||||
|
func IsErrDataExpired(err error) bool {
|
||||||
|
_, ok := err.(ErrDataExpired)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSetting returns specific setting
|
||||||
|
func GetSetting(key string) (*Setting, error) {
|
||||||
|
v, err := GetSettings([]string{key})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(v) == 0 {
|
||||||
|
return nil, ErrSettingIsNotExist{key}
|
||||||
|
}
|
||||||
|
return v[key], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSettings returns specific settings
|
||||||
|
func GetSettings(keys []string) (map[string]*Setting, error) {
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
keys[i] = strings.ToLower(keys[i])
|
||||||
|
}
|
||||||
|
settings := make([]*Setting, 0, len(keys))
|
||||||
|
if err := db.GetEngine(db.DefaultContext).
|
||||||
|
Where(builder.In("setting_key", keys)).
|
||||||
|
Find(&settings); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
settingsMap := make(map[string]*Setting)
|
||||||
|
for _, s := range settings {
|
||||||
|
settingsMap[s.SettingKey] = s
|
||||||
|
}
|
||||||
|
return settingsMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type AllSettings map[string]*Setting
|
||||||
|
|
||||||
|
func (settings AllSettings) Get(key string) Setting {
|
||||||
|
if v, ok := settings[key]; ok {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return Setting{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings AllSettings) GetBool(key string) bool {
|
||||||
|
b, _ := strconv.ParseBool(settings.Get(key).SettingValue)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings AllSettings) GetVersion(key string) int {
|
||||||
|
return settings.Get(key).Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllSettings returns all settings from user
|
||||||
|
func GetAllSettings() (AllSettings, error) {
|
||||||
|
settings := make([]*Setting, 0, 5)
|
||||||
|
if err := db.GetEngine(db.DefaultContext).
|
||||||
|
Find(&settings); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
settingsMap := make(map[string]*Setting)
|
||||||
|
for _, s := range settings {
|
||||||
|
settingsMap[s.SettingKey] = s
|
||||||
|
}
|
||||||
|
return settingsMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSetting deletes a specific setting for a user
|
||||||
|
func DeleteSetting(setting *Setting) error {
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).Delete(setting)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSettingNoVersion(key, value string) error {
|
||||||
|
s, err := GetSetting(key)
|
||||||
|
if IsErrSettingIsNotExist(err) {
|
||||||
|
return SetSetting(&Setting{
|
||||||
|
SettingKey: key,
|
||||||
|
SettingValue: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.SettingValue = value
|
||||||
|
return SetSetting(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSetting updates a users' setting for a specific key
|
||||||
|
func SetSetting(setting *Setting) error {
|
||||||
|
if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
setting.Version++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func upsertSettingValue(key, value string, version int) error {
|
||||||
|
return db.WithTx(func(ctx context.Context) error {
|
||||||
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
// here we use a general method to do a safe upsert for different databases (and most transaction levels)
|
||||||
|
// 1. try to UPDATE the record and acquire the transaction write lock
|
||||||
|
// if UPDATE returns non-zero rows are changed, OK, the setting is saved correctly
|
||||||
|
// if UPDATE returns "0 rows changed", two possibilities: (a) record doesn't exist (b) value is not changed
|
||||||
|
// 2. do a SELECT to check if the row exists or not (we already have the transaction lock)
|
||||||
|
// 3. if the row doesn't exist, do an INSERT (we are still protected by the transaction lock, so it's safe)
|
||||||
|
//
|
||||||
|
// to optimize the SELECT in step 2, we can use an extra column like `revision=revision+1`
|
||||||
|
// to make sure the UPDATE always returns a non-zero value for existing (unchanged) records.
|
||||||
|
|
||||||
|
res, err := e.Exec("UPDATE system_setting SET setting_value=?, version = version+1 WHERE setting_key=? AND version=?", value, key, version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows, _ := res.RowsAffected()
|
||||||
|
if rows > 0 {
|
||||||
|
// the existing row is updated, so we can return
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case the value isn't changed, update would return 0 rows changed, so we need this check
|
||||||
|
has, err := e.Exist(&Setting{SettingKey: key})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if has {
|
||||||
|
return ErrDataExpired{Key: key}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no existing row, insert a new row
|
||||||
|
_, err = e.Insert(&Setting{SettingKey: key, SettingValue: value})
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
GravatarSourceURL *url.URL
|
||||||
|
LibravatarService *libravatar.Libravatar
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() error {
|
||||||
|
var disableGravatar bool
|
||||||
|
disableGravatarSetting, err := GetSetting(KeyPictureDisableGravatar)
|
||||||
|
if IsErrSettingIsNotExist(err) {
|
||||||
|
disableGravatar = setting.GetDefaultDisableGravatar()
|
||||||
|
disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
disableGravatar = disableGravatarSetting.GetValueBool()
|
||||||
|
}
|
||||||
|
|
||||||
|
var enableFederatedAvatar bool
|
||||||
|
enableFederatedAvatarSetting, err := GetSetting(KeyPictureEnableFederatedAvatar)
|
||||||
|
if IsErrSettingIsNotExist(err) {
|
||||||
|
enableFederatedAvatar = setting.GetDefaultEnableFederatedAvatar(disableGravatar)
|
||||||
|
enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
enableFederatedAvatar = disableGravatarSetting.GetValueBool()
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.OfflineMode {
|
||||||
|
disableGravatar = true
|
||||||
|
enableFederatedAvatar = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if disableGravatar || !enableFederatedAvatar {
|
||||||
|
var err error
|
||||||
|
GravatarSourceURL, err = url.Parse(setting.GravatarSource)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to parse Gravatar URL(%s): %v", setting.GravatarSource, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if enableFederatedAvatarSetting.GetValueBool() {
|
||||||
|
LibravatarService = libravatar.New()
|
||||||
|
if GravatarSourceURL.Scheme == "https" {
|
||||||
|
LibravatarService.SetUseHTTPS(true)
|
||||||
|
LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
|
||||||
|
} else {
|
||||||
|
LibravatarService.SetUseHTTPS(false)
|
||||||
|
LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
11
models/system/setting_key.go
Normal file
11
models/system/setting_key.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2022 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 system
|
||||||
|
|
||||||
|
// enumerate all system setting keys
|
||||||
|
const (
|
||||||
|
KeyPictureDisableGravatar = "picture.disable_gravatar"
|
||||||
|
KeyPictureEnableFederatedAvatar = "picture.enable_federated_avatar"
|
||||||
|
)
|
53
models/system/setting_test.go
Normal file
53
models/system/setting_test.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2021 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 system_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/system"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSettings(t *testing.T) {
|
||||||
|
keyName := "server.LFS_LOCKS_PAGING_NUM"
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
newSetting := &system.Setting{SettingKey: keyName, SettingValue: "50"}
|
||||||
|
|
||||||
|
// create setting
|
||||||
|
err := system.SetSetting(newSetting)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// test about saving unchanged values
|
||||||
|
err = system.SetSetting(newSetting)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// get specific setting
|
||||||
|
settings, err := system.GetSettings([]string{keyName})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, settings, 1)
|
||||||
|
assert.EqualValues(t, newSetting.SettingValue, settings[strings.ToLower(keyName)].SettingValue)
|
||||||
|
|
||||||
|
// updated setting
|
||||||
|
updatedSetting := &system.Setting{SettingKey: keyName, SettingValue: "100", Version: newSetting.Version}
|
||||||
|
err = system.SetSetting(updatedSetting)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// get all settings
|
||||||
|
settings, err = system.GetAllSettings()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, settings, 3)
|
||||||
|
assert.EqualValues(t, updatedSetting.SettingValue, settings[strings.ToLower(updatedSetting.SettingKey)].SettingValue)
|
||||||
|
|
||||||
|
// delete setting
|
||||||
|
err = system.DeleteSetting(&system.Setting{SettingKey: strings.ToLower(keyName)})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
settings, err = system.GetAllSettings()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, settings, 2)
|
||||||
|
}
|
|
@ -7,12 +7,12 @@ package unittest
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -91,10 +91,8 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
|
||||||
setting.AppDataPath = appDataPath
|
setting.AppDataPath = appDataPath
|
||||||
setting.AppWorkPath = testOpts.GiteaRootPath
|
setting.AppWorkPath = testOpts.GiteaRootPath
|
||||||
setting.StaticRootPath = testOpts.GiteaRootPath
|
setting.StaticRootPath = testOpts.GiteaRootPath
|
||||||
setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/")
|
setting.GravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
if err != nil {
|
|
||||||
fatalTestError("url.Parse: %v\n", err)
|
|
||||||
}
|
|
||||||
setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments")
|
setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments")
|
||||||
|
|
||||||
setting.LFS.Storage.Path = filepath.Join(setting.AppDataPath, "lfs")
|
setting.LFS.Storage.Path = filepath.Join(setting.AppDataPath, "lfs")
|
||||||
|
@ -112,6 +110,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
|
||||||
if err = storage.Init(); err != nil {
|
if err = storage.Init(); err != nil {
|
||||||
fatalTestError("storage.Init: %v\n", err)
|
fatalTestError("storage.Init: %v\n", err)
|
||||||
}
|
}
|
||||||
|
if err = system_model.Init(); err != nil {
|
||||||
|
fatalTestError("models.Init: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err = util.RemoveAll(repoRootPath); err != nil {
|
if err = util.RemoveAll(repoRootPath); err != nil {
|
||||||
fatalTestError("util.RemoveAll: %v\n", err)
|
fatalTestError("util.RemoveAll: %v\n", err)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/avatars"
|
"code.gitea.io/gitea/models/avatars"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -67,10 +68,16 @@ func (u *User) AvatarLinkWithSize(size int) string {
|
||||||
useLocalAvatar := false
|
useLocalAvatar := false
|
||||||
autoGenerateAvatar := false
|
autoGenerateAvatar := false
|
||||||
|
|
||||||
|
var disableGravatar bool
|
||||||
|
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
|
||||||
|
if disableGravatarSetting != nil {
|
||||||
|
disableGravatar = disableGravatarSetting.GetValueBool()
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case u.UseCustomAvatar:
|
case u.UseCustomAvatar:
|
||||||
useLocalAvatar = true
|
useLocalAvatar = true
|
||||||
case setting.DisableGravatar, setting.OfflineMode:
|
case disableGravatar, setting.OfflineMode:
|
||||||
useLocalAvatar = true
|
useLocalAvatar = true
|
||||||
autoGenerateAvatar = true
|
autoGenerateAvatar = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,34 @@ func init() {
|
||||||
db.RegisterModel(new(Setting))
|
db.RegisterModel(new(Setting))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrUserSettingIsNotExist represents an error that a setting is not exist with special key
|
||||||
|
type ErrUserSettingIsNotExist struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error
|
||||||
|
func (err ErrUserSettingIsNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("Setting[%s] is not exist", err.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUserSettingIsNotExist return true if err is ErrSettingIsNotExist
|
||||||
|
func IsErrUserSettingIsNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrUserSettingIsNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSetting returns specific setting
|
||||||
|
func GetSetting(uid int64, key string) (*Setting, error) {
|
||||||
|
v, err := GetUserSettings(uid, []string{key})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(v) == 0 {
|
||||||
|
return nil, ErrUserSettingIsNotExist{key}
|
||||||
|
}
|
||||||
|
return v[key], nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserSettings returns specific settings from user
|
// GetUserSettings returns specific settings from user
|
||||||
func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) {
|
func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) {
|
||||||
settings := make([]*Setting, 0, len(keys))
|
settings := make([]*Setting, 0, len(keys))
|
||||||
|
|
|
@ -11,8 +11,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -100,6 +102,14 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
|
||||||
assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified)
|
assert.EqualValues(t, []string{"readme.md"}, headCommit.Modified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enableGravatar(t *testing.T) {
|
||||||
|
err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, "false")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
setting.GravatarSource = "https://secure.gravatar.com/avatar"
|
||||||
|
err = system_model.Init()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPushCommits_AvatarLink(t *testing.T) {
|
func TestPushCommits_AvatarLink(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
@ -123,6 +133,8 @@ func TestPushCommits_AvatarLink(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableGravatar(t)
|
||||||
|
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=84",
|
"https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon&s=84",
|
||||||
pushCommits.AvatarLink("user2@example.com"))
|
pushCommits.AvatarLink("user2@example.com"))
|
||||||
|
|
|
@ -4,14 +4,6 @@
|
||||||
|
|
||||||
package setting
|
package setting
|
||||||
|
|
||||||
import (
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
|
|
||||||
"strk.kbt.io/projects/go/libravatar"
|
|
||||||
)
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
var (
|
var (
|
||||||
// Picture settings
|
// Picture settings
|
||||||
|
@ -30,10 +22,8 @@ var (
|
||||||
}
|
}
|
||||||
|
|
||||||
GravatarSource string
|
GravatarSource string
|
||||||
GravatarSourceURL *url.URL
|
DisableGravatar bool // Depreciated: migrated to database
|
||||||
DisableGravatar bool
|
EnableFederatedAvatar bool // Depreciated: migrated to database
|
||||||
EnableFederatedAvatar bool
|
|
||||||
LibravatarService *libravatar.Libravatar
|
|
||||||
|
|
||||||
RepoAvatar = struct {
|
RepoAvatar = struct {
|
||||||
Storage
|
Storage
|
||||||
|
@ -69,38 +59,30 @@ func newPictureService() {
|
||||||
default:
|
default:
|
||||||
GravatarSource = source
|
GravatarSource = source
|
||||||
}
|
}
|
||||||
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
|
|
||||||
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(!InstallLock)
|
|
||||||
if OfflineMode {
|
|
||||||
DisableGravatar = true
|
|
||||||
EnableFederatedAvatar = false
|
|
||||||
}
|
|
||||||
if DisableGravatar {
|
|
||||||
EnableFederatedAvatar = false
|
|
||||||
}
|
|
||||||
if EnableFederatedAvatar || !DisableGravatar {
|
|
||||||
var err error
|
|
||||||
GravatarSourceURL, err = url.Parse(GravatarSource)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to parse Gravatar URL(%s): %v",
|
|
||||||
GravatarSource, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if EnableFederatedAvatar {
|
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar())
|
||||||
LibravatarService = libravatar.New()
|
deprecatedSettingDB("", "DISABLE_GRAVATAR")
|
||||||
if GravatarSourceURL.Scheme == "https" {
|
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar))
|
||||||
LibravatarService.SetUseHTTPS(true)
|
deprecatedSettingDB("", "ENABLE_FEDERATED_AVATAR")
|
||||||
LibravatarService.SetSecureFallbackHost(GravatarSourceURL.Host)
|
|
||||||
} else {
|
|
||||||
LibravatarService.SetUseHTTPS(false)
|
|
||||||
LibravatarService.SetFallbackHost(GravatarSourceURL.Host)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newRepoAvatarService()
|
newRepoAvatarService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDefaultDisableGravatar() bool {
|
||||||
|
return !OfflineMode
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool {
|
||||||
|
v := !InstallLock
|
||||||
|
if OfflineMode {
|
||||||
|
v = false
|
||||||
|
}
|
||||||
|
if disableGravatar {
|
||||||
|
v = false
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func newRepoAvatarService() {
|
func newRepoAvatarService() {
|
||||||
sec := Cfg.Section("picture")
|
sec := Cfg.Section("picture")
|
||||||
|
|
||||||
|
|
|
@ -606,6 +606,13 @@ func deprecatedSetting(oldSection, oldKey, newSection, newKey string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini
|
||||||
|
func deprecatedSettingDB(oldSection, oldKey string) {
|
||||||
|
if Cfg.Section(oldSection).HasKey(oldKey) {
|
||||||
|
log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// loadFromConf initializes configuration context.
|
// loadFromConf initializes configuration context.
|
||||||
// NOTE: do not print any log except error.
|
// NOTE: do not print any log except error.
|
||||||
func loadFromConf(allowEmpty bool, extraConfig string) {
|
func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package appstate
|
package system
|
||||||
|
|
||||||
// StateStore is the interface to get/set app state items
|
// StateStore is the interface to get/set app state items
|
||||||
type StateStore interface {
|
type StateStore interface {
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package appstate
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
|
@ -2,10 +2,10 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package appstate
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models/appstate"
|
"code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
|
||||||
"github.com/yuin/goldmark/util"
|
"github.com/yuin/goldmark/util"
|
||||||
|
@ -16,7 +16,7 @@ type DBStore struct{}
|
||||||
|
|
||||||
// Get reads the state item
|
// Get reads the state item
|
||||||
func (f *DBStore) Get(item StateItem) error {
|
func (f *DBStore) Get(item StateItem) error {
|
||||||
content, err := appstate.GetAppStateContent(item.Name())
|
content, err := system.GetAppStateContent(item.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,5 @@ func (f *DBStore) Set(item StateItem) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return appstate.SaveAppStateContent(item.Name(), util.BytesToReadOnlyString(b))
|
return system.SaveAppStateContent(item.Name(), util.BytesToReadOnlyString(b))
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package appstate
|
package system
|
||||||
|
|
||||||
// RuntimeState contains app state for runtime, and we can save remote version for update checker here in future
|
// RuntimeState contains app state for runtime, and we can save remote version for update checker here in future
|
||||||
type RuntimeState struct {
|
type RuntimeState struct {
|
46
modules/system/setting.go
Normal file
46
modules/system/setting.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2021 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 system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/system"
|
||||||
|
"code.gitea.io/gitea/modules/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genKey(key string) string {
|
||||||
|
return "system.setting." + key
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSetting returns the setting value via the key
|
||||||
|
func GetSetting(key string) (string, error) {
|
||||||
|
return cache.GetString(genKey(key), func() (string, error) {
|
||||||
|
res, err := system.GetSetting(key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return res.SettingValue, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSettingBool return bool value of setting,
|
||||||
|
// none existing keys and errors are ignored and result in false
|
||||||
|
func GetSettingBool(key string) bool {
|
||||||
|
s, _ := GetSetting(key)
|
||||||
|
b, _ := strconv.ParseBool(s)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSetting sets the setting value
|
||||||
|
func SetSetting(key, value string, version int) error {
|
||||||
|
cache.Remove(genKey(key))
|
||||||
|
|
||||||
|
return system.SetSetting(&system.Setting{
|
||||||
|
SettingKey: key,
|
||||||
|
SettingValue: value,
|
||||||
|
Version: version,
|
||||||
|
})
|
||||||
|
}
|
34
modules/system/user_setting.go
Normal file
34
modules/system/user_setting.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2021 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 system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genUserKey(userID int64, key string) string {
|
||||||
|
return fmt.Sprintf("user_%d.setting.%s", userID, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserSetting returns the user setting value via the key
|
||||||
|
func GetUserSetting(userID int64, key string) (string, error) {
|
||||||
|
return cache.GetString(genUserKey(userID, key), func() (string, error) {
|
||||||
|
res, err := user.GetSetting(userID, key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return res.SettingValue, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserSetting sets the user setting value
|
||||||
|
func SetUserSetting(userID int64, key, value string) error {
|
||||||
|
cache.Remove(genUserKey(userID, key))
|
||||||
|
|
||||||
|
return user.SetUserSetting(userID, key, value)
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import (
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"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"
|
||||||
|
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/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/emoji"
|
"code.gitea.io/gitea/modules/emoji"
|
||||||
|
@ -41,6 +42,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/repository"
|
"code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/svg"
|
"code.gitea.io/gitea/modules/svg"
|
||||||
|
system_module "code.gitea.io/gitea/modules/system"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/gitdiff"
|
"code.gitea.io/gitea/services/gitdiff"
|
||||||
|
@ -85,7 +87,7 @@ func NewFuncMap() []template.FuncMap {
|
||||||
return setting.AssetVersion
|
return setting.AssetVersion
|
||||||
},
|
},
|
||||||
"DisableGravatar": func() bool {
|
"DisableGravatar": func() bool {
|
||||||
return setting.DisableGravatar
|
return system_module.GetSettingBool(system_model.KeyPictureDisableGravatar)
|
||||||
},
|
},
|
||||||
"DefaultShowFullName": func() bool {
|
"DefaultShowFullName": func() bool {
|
||||||
return setting.UI.DefaultShowFullName
|
return setting.UI.DefaultShowFullName
|
||||||
|
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/appstate"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/proxy"
|
"code.gitea.io/gitea/modules/proxy"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/system"
|
||||||
|
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
)
|
)
|
||||||
|
@ -64,13 +64,13 @@ func GiteaUpdateChecker(httpEndpoint string) error {
|
||||||
|
|
||||||
// UpdateRemoteVersion updates the latest available version of Gitea
|
// UpdateRemoteVersion updates the latest available version of Gitea
|
||||||
func UpdateRemoteVersion(version string) (err error) {
|
func UpdateRemoteVersion(version string) (err error) {
|
||||||
return appstate.AppState.Set(&CheckerState{LatestVersion: version})
|
return system.AppState.Set(&CheckerState{LatestVersion: version})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemoteVersion returns the current remote version (or currently installed version if fail to fetch from DB)
|
// GetRemoteVersion returns the current remote version (or currently installed version if fail to fetch from DB)
|
||||||
func GetRemoteVersion() string {
|
func GetRemoteVersion() string {
|
||||||
item := new(CheckerState)
|
item := new(CheckerState)
|
||||||
if err := appstate.AppState.Get(item); err != nil {
|
if err := system.AppState.Get(item); err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return item.LatestVersion
|
return item.LatestVersion
|
||||||
|
|
|
@ -2879,6 +2879,9 @@ config.access_log_template = Template
|
||||||
config.xorm_log_mode = XORM Log Mode
|
config.xorm_log_mode = XORM Log Mode
|
||||||
config.xorm_log_sql = Log SQL
|
config.xorm_log_sql = Log SQL
|
||||||
|
|
||||||
|
config.get_setting_failed = Get setting %s failed
|
||||||
|
config.set_setting_failed = Set setting %s failed
|
||||||
|
|
||||||
monitor.cron = Cron Tasks
|
monitor.cron = Cron Tasks
|
||||||
monitor.name = Name
|
monitor.name = Name
|
||||||
monitor.schedule = Schedule
|
monitor.schedule = Schedule
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/modules/appstate"
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/eventsource"
|
"code.gitea.io/gitea/modules/eventsource"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -27,6 +26,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/ssh"
|
"code.gitea.io/gitea/modules/ssh"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/svg"
|
"code.gitea.io/gitea/modules/svg"
|
||||||
|
"code.gitea.io/gitea/modules/system"
|
||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
@ -76,8 +76,8 @@ func InitGitServices() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncAppPathForGit(ctx context.Context) error {
|
func syncAppPathForGit(ctx context.Context) error {
|
||||||
runtimeState := new(appstate.RuntimeState)
|
runtimeState := new(system.RuntimeState)
|
||||||
if err := appstate.AppState.Get(runtimeState); err != nil {
|
if err := system.AppState.Get(runtimeState); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if runtimeState.LastAppPath != setting.AppPath {
|
if runtimeState.LastAppPath != setting.AppPath {
|
||||||
|
@ -90,7 +90,7 @@ func syncAppPathForGit(ctx context.Context) error {
|
||||||
mustInit(asymkey_model.RewriteAllPublicKeys)
|
mustInit(asymkey_model.RewriteAllPublicKeys)
|
||||||
|
|
||||||
runtimeState.LastAppPath = setting.AppPath
|
runtimeState.LastAppPath = setting.AppPath
|
||||||
return appstate.AppState.Set(runtimeState)
|
return system.AppState.Set(runtimeState)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -133,10 +133,10 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||||
|
|
||||||
mustInitCtx(ctx, common.InitDBEngine)
|
mustInitCtx(ctx, common.InitDBEngine)
|
||||||
log.Info("ORM engine initialization successful!")
|
log.Info("ORM engine initialization successful!")
|
||||||
mustInit(appstate.Init)
|
mustInit(system.Init)
|
||||||
mustInit(oauth2.Init)
|
mustInit(oauth2.Init)
|
||||||
|
|
||||||
models.NewRepoContext()
|
mustInit(models.Init)
|
||||||
mustInit(repo_service.Init)
|
mustInit(repo_service.Init)
|
||||||
|
|
||||||
// Booting long running goroutines.
|
// Booting long running goroutines.
|
||||||
|
|
|
@ -12,12 +12,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
|
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/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
@ -147,8 +149,19 @@ func Install(ctx *context.Context) {
|
||||||
|
|
||||||
// Server and other services settings
|
// Server and other services settings
|
||||||
form.OfflineMode = setting.OfflineMode
|
form.OfflineMode = setting.OfflineMode
|
||||||
form.DisableGravatar = setting.DisableGravatar
|
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
|
||||||
form.EnableFederatedAvatar = setting.EnableFederatedAvatar
|
if disableGravatarSetting != nil {
|
||||||
|
form.DisableGravatar = disableGravatarSetting.GetValueBool()
|
||||||
|
} else {
|
||||||
|
form.DisableGravatar = false
|
||||||
|
}
|
||||||
|
|
||||||
|
enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
|
||||||
|
if enableFederatedAvatarSetting != nil {
|
||||||
|
form.EnableFederatedAvatar = enableFederatedAvatarSetting.GetValueBool()
|
||||||
|
} else {
|
||||||
|
form.EnableFederatedAvatar = false
|
||||||
|
}
|
||||||
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
|
||||||
|
@ -439,7 +452,11 @@ func SubmitInstall(ctx *context.Context) {
|
||||||
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(fmt.Sprint(form.MailNotify))
|
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(fmt.Sprint(form.MailNotify))
|
||||||
|
|
||||||
cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode))
|
cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode))
|
||||||
cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(fmt.Sprint(form.DisableGravatar))
|
// if you are reinstalling, this maybe not right because of missing version
|
||||||
|
if err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, strconv.FormatBool(form.DisableGravatar)); err != nil {
|
||||||
|
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
|
||||||
|
return
|
||||||
|
}
|
||||||
cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(fmt.Sprint(form.EnableFederatedAvatar))
|
cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(fmt.Sprint(form.EnableFederatedAvatar))
|
||||||
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(fmt.Sprint(form.EnableOpenIDSignIn))
|
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(fmt.Sprint(form.EnableOpenIDSignIn))
|
||||||
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(fmt.Sprint(form.EnableOpenIDSignUp))
|
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(fmt.Sprint(form.EnableOpenIDSignUp))
|
||||||
|
|
|
@ -8,18 +8,13 @@ package admin
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
|
||||||
"code.gitea.io/gitea/modules/json"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
"code.gitea.io/gitea/modules/queue"
|
"code.gitea.io/gitea/modules/queue"
|
||||||
|
@ -27,18 +22,13 @@ import (
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/modules/updatechecker"
|
"code.gitea.io/gitea/modules/updatechecker"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/services/cron"
|
"code.gitea.io/gitea/services/cron"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
"code.gitea.io/gitea/services/mailer"
|
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tplDashboard base.TplName = "admin/dashboard"
|
tplDashboard base.TplName = "admin/dashboard"
|
||||||
tplConfig base.TplName = "admin/config"
|
|
||||||
tplMonitor base.TplName = "admin/monitor"
|
tplMonitor base.TplName = "admin/monitor"
|
||||||
tplStacktrace base.TplName = "admin/stacktrace"
|
tplStacktrace base.TplName = "admin/stacktrace"
|
||||||
tplQueue base.TplName = "admin/queue"
|
tplQueue base.TplName = "admin/queue"
|
||||||
|
@ -165,165 +155,6 @@ func DashboardPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTestMail send test mail to confirm mail service is OK
|
|
||||||
func SendTestMail(ctx *context.Context) {
|
|
||||||
email := ctx.FormString("email")
|
|
||||||
// Send a test email to the user's email address and redirect back to Config
|
|
||||||
if err := mailer.SendTestMail(email); err != nil {
|
|
||||||
ctx.Flash.Error(ctx.Tr("admin.config.test_mail_failed", email, err))
|
|
||||||
} else {
|
|
||||||
ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Redirect(setting.AppSubURL + "/admin/config")
|
|
||||||
}
|
|
||||||
|
|
||||||
func shadowPasswordKV(cfgItem, splitter string) string {
|
|
||||||
fields := strings.Split(cfgItem, splitter)
|
|
||||||
for i := 0; i < len(fields); i++ {
|
|
||||||
if strings.HasPrefix(fields[i], "password=") {
|
|
||||||
fields[i] = "password=******"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(fields, splitter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func shadowURL(provider, cfgItem string) string {
|
|
||||||
u, err := url.Parse(cfgItem)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Shadowing Password for %v failed: %v", provider, err)
|
|
||||||
return cfgItem
|
|
||||||
}
|
|
||||||
if u.User != nil {
|
|
||||||
atIdx := strings.Index(cfgItem, "@")
|
|
||||||
if atIdx > 0 {
|
|
||||||
colonIdx := strings.LastIndex(cfgItem[:atIdx], ":")
|
|
||||||
if colonIdx > 0 {
|
|
||||||
return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cfgItem
|
|
||||||
}
|
|
||||||
|
|
||||||
func shadowPassword(provider, cfgItem string) string {
|
|
||||||
switch provider {
|
|
||||||
case "redis":
|
|
||||||
return shadowPasswordKV(cfgItem, ",")
|
|
||||||
case "mysql":
|
|
||||||
// root:@tcp(localhost:3306)/macaron?charset=utf8
|
|
||||||
atIdx := strings.Index(cfgItem, "@")
|
|
||||||
if atIdx > 0 {
|
|
||||||
colonIdx := strings.Index(cfgItem[:atIdx], ":")
|
|
||||||
if colonIdx > 0 {
|
|
||||||
return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cfgItem
|
|
||||||
case "postgres":
|
|
||||||
// user=jiahuachen dbname=macaron port=5432 sslmode=disable
|
|
||||||
if !strings.HasPrefix(cfgItem, "postgres://") {
|
|
||||||
return shadowPasswordKV(cfgItem, " ")
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case "couchbase":
|
|
||||||
return shadowURL(provider, cfgItem)
|
|
||||||
// postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full
|
|
||||||
// Notice: use shadowURL
|
|
||||||
}
|
|
||||||
return cfgItem
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config show admin config page
|
|
||||||
func Config(ctx *context.Context) {
|
|
||||||
ctx.Data["Title"] = ctx.Tr("admin.config")
|
|
||||||
ctx.Data["PageIsAdmin"] = true
|
|
||||||
ctx.Data["PageIsAdminConfig"] = true
|
|
||||||
|
|
||||||
ctx.Data["CustomConf"] = setting.CustomConf
|
|
||||||
ctx.Data["AppUrl"] = setting.AppURL
|
|
||||||
ctx.Data["Domain"] = setting.Domain
|
|
||||||
ctx.Data["OfflineMode"] = setting.OfflineMode
|
|
||||||
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
|
||||||
ctx.Data["RunUser"] = setting.RunUser
|
|
||||||
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
|
|
||||||
ctx.Data["GitVersion"] = git.VersionInfo()
|
|
||||||
|
|
||||||
ctx.Data["RepoRootPath"] = setting.RepoRootPath
|
|
||||||
ctx.Data["CustomRootPath"] = setting.CustomPath
|
|
||||||
ctx.Data["StaticRootPath"] = setting.StaticRootPath
|
|
||||||
ctx.Data["LogRootPath"] = setting.LogRootPath
|
|
||||||
ctx.Data["ScriptType"] = setting.ScriptType
|
|
||||||
ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
|
|
||||||
ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail
|
|
||||||
ctx.Data["ReverseProxyAuthFullName"] = setting.ReverseProxyAuthFullName
|
|
||||||
|
|
||||||
ctx.Data["SSH"] = setting.SSH
|
|
||||||
ctx.Data["LFS"] = setting.LFS
|
|
||||||
|
|
||||||
ctx.Data["Service"] = setting.Service
|
|
||||||
ctx.Data["DbCfg"] = setting.Database
|
|
||||||
ctx.Data["Webhook"] = setting.Webhook
|
|
||||||
|
|
||||||
ctx.Data["MailerEnabled"] = false
|
|
||||||
if setting.MailService != nil {
|
|
||||||
ctx.Data["MailerEnabled"] = true
|
|
||||||
ctx.Data["Mailer"] = setting.MailService
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["CacheAdapter"] = setting.CacheService.Adapter
|
|
||||||
ctx.Data["CacheInterval"] = setting.CacheService.Interval
|
|
||||||
|
|
||||||
ctx.Data["CacheConn"] = shadowPassword(setting.CacheService.Adapter, setting.CacheService.Conn)
|
|
||||||
ctx.Data["CacheItemTTL"] = setting.CacheService.TTL
|
|
||||||
|
|
||||||
sessionCfg := setting.SessionConfig
|
|
||||||
if sessionCfg.Provider == "VirtualSession" {
|
|
||||||
var realSession session.Options
|
|
||||||
if err := json.Unmarshal([]byte(sessionCfg.ProviderConfig), &realSession); err != nil {
|
|
||||||
log.Error("Unable to unmarshall session config for virtualed provider config: %s\nError: %v", sessionCfg.ProviderConfig, err)
|
|
||||||
}
|
|
||||||
sessionCfg.Provider = realSession.Provider
|
|
||||||
sessionCfg.ProviderConfig = realSession.ProviderConfig
|
|
||||||
sessionCfg.CookieName = realSession.CookieName
|
|
||||||
sessionCfg.CookiePath = realSession.CookiePath
|
|
||||||
sessionCfg.Gclifetime = realSession.Gclifetime
|
|
||||||
sessionCfg.Maxlifetime = realSession.Maxlifetime
|
|
||||||
sessionCfg.Secure = realSession.Secure
|
|
||||||
sessionCfg.Domain = realSession.Domain
|
|
||||||
}
|
|
||||||
sessionCfg.ProviderConfig = shadowPassword(sessionCfg.Provider, sessionCfg.ProviderConfig)
|
|
||||||
ctx.Data["SessionConfig"] = sessionCfg
|
|
||||||
|
|
||||||
ctx.Data["DisableGravatar"] = setting.DisableGravatar
|
|
||||||
ctx.Data["EnableFederatedAvatar"] = setting.EnableFederatedAvatar
|
|
||||||
|
|
||||||
ctx.Data["Git"] = setting.Git
|
|
||||||
|
|
||||||
type envVar struct {
|
|
||||||
Name, Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
envVars := map[string]*envVar{}
|
|
||||||
if len(os.Getenv("GITEA_WORK_DIR")) > 0 {
|
|
||||||
envVars["GITEA_WORK_DIR"] = &envVar{"GITEA_WORK_DIR", os.Getenv("GITEA_WORK_DIR")}
|
|
||||||
}
|
|
||||||
if len(os.Getenv("GITEA_CUSTOM")) > 0 {
|
|
||||||
envVars["GITEA_CUSTOM"] = &envVar{"GITEA_CUSTOM", os.Getenv("GITEA_CUSTOM")}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["EnvVars"] = envVars
|
|
||||||
ctx.Data["Loggers"] = setting.GetLogDescriptions()
|
|
||||||
ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
|
|
||||||
ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
|
|
||||||
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
|
||||||
ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
|
|
||||||
ctx.Data["LogSQL"] = setting.Database.LogSQL
|
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor show admin monitor page
|
// Monitor show admin monitor page
|
||||||
func Monitor(ctx *context.Context) {
|
func Monitor(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("admin.monitor")
|
ctx.Data["Title"] = ctx.Tr("admin.monitor")
|
||||||
|
|
217
routers/web/admin/config.go
Normal file
217
routers/web/admin/config.go
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// 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 admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
system_module "code.gitea.io/gitea/modules/system"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"code.gitea.io/gitea/services/mailer"
|
||||||
|
|
||||||
|
"gitea.com/go-chi/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
const tplConfig base.TplName = "admin/config"
|
||||||
|
|
||||||
|
// SendTestMail send test mail to confirm mail service is OK
|
||||||
|
func SendTestMail(ctx *context.Context) {
|
||||||
|
email := ctx.FormString("email")
|
||||||
|
// Send a test email to the user's email address and redirect back to Config
|
||||||
|
if err := mailer.SendTestMail(email); err != nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("admin.config.test_mail_failed", email, err))
|
||||||
|
} else {
|
||||||
|
ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Redirect(setting.AppSubURL + "/admin/config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadowPasswordKV(cfgItem, splitter string) string {
|
||||||
|
fields := strings.Split(cfgItem, splitter)
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
if strings.HasPrefix(fields[i], "password=") {
|
||||||
|
fields[i] = "password=******"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(fields, splitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadowURL(provider, cfgItem string) string {
|
||||||
|
u, err := url.Parse(cfgItem)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Shadowing Password for %v failed: %v", provider, err)
|
||||||
|
return cfgItem
|
||||||
|
}
|
||||||
|
if u.User != nil {
|
||||||
|
atIdx := strings.Index(cfgItem, "@")
|
||||||
|
if atIdx > 0 {
|
||||||
|
colonIdx := strings.LastIndex(cfgItem[:atIdx], ":")
|
||||||
|
if colonIdx > 0 {
|
||||||
|
return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfgItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadowPassword(provider, cfgItem string) string {
|
||||||
|
switch provider {
|
||||||
|
case "redis":
|
||||||
|
return shadowPasswordKV(cfgItem, ",")
|
||||||
|
case "mysql":
|
||||||
|
// root:@tcp(localhost:3306)/macaron?charset=utf8
|
||||||
|
atIdx := strings.Index(cfgItem, "@")
|
||||||
|
if atIdx > 0 {
|
||||||
|
colonIdx := strings.Index(cfgItem[:atIdx], ":")
|
||||||
|
if colonIdx > 0 {
|
||||||
|
return cfgItem[:colonIdx+1] + "******" + cfgItem[atIdx:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfgItem
|
||||||
|
case "postgres":
|
||||||
|
// user=jiahuachen dbname=macaron port=5432 sslmode=disable
|
||||||
|
if !strings.HasPrefix(cfgItem, "postgres://") {
|
||||||
|
return shadowPasswordKV(cfgItem, " ")
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case "couchbase":
|
||||||
|
return shadowURL(provider, cfgItem)
|
||||||
|
// postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full
|
||||||
|
// Notice: use shadowURL
|
||||||
|
}
|
||||||
|
return cfgItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config show admin config page
|
||||||
|
func Config(ctx *context.Context) {
|
||||||
|
ctx.Data["Title"] = ctx.Tr("admin.config")
|
||||||
|
ctx.Data["PageIsAdmin"] = true
|
||||||
|
ctx.Data["PageIsAdminConfig"] = true
|
||||||
|
|
||||||
|
systemSettings, err := system_model.GetAllSettings()
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("system_model.GetAllSettings", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// All editable settings from UI
|
||||||
|
ctx.Data["SystemSettings"] = systemSettings
|
||||||
|
ctx.PageData["adminConfigPage"] = true
|
||||||
|
|
||||||
|
ctx.Data["CustomConf"] = setting.CustomConf
|
||||||
|
ctx.Data["AppUrl"] = setting.AppURL
|
||||||
|
ctx.Data["Domain"] = setting.Domain
|
||||||
|
ctx.Data["OfflineMode"] = setting.OfflineMode
|
||||||
|
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
||||||
|
ctx.Data["RunUser"] = setting.RunUser
|
||||||
|
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
|
||||||
|
ctx.Data["GitVersion"] = git.VersionInfo()
|
||||||
|
|
||||||
|
ctx.Data["RepoRootPath"] = setting.RepoRootPath
|
||||||
|
ctx.Data["CustomRootPath"] = setting.CustomPath
|
||||||
|
ctx.Data["StaticRootPath"] = setting.StaticRootPath
|
||||||
|
ctx.Data["LogRootPath"] = setting.LogRootPath
|
||||||
|
ctx.Data["ScriptType"] = setting.ScriptType
|
||||||
|
ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
|
||||||
|
ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail
|
||||||
|
|
||||||
|
ctx.Data["SSH"] = setting.SSH
|
||||||
|
ctx.Data["LFS"] = setting.LFS
|
||||||
|
|
||||||
|
ctx.Data["Service"] = setting.Service
|
||||||
|
ctx.Data["DbCfg"] = setting.Database
|
||||||
|
ctx.Data["Webhook"] = setting.Webhook
|
||||||
|
|
||||||
|
ctx.Data["MailerEnabled"] = false
|
||||||
|
if setting.MailService != nil {
|
||||||
|
ctx.Data["MailerEnabled"] = true
|
||||||
|
ctx.Data["Mailer"] = setting.MailService
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["CacheAdapter"] = setting.CacheService.Adapter
|
||||||
|
ctx.Data["CacheInterval"] = setting.CacheService.Interval
|
||||||
|
|
||||||
|
ctx.Data["CacheConn"] = shadowPassword(setting.CacheService.Adapter, setting.CacheService.Conn)
|
||||||
|
ctx.Data["CacheItemTTL"] = setting.CacheService.TTL
|
||||||
|
|
||||||
|
sessionCfg := setting.SessionConfig
|
||||||
|
if sessionCfg.Provider == "VirtualSession" {
|
||||||
|
var realSession session.Options
|
||||||
|
if err := json.Unmarshal([]byte(sessionCfg.ProviderConfig), &realSession); err != nil {
|
||||||
|
log.Error("Unable to unmarshall session config for virtual provider config: %s\nError: %v", sessionCfg.ProviderConfig, err)
|
||||||
|
}
|
||||||
|
sessionCfg.Provider = realSession.Provider
|
||||||
|
sessionCfg.ProviderConfig = realSession.ProviderConfig
|
||||||
|
sessionCfg.CookieName = realSession.CookieName
|
||||||
|
sessionCfg.CookiePath = realSession.CookiePath
|
||||||
|
sessionCfg.Gclifetime = realSession.Gclifetime
|
||||||
|
sessionCfg.Maxlifetime = realSession.Maxlifetime
|
||||||
|
sessionCfg.Secure = realSession.Secure
|
||||||
|
sessionCfg.Domain = realSession.Domain
|
||||||
|
}
|
||||||
|
sessionCfg.ProviderConfig = shadowPassword(sessionCfg.Provider, sessionCfg.ProviderConfig)
|
||||||
|
ctx.Data["SessionConfig"] = sessionCfg
|
||||||
|
|
||||||
|
ctx.Data["Git"] = setting.Git
|
||||||
|
|
||||||
|
type envVar struct {
|
||||||
|
Name, Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
envVars := map[string]*envVar{}
|
||||||
|
if len(os.Getenv("GITEA_WORK_DIR")) > 0 {
|
||||||
|
envVars["GITEA_WORK_DIR"] = &envVar{"GITEA_WORK_DIR", os.Getenv("GITEA_WORK_DIR")}
|
||||||
|
}
|
||||||
|
if len(os.Getenv("GITEA_CUSTOM")) > 0 {
|
||||||
|
envVars["GITEA_CUSTOM"] = &envVar{"GITEA_CUSTOM", os.Getenv("GITEA_CUSTOM")}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["EnvVars"] = envVars
|
||||||
|
ctx.Data["Loggers"] = setting.GetLogDescriptions()
|
||||||
|
ctx.Data["EnableAccessLog"] = setting.EnableAccessLog
|
||||||
|
ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
|
||||||
|
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
||||||
|
ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
|
||||||
|
ctx.Data["LogSQL"] = setting.Database.LogSQL
|
||||||
|
|
||||||
|
ctx.HTML(http.StatusOK, tplConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChangeConfig(ctx *context.Context) {
|
||||||
|
key := strings.TrimSpace(ctx.FormString("key"))
|
||||||
|
if key == "" {
|
||||||
|
ctx.JSON(http.StatusOK, map[string]string{
|
||||||
|
"redirect": ctx.Req.URL.String(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value := ctx.FormString("value")
|
||||||
|
version := ctx.FormInt("version")
|
||||||
|
|
||||||
|
if err := system_module.SetSetting(key, value, version); err != nil {
|
||||||
|
log.Error("set setting failed: %v", err)
|
||||||
|
ctx.JSON(http.StatusOK, map[string]string{
|
||||||
|
"err": ctx.Tr("admin.config.set_setting_failed", key),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||||
|
"version": version + 1,
|
||||||
|
})
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -26,13 +26,13 @@ func Notices(ctx *context.Context) {
|
||||||
ctx.Data["PageIsAdmin"] = true
|
ctx.Data["PageIsAdmin"] = true
|
||||||
ctx.Data["PageIsAdminNotices"] = true
|
ctx.Data["PageIsAdminNotices"] = true
|
||||||
|
|
||||||
total := admin_model.CountNotices()
|
total := system_model.CountNotices()
|
||||||
page := ctx.FormInt("page")
|
page := ctx.FormInt("page")
|
||||||
if page <= 1 {
|
if page <= 1 {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
notices, err := admin_model.Notices(page, setting.UI.Admin.NoticePagingNum)
|
notices, err := system_model.Notices(page, setting.UI.Admin.NoticePagingNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Notices", err)
|
ctx.ServerError("Notices", err)
|
||||||
return
|
return
|
||||||
|
@ -57,7 +57,7 @@ func DeleteNotices(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := admin_model.DeleteNoticesByIDs(ids); err != nil {
|
if err := system_model.DeleteNoticesByIDs(ids); err != nil {
|
||||||
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
|
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
|
||||||
ctx.Status(http.StatusInternalServerError)
|
ctx.Status(http.StatusInternalServerError)
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,7 +68,7 @@ func DeleteNotices(ctx *context.Context) {
|
||||||
|
|
||||||
// EmptyNotices delete all the notices
|
// EmptyNotices delete all the notices
|
||||||
func EmptyNotices(ctx *context.Context) {
|
func EmptyNotices(ctx *context.Context) {
|
||||||
if err := admin_model.DeleteNotices(0, 0); err != nil {
|
if err := system_model.DeleteNotices(0, 0); err != nil {
|
||||||
ctx.ServerError("DeleteNotices", err)
|
ctx.ServerError("DeleteNotices", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
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/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -24,7 +24,7 @@ func SetEditorconfigIfExists(ctx *context.Context) {
|
||||||
|
|
||||||
if err != nil && !git.IsErrNotExist(err) {
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
description := fmt.Sprintf("Error while getting .editorconfig file: %v", err)
|
description := fmt.Sprintf("Error while getting .editorconfig file: %v", err)
|
||||||
if err := admin_model.CreateRepositoryNotice(description); err != nil {
|
if err := system_model.CreateRepositoryNotice(description); err != nil {
|
||||||
ctx.ServerError("ErrCreatingReporitoryNotice", err)
|
ctx.ServerError("ErrCreatingReporitoryNotice", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -473,8 +473,13 @@ func RegisterRoutes(m *web.Route) {
|
||||||
m.Group("/admin", func() {
|
m.Group("/admin", func() {
|
||||||
m.Get("", adminReq, admin.Dashboard)
|
m.Get("", adminReq, admin.Dashboard)
|
||||||
m.Post("", adminReq, bindIgnErr(forms.AdminDashboardForm{}), admin.DashboardPost)
|
m.Post("", adminReq, bindIgnErr(forms.AdminDashboardForm{}), admin.DashboardPost)
|
||||||
m.Get("/config", admin.Config)
|
|
||||||
m.Post("/config/test_mail", admin.SendTestMail)
|
m.Group("/config", func() {
|
||||||
|
m.Get("", admin.Config)
|
||||||
|
m.Post("", admin.ChangeConfig)
|
||||||
|
m.Post("/test_mail", admin.SendTestMail)
|
||||||
|
})
|
||||||
|
|
||||||
m.Group("/monitor", func() {
|
m.Group("/monitor", func() {
|
||||||
m.Get("", admin.Monitor)
|
m.Get("", admin.Monitor)
|
||||||
m.Get("/stacktrace", admin.GoroutineStacktrace)
|
m.Get("/stacktrace", admin.GoroutineStacktrace)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
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/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -114,7 +114,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
||||||
t.LastDoer = doerName
|
t.LastDoer = doerName
|
||||||
t.lock.Unlock()
|
t.lock.Unlock()
|
||||||
|
|
||||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "cancelled", doerName, message)); err != nil {
|
if err := system_model.CreateNotice(ctx, system_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "cancelled", doerName, message)); err != nil {
|
||||||
log.Error("CreateNotice: %v", err)
|
log.Error("CreateNotice: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -127,7 +127,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
||||||
t.lock.Unlock()
|
t.lock.Unlock()
|
||||||
|
|
||||||
if config.DoNoticeOnSuccess() {
|
if config.DoNoticeOnSuccess() {
|
||||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "finished", doerName)); err != nil {
|
if err := system_model.CreateNotice(ctx, system_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "finished", doerName)); err != nil {
|
||||||
log.Error("CreateNotice: %v", err)
|
log.Error("CreateNotice: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
"code.gitea.io/gitea/models/admin"
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"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/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/updatechecker"
|
"code.gitea.io/gitea/modules/updatechecker"
|
||||||
|
@ -166,7 +166,7 @@ func registerDeleteOldSystemNotices() {
|
||||||
OlderThan: 365 * 24 * time.Hour,
|
OlderThan: 365 * 24 * time.Hour,
|
||||||
}, func(ctx context.Context, _ *user_model.User, config Config) error {
|
}, func(ctx context.Context, _ *user_model.User, config Config) error {
|
||||||
olderThanConfig := config.(*OlderThanConfig)
|
olderThanConfig := config.(*OlderThanConfig)
|
||||||
return admin.DeleteOldSystemNotices(olderThanConfig.OlderThan)
|
return system.DeleteOldSystemNotices(olderThanConfig.OlderThan)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"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"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
project_model "code.gitea.io/gitea/models/project"
|
project_model "code.gitea.io/gitea/models/project"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
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/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
|
@ -234,7 +234,7 @@ func deleteIssue(issue *issues_model.Issue) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range issue.Attachments {
|
for i := range issue.Attachments {
|
||||||
admin_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", issue.Attachments[i].RelativePath())
|
system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", issue.Attachments[i].RelativePath())
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all database data still assigned to this issue
|
// delete all database data still assigned to this issue
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
base "code.gitea.io/gitea/modules/migration"
|
base "code.gitea.io/gitea/modules/migration"
|
||||||
|
@ -17,7 +17,7 @@ import (
|
||||||
// WarnAndNotice will log the provided message and send a repository notice
|
// WarnAndNotice will log the provided message and send a repository notice
|
||||||
func WarnAndNotice(fmtStr string, args ...interface{}) {
|
func WarnAndNotice(fmtStr string, args ...interface{}) {
|
||||||
log.Warn(fmtStr, args...)
|
log.Warn(fmtStr, args...)
|
||||||
if err := admin_model.CreateRepositoryNotice(fmt.Sprintf(fmtStr, args...)); err != nil {
|
if err := system_model.CreateRepositoryNotice(fmt.Sprintf(fmtStr, args...)); err != nil {
|
||||||
log.Error("create repository notice failed: ", err)
|
log.Error("create repository notice failed: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
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/hostmatcher"
|
"code.gitea.io/gitea/modules/hostmatcher"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -132,7 +132,7 @@ func MigrateRepository(ctx context.Context, doer *user_model.User, ownerName str
|
||||||
if err1 := uploader.Rollback(); err1 != nil {
|
if err1 := uploader.Rollback(); err1 != nil {
|
||||||
log.Error("rollback failed: %v", err1)
|
log.Error("rollback failed: %v", err1)
|
||||||
}
|
}
|
||||||
if err2 := admin_model.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.OriginalURL, err)); err2 != nil {
|
if err2 := system_model.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.OriginalURL, err)); err2 != nil {
|
||||||
log.Error("create respotiry notice failed: ", err2)
|
log.Error("create respotiry notice failed: ", err2)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"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"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
|
@ -188,7 +188,7 @@ func pruneBrokenReferences(ctx context.Context,
|
||||||
|
|
||||||
log.Error("Failed to prune mirror repository %s%-v references:\nStdout: %s\nStderr: %s\nErr: %v", wiki, m.Repo, stdoutMessage, stderrMessage, pruneErr)
|
log.Error("Failed to prune mirror repository %s%-v references:\nStdout: %s\nStderr: %s\nErr: %v", wiki, m.Repo, stdoutMessage, stderrMessage, pruneErr)
|
||||||
desc := fmt.Sprintf("Failed to prune mirror repository %s'%s' references: %s", wiki, repoPath, stderrMessage)
|
desc := fmt.Sprintf("Failed to prune mirror repository %s'%s' references: %s", wiki, repoPath, stderrMessage)
|
||||||
if err := admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err := system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
// this if will only be reached on a successful prune so try to get the mirror again
|
// this if will only be reached on a successful prune so try to get the mirror again
|
||||||
|
@ -267,7 +267,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
log.Error("SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||||
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage)
|
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -356,7 +356,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
log.Error("SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||||
desc := fmt.Sprintf("Failed to update mirror repository wiki '%s': %s", wikiPath, stderrMessage)
|
desc := fmt.Sprintf("Failed to update mirror repository wiki '%s': %s", wikiPath, stderrMessage)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -568,7 +568,7 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository
|
||||||
if !git.IsErrUnsupportedVersion(err) {
|
if !git.IsErrUnsupportedVersion(err) {
|
||||||
log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err)
|
log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err)
|
||||||
desc := fmt.Sprintf("Failed to uupdate default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err)
|
desc := fmt.Sprintf("Failed to uupdate default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -579,7 +579,7 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository
|
||||||
if err := repo_model.UpdateRepositoryCols(db.DefaultContext, m.Repo, "default_branch", "is_empty"); err != nil {
|
if err := repo_model.UpdateRepositoryCols(db.DefaultContext, m.Repo, "default_branch", "is_empty"); err != nil {
|
||||||
log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err)
|
log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err)
|
||||||
desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err)
|
desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"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"
|
||||||
|
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/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -42,7 +42,7 @@ func GitFsck(ctx context.Context, timeout time.Duration, args []string) error {
|
||||||
repoPath := repo.RepoPath()
|
repoPath := repo.RepoPath()
|
||||||
if err := git.Fsck(ctx, repoPath, timeout, args...); err != nil {
|
if err := git.Fsck(ctx, repoPath, timeout, args...); err != nil {
|
||||||
log.Warn("Failed to health check repository (%v): %v", repo, err)
|
log.Warn("Failed to health check repository (%v): %v", repo, err)
|
||||||
if err = admin_model.CreateRepositoryNotice("Failed to health check repository (%s): %v", repo.FullName(), err); err != nil {
|
if err = system_model.CreateRepositoryNotice("Failed to health check repository (%s): %v", repo.FullName(), err); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
|
log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
|
||||||
desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
|
desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
|
return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
|
||||||
|
@ -93,7 +93,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) erro
|
||||||
if err := repo_module.UpdateRepoSize(ctx, repo); err != nil {
|
if err := repo_module.UpdateRepoSize(ctx, repo); err != nil {
|
||||||
log.Error("Updating size as part of garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
|
log.Error("Updating size as part of garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)
|
||||||
desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
|
desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = system_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
|
return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %v", repo.FullName(), err)
|
||||||
|
@ -135,7 +135,7 @@ func gatherMissingRepoRecords(ctx context.Context) ([]*repo_model.Repository, er
|
||||||
if strings.HasPrefix(err.Error(), "Aborted gathering missing repo") {
|
if strings.HasPrefix(err.Error(), "Aborted gathering missing repo") {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err2 := admin_model.CreateRepositoryNotice("gatherMissingRepoRecords: %v", err); err2 != nil {
|
if err2 := system_model.CreateRepositoryNotice("gatherMissingRepoRecords: %v", err); err2 != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err2)
|
log.Error("CreateRepositoryNotice: %v", err2)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -163,7 +163,7 @@ func DeleteMissingRepositories(ctx context.Context, doer *user_model.User) error
|
||||||
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
|
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
|
||||||
if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
|
if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
|
||||||
log.Error("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err)
|
log.Error("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err)
|
||||||
if err2 := admin_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil {
|
if err2 := system_model.CreateRepositoryNotice("Failed to DeleteRepository %s [%d]: Error: %v", repo.FullName(), repo.ID, err); err2 != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err)
|
log.Error("CreateRepositoryNotice: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
|
||||||
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
|
||||||
if err := git.InitRepository(ctx, repo.RepoPath(), true); err != nil {
|
if err := git.InitRepository(ctx, repo.RepoPath(), true); err != nil {
|
||||||
log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
|
log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
|
||||||
if err2 := admin_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
|
if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
|
||||||
log.Error("CreateRepositoryNotice: %v", err2)
|
log.Error("CreateRepositoryNotice: %v", err2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
"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"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -83,8 +83,8 @@ func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_mo
|
||||||
// Init start repository service
|
// Init start repository service
|
||||||
func Init() error {
|
func Init() error {
|
||||||
repo_module.LoadRepoConfig()
|
repo_module.LoadRepoConfig()
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repository uploads", setting.Repository.Upload.TempPath)
|
system_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repository uploads", setting.Repository.Upload.TempPath)
|
||||||
admin_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repositories", repo_module.LocalCopyPath())
|
system_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repositories", repo_module.LocalCopyPath())
|
||||||
return initPushQueue()
|
return initPushQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
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/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
"code.gitea.io/gitea/modules/eventsource"
|
"code.gitea.io/gitea/modules/eventsource"
|
||||||
|
@ -186,7 +186,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
|
||||||
path := user_model.UserPath(u.Name)
|
path := user_model.UserPath(u.Name)
|
||||||
if err := util.RemoveAll(path); err != nil {
|
if err := util.RemoveAll(path); err != nil {
|
||||||
err = fmt.Errorf("Failed to RemoveAll %s: %v", path, err)
|
err = fmt.Errorf("Failed to RemoveAll %s: %v", path, err)
|
||||||
_ = admin_model.CreateNotice(ctx, admin_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err))
|
_ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
|
||||||
avatarPath := u.CustomAvatarRelativePath()
|
avatarPath := u.CustomAvatarRelativePath()
|
||||||
if err := storage.Avatars.Delete(avatarPath); err != nil {
|
if err := storage.Avatars.Delete(avatarPath); err != nil {
|
||||||
err = fmt.Errorf("Failed to remove %s: %v", avatarPath, err)
|
err = fmt.Errorf("Failed to remove %s: %v", avatarPath, err)
|
||||||
_ = admin_model.CreateNotice(ctx, admin_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err))
|
_ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
admin_model "code.gitea.io/gitea/models/admin"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -384,6 +384,6 @@ func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
admin_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath())
|
system_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,10 +301,18 @@
|
||||||
<div class="ui attached table segment">
|
<div class="ui attached table segment">
|
||||||
<dl class="dl-horizontal admin-dl-horizontal">
|
<dl class="dl-horizontal admin-dl-horizontal">
|
||||||
<dt>{{.locale.Tr "admin.config.disable_gravatar"}}</dt>
|
<dt>{{.locale.Tr "admin.config.disable_gravatar"}}</dt>
|
||||||
<dd>{{if .DisableGravatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
<dd>
|
||||||
|
<div class="ui toggle checkbox">
|
||||||
|
<input type="checkbox" name="picture.disable_gravatar" version="{{.SystemSettings.GetVersion "picture.disable_gravatar"}}"{{if .SystemSettings.GetBool "picture.disable_gravatar"}} checked{{end}}>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<dt>{{.locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
<dt>{{.locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
||||||
<dd>{{if .EnableFederatedAvatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
<dd>
|
||||||
|
<div class="ui toggle checkbox">
|
||||||
|
<input type="checkbox" name="picture.enable_federated_avatar" version="{{.SystemSettings.GetVersion "picture.enable_federated_avatar"}}"{{if .SystemSettings.GetBool "picture.enable_federated_avatar"}} checked{{end}}>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
37
web_src/js/features/admin/config.js
Normal file
37
web_src/js/features/admin/config.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import $ from 'jquery';
|
||||||
|
import {showTemporaryTooltip} from '../../modules/tippy.js';
|
||||||
|
|
||||||
|
const {appSubUrl, csrfToken, pageData} = window.config;
|
||||||
|
|
||||||
|
export function initAdminConfigs() {
|
||||||
|
const isAdminConfigPage = pageData?.adminConfigPage;
|
||||||
|
if (!isAdminConfigPage) return;
|
||||||
|
|
||||||
|
$("input[type='checkbox']").on('change', (e) => {
|
||||||
|
const $this = $(e.currentTarget);
|
||||||
|
$.ajax({
|
||||||
|
url: `${appSubUrl}/admin/config`,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
_csrf: csrfToken,
|
||||||
|
key: $this.attr('name'),
|
||||||
|
value: $this.is(':checked'),
|
||||||
|
version: $this.attr('version'),
|
||||||
|
}
|
||||||
|
}).done((resp) => {
|
||||||
|
if (resp) {
|
||||||
|
if (resp.redirect) {
|
||||||
|
window.location.href = resp.redirect;
|
||||||
|
} else if (resp.version) {
|
||||||
|
$this.attr('version', resp.version);
|
||||||
|
} else if (resp.err) {
|
||||||
|
showTemporaryTooltip(e.currentTarget, resp.err);
|
||||||
|
$this.prop('checked', !$this.is(':checked'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
|
@ -16,7 +16,8 @@ import initRepoMigration from './features/repo-migration.js';
|
||||||
import initRepoProject from './features/repo-projects.js';
|
import initRepoProject from './features/repo-projects.js';
|
||||||
import initServiceWorker from './features/serviceworker.js';
|
import initServiceWorker from './features/serviceworker.js';
|
||||||
import initTableSort from './features/tablesort.js';
|
import initTableSort from './features/tablesort.js';
|
||||||
import {initAdminUserListSearchForm} from './features/admin-users.js';
|
import {initAdminUserListSearchForm} from './features/admin/users.js';
|
||||||
|
import {initAdminConfigs} from './features/admin/config.js';
|
||||||
import {initMarkupAnchors} from './markup/anchors.js';
|
import {initMarkupAnchors} from './markup/anchors.js';
|
||||||
import {initNotificationCount, initNotificationsTable} from './features/notification.js';
|
import {initNotificationCount, initNotificationsTable} from './features/notification.js';
|
||||||
import {initRepoIssueContentHistory} from './features/repo-issue-content.js';
|
import {initRepoIssueContentHistory} from './features/repo-issue-content.js';
|
||||||
|
@ -60,8 +61,8 @@ import {
|
||||||
initGlobalTooltips,
|
initGlobalTooltips,
|
||||||
} from './features/common-global.js';
|
} from './features/common-global.js';
|
||||||
import {initRepoTopicBar} from './features/repo-home.js';
|
import {initRepoTopicBar} from './features/repo-home.js';
|
||||||
import {initAdminEmails} from './features/admin-emails.js';
|
import {initAdminEmails} from './features/admin/emails.js';
|
||||||
import {initAdminCommon} from './features/admin-common.js';
|
import {initAdminCommon} from './features/admin/common.js';
|
||||||
import {initRepoTemplateSearch} from './features/repo-template.js';
|
import {initRepoTemplateSearch} from './features/repo-template.js';
|
||||||
import {initRepoCodeView} from './features/repo-code.js';
|
import {initRepoCodeView} from './features/repo-code.js';
|
||||||
import {initSshKeyFormParser} from './features/sshkey-helper.js';
|
import {initSshKeyFormParser} from './features/sshkey-helper.js';
|
||||||
|
@ -139,6 +140,7 @@ $(document).ready(() => {
|
||||||
initAdminCommon();
|
initAdminCommon();
|
||||||
initAdminEmails();
|
initAdminEmails();
|
||||||
initAdminUserListSearchForm();
|
initAdminUserListSearchForm();
|
||||||
|
initAdminConfigs();
|
||||||
|
|
||||||
initDashboardRepoList();
|
initDashboardRepoList();
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@
|
||||||
--color-timeline: #ececec;
|
--color-timeline: #ececec;
|
||||||
--color-input-text: #212121;
|
--color-input-text: #212121;
|
||||||
--color-input-background: #ffffff;
|
--color-input-background: #ffffff;
|
||||||
|
--color-input-toggle-background: #dedede;
|
||||||
--color-input-border: #dedede;
|
--color-input-border: #dedede;
|
||||||
--color-input-border-hover: #cecece;
|
--color-input-border-hover: #cecece;
|
||||||
--color-navbar: #f8f8f8;
|
--color-navbar: #f8f8f8;
|
||||||
|
|
|
@ -113,7 +113,7 @@ textarea:focus,
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.toggle.checkbox label::before {
|
.ui.toggle.checkbox label::before {
|
||||||
background: var(--color-input-background);
|
background: var(--color-input-toggle-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.toggle.checkbox label,
|
.ui.toggle.checkbox label,
|
||||||
|
|
|
@ -106,6 +106,7 @@
|
||||||
--color-timeline: #4c525e;
|
--color-timeline: #4c525e;
|
||||||
--color-input-text: #d5dbe6;
|
--color-input-text: #d5dbe6;
|
||||||
--color-input-background: #232933;
|
--color-input-background: #232933;
|
||||||
|
--color-input-toggle-background: #454a57;
|
||||||
--color-input-border: #454a57;
|
--color-input-border: #454a57;
|
||||||
--color-input-border-hover: #505667;
|
--color-input-border-hover: #505667;
|
||||||
--color-navbar: #2a2e3a;
|
--color-navbar: #2a2e3a;
|
||||||
|
|
Loading…
Reference in a new issue