mirror of https://github.com/gogs/gogs.git
conf: overhaul settings (#5953)
* Overhaul cache settings * Overhaul HTTP settings * conf: overhaul more settings * log: make LGTM happy * travis: upload report to Codecov * Add codecov.ymlpull/5955/head
parent
d59b0f6ff7
commit
17ae0ed3ee
|
@ -14,4 +14,7 @@ before_install:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- go build -v -tags "pam"
|
- go build -v -tags "pam"
|
||||||
- go test -v -cover -race ./...
|
- go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
|
@ -52,6 +52,7 @@ All notable changes to Gogs are documented in this file.
|
||||||
- Configuration option `[repository] MIRROR_QUEUE_LENGTH`
|
- Configuration option `[repository] MIRROR_QUEUE_LENGTH`
|
||||||
- Configuration option `[repository] PULL_REQUEST_QUEUE_LENGTH`
|
- Configuration option `[repository] PULL_REQUEST_QUEUE_LENGTH`
|
||||||
- Configuration option `[session] ENABLE_SET_COOKIE`
|
- Configuration option `[session] ENABLE_SET_COOKIE`
|
||||||
|
- Configuration option `[release.attachment] PATH`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
comment:
|
||||||
|
layout: 'diff, files'
|
116
conf/app.ini
116
conf/app.ini
|
@ -244,19 +244,63 @@ MAX_LIFE_TIME = 86400
|
||||||
; The cookie name for CSRF token.
|
; The cookie name for CSRF token.
|
||||||
CSRF_COOKIE_NAME = _csrf
|
CSRF_COOKIE_NAME = _csrf
|
||||||
|
|
||||||
; Attachment settings for releases
|
[cache]
|
||||||
[release.attachment]
|
; The cache adapter, either "memory", "redis", or "memcache".
|
||||||
; Whether attachments are enabled. Defaults to `true`
|
ADAPTER = memory
|
||||||
|
; For "memory" only, GC interval in seconds.
|
||||||
|
INTERVAL = 60
|
||||||
|
; For "redis" and "memcache", connection host address:
|
||||||
|
; - redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
|
||||||
|
; - memcache: `127.0.0.1:11211`
|
||||||
|
HOST =
|
||||||
|
|
||||||
|
[http]
|
||||||
|
; The value for "Access-Control-Allow-Origin" header, default is not to present.
|
||||||
|
ACCESS_CONTROL_ALLOW_ORIGIN =
|
||||||
|
|
||||||
|
[attachment]
|
||||||
|
; Whether to enabled upload attachments in general.
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
; Path for attachments. Defaults to `data/attachments`
|
; The path to store attachments on the file system.
|
||||||
PATH = data/attachments
|
PATH = data/attachments
|
||||||
; One or more allowed types, e.g. image/jpeg|image/png
|
; File types that are allowed to be uploaded, e.g. "image/jpeg|image/png". Leave empty to allow any file type.
|
||||||
|
ALLOWED_TYPES = image/jpeg|image/png
|
||||||
|
; The maximum size of each file in MB.
|
||||||
|
MAX_SIZE = 4
|
||||||
|
; The maximum number of files per upload.
|
||||||
|
MAX_FILES = 5
|
||||||
|
|
||||||
|
[release.attachment]
|
||||||
|
; Whether to enabled upload attachments for releases.
|
||||||
|
ENABLED = true
|
||||||
|
; File types that are allowed to be uploaded, e.g. "image/jpeg|image/png". Leave empty to allow any file type.
|
||||||
ALLOWED_TYPES = */*
|
ALLOWED_TYPES = */*
|
||||||
; Max size of each file. Defaults to 32MB
|
; The maximum size of each file in MB.
|
||||||
MAX_SIZE = 32
|
MAX_SIZE = 32
|
||||||
; Max number of files per upload. Defaults to 10
|
; The maximum number of files per upload.
|
||||||
MAX_FILES = 10
|
MAX_FILES = 10
|
||||||
|
|
||||||
|
[time]
|
||||||
|
; Specifies the format for fully outputed dates.
|
||||||
|
; Values should be one of the following:
|
||||||
|
; ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano.
|
||||||
|
; For more information about the format see http://golang.org/pkg/time/#pkg-constants.
|
||||||
|
FORMAT = RFC1123
|
||||||
|
|
||||||
|
[picture]
|
||||||
|
; The path to store user avatars on the file system.
|
||||||
|
AVATAR_UPLOAD_PATH = data/avatars
|
||||||
|
; The path to store repository avatars on the file system.
|
||||||
|
REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars
|
||||||
|
; Chinese users can use a custom avatar source, such as http://cn.gravatar.com/avatar/.
|
||||||
|
GRAVATAR_SOURCE = gravatar
|
||||||
|
; Whether to disable Gravatar, this value will be forced to be true in offline mode.
|
||||||
|
DISABLE_GRAVATAR = false
|
||||||
|
; Whether to enable federated avatar lookup uses DNS to discover avatar associated
|
||||||
|
; with emails, see https://www.libravatar.org for details.
|
||||||
|
; This value will be forced to be false in offline mode or when Gravatar is disbaled.
|
||||||
|
ENABLE_FEDERATED_AVATAR = false
|
||||||
|
|
||||||
[markdown]
|
[markdown]
|
||||||
; Enable hard line break extension
|
; Enable hard line break extension
|
||||||
ENABLE_HARD_LINE_BREAK = false
|
ENABLE_HARD_LINE_BREAK = false
|
||||||
|
@ -274,10 +318,6 @@ DASHES = true
|
||||||
LATEX_DASHES = true
|
LATEX_DASHES = true
|
||||||
ANGLED_QUOTES = true
|
ANGLED_QUOTES = true
|
||||||
|
|
||||||
[http]
|
|
||||||
; Value for Access-Control-Allow-Origin header, default is not to present
|
|
||||||
ACCESS_CONTROL_ALLOW_ORIGIN =
|
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
; Disable regular (non-admin) users to create organizations
|
; Disable regular (non-admin) users to create organizations
|
||||||
DISABLE_REGULAR_ORG_CREATION = false
|
DISABLE_REGULAR_ORG_CREATION = false
|
||||||
|
@ -294,50 +334,6 @@ SKIP_TLS_VERIFY = false
|
||||||
; Number of history information in each page
|
; Number of history information in each page
|
||||||
PAGING_NUM = 10
|
PAGING_NUM = 10
|
||||||
|
|
||||||
[cache]
|
|
||||||
; Either "memory", "redis", or "memcache", default is "memory"
|
|
||||||
ADAPTER = memory
|
|
||||||
; For "memory" only, GC interval in seconds, default is 60
|
|
||||||
INTERVAL = 60
|
|
||||||
; For "redis" and "memcache", connection host address
|
|
||||||
; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
|
|
||||||
; memcache: `127.0.0.1:11211`
|
|
||||||
HOST =
|
|
||||||
|
|
||||||
[picture]
|
|
||||||
; Path to store user uploaded avatars
|
|
||||||
AVATAR_UPLOAD_PATH = data/avatars
|
|
||||||
; Path to store repository uploaded avatars
|
|
||||||
REPOSITORY_AVATAR_UPLOAD_PATH = data/repo-avatars
|
|
||||||
; Chinese users can choose "duoshuo"
|
|
||||||
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
|
|
||||||
GRAVATAR_SOURCE = gravatar
|
|
||||||
; This value will be forced to be true in offline mode.
|
|
||||||
DISABLE_GRAVATAR = false
|
|
||||||
; Federated avatar lookup uses DNS to discover avatar associated
|
|
||||||
; with emails, see https://www.libravatar.org
|
|
||||||
; This value will be forced to be false in offline mode or Gravatar is disbaled.
|
|
||||||
ENABLE_FEDERATED_AVATAR = false
|
|
||||||
|
|
||||||
; Attachment settings for issues
|
|
||||||
[attachment]
|
|
||||||
; Whether attachments are enabled. Defaults to `true`
|
|
||||||
ENABLED = true
|
|
||||||
; Path for attachments. Defaults to `data/attachments`
|
|
||||||
PATH = data/attachments
|
|
||||||
; One or more allowed types, e.g. image/jpeg|image/png
|
|
||||||
ALLOWED_TYPES = image/jpeg|image/png
|
|
||||||
; Max size of each file. Defaults to 4MB
|
|
||||||
MAX_SIZE = 4
|
|
||||||
; Max number of files per upload. Defaults to 5
|
|
||||||
MAX_FILES = 5
|
|
||||||
|
|
||||||
[time]
|
|
||||||
; Specifies the format for fully outputed dates. Defaults to RFC1123
|
|
||||||
; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano
|
|
||||||
; For more information about the format see http://golang.org/pkg/time/#pkg-constants
|
|
||||||
FORMAT =
|
|
||||||
|
|
||||||
; General settings of loggers
|
; General settings of loggers
|
||||||
[log]
|
[log]
|
||||||
ROOT_PATH =
|
ROOT_PATH =
|
||||||
|
@ -446,7 +442,7 @@ PULL = 300
|
||||||
GC = 60
|
GC = 60
|
||||||
|
|
||||||
[mirror]
|
[mirror]
|
||||||
; Default interval in hours between each check
|
; The default interval in hours for fetching updates.
|
||||||
DEFAULT_INTERVAL = 8
|
DEFAULT_INTERVAL = 8
|
||||||
|
|
||||||
[api]
|
[api]
|
||||||
|
@ -491,6 +487,10 @@ ENABLE_BASIC_AUTH = false
|
||||||
BASIC_AUTH_USERNAME =
|
BASIC_AUTH_USERNAME =
|
||||||
BASIC_AUTH_PASSWORD =
|
BASIC_AUTH_PASSWORD =
|
||||||
|
|
||||||
|
; Extension mapping to highlight class
|
||||||
|
; e.g. .toml=ini
|
||||||
|
[highlight.mapping]
|
||||||
|
|
||||||
[i18n]
|
[i18n]
|
||||||
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES,uk-UA,en-GB,hu-HU,sk-SK,id-ID,fa-IR,vi-VN,pt-PT
|
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES,uk-UA,en-GB,hu-HU,sk-SK,id-ID,fa-IR,vi-VN,pt-PT
|
||||||
NAMES = English,简体中文,繁體中文(香港),繁體中文(臺灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,galego,українська,English (United Kingdom),Magyar,Slovenčina,Indonesian,Persian,Vietnamese,Português
|
NAMES = English,简体中文,繁體中文(香港),繁體中文(臺灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,galego,українська,English (United Kingdom),Magyar,Slovenčina,Indonesian,Persian,Vietnamese,Português
|
||||||
|
@ -528,10 +528,6 @@ fa-IR = fa
|
||||||
vi-VN = vi
|
vi-VN = vi
|
||||||
pt-PT = pt
|
pt-PT = pt
|
||||||
|
|
||||||
; Extension mapping to highlight class
|
|
||||||
; e.g. .toml=ini
|
|
||||||
[highlight.mapping]
|
|
||||||
|
|
||||||
[other]
|
[other]
|
||||||
SHOW_FOOTER_BRANDING = false
|
SHOW_FOOTER_BRANDING = false
|
||||||
; Show time of template execution in the footer
|
; Show time of template execution in the footer
|
||||||
|
|
|
@ -1276,12 +1276,16 @@ config.session.gc_interval = GC interval
|
||||||
config.session.max_life_time = Max life time
|
config.session.max_life_time = Max life time
|
||||||
config.session.csrf_cookie_name = CSRF cookie
|
config.session.csrf_cookie_name = CSRF cookie
|
||||||
|
|
||||||
|
config.cache_config = Cache configuration
|
||||||
|
config.cache.adapter = Adapter
|
||||||
|
config.cache.interval = GC interval
|
||||||
|
config.cache.host = Host
|
||||||
|
|
||||||
|
config.http_config = HTTP configuration
|
||||||
|
config.http.access_control_allow_origin = Access control allow origin
|
||||||
|
|
||||||
config.log_file_root_path = Log File Root Path
|
config.log_file_root_path = Log File Root Path
|
||||||
|
|
||||||
config.http_config = HTTP Configuration
|
|
||||||
config.http_access_control_allow_origin = Access Control Allow Origin
|
|
||||||
|
|
||||||
|
|
||||||
config.webhook_config = Webhook Configuration
|
config.webhook_config = Webhook Configuration
|
||||||
config.queue_length = Queue Length
|
config.queue_length = Queue Length
|
||||||
config.deliver_timeout = Deliver Timeout
|
config.deliver_timeout = Deliver Timeout
|
||||||
|
@ -1290,11 +1294,6 @@ config.skip_tls_verify = Skip TLS Verify
|
||||||
config.oauth_config = OAuth Configuration
|
config.oauth_config = OAuth Configuration
|
||||||
config.oauth_enabled = Enabled
|
config.oauth_enabled = Enabled
|
||||||
|
|
||||||
config.cache_config = Cache Configuration
|
|
||||||
config.cache_adapter = Cache Adapter
|
|
||||||
config.cache_interval = Cache Interval
|
|
||||||
config.cache_conn = Cache Connection
|
|
||||||
|
|
||||||
config.picture_config = Picture Configuration
|
config.picture_config = Picture Configuration
|
||||||
config.picture_service = Picture Service
|
config.picture_service = Picture Service
|
||||||
config.disable_gravatar = Disable Gravatar
|
config.disable_gravatar = Disable Gravatar
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -66,7 +66,7 @@ func runImportLocale(c *cli.Context) error {
|
||||||
escapedQuotes := []byte(`\"`)
|
escapedQuotes := []byte(`\"`)
|
||||||
regularQuotes := []byte(`"`)
|
regularQuotes := []byte(`"`)
|
||||||
// Cut out en-US.
|
// Cut out en-US.
|
||||||
for _, lang := range conf.Langs[1:] {
|
for _, lang := range conf.I18n.Langs[1:] {
|
||||||
name := fmt.Sprintf("locale_%s.ini", lang)
|
name := fmt.Sprintf("locale_%s.ini", lang)
|
||||||
source := filepath.Join(c.String("source"), name)
|
source := filepath.Join(c.String("source"), name)
|
||||||
target := filepath.Join(c.String("target"), name)
|
target := filepath.Join(c.String("target"), name)
|
||||||
|
|
|
@ -68,7 +68,7 @@ func setup(c *cli.Context, logPath string, connectDB bool) {
|
||||||
|
|
||||||
err = log.NewFile(log.FileConfig{
|
err = log.NewFile(log.FileConfig{
|
||||||
Level: level,
|
Level: level,
|
||||||
Filename: filepath.Join(conf.LogRootPath, logPath),
|
Filename: filepath.Join(conf.Log.RootPath, logPath),
|
||||||
FileRotationConfig: log.FileRotationConfig{
|
FileRotationConfig: log.FileRotationConfig{
|
||||||
Rotate: true,
|
Rotate: true,
|
||||||
Daily: true,
|
Daily: true,
|
||||||
|
|
|
@ -92,14 +92,14 @@ func newMacaron() *macaron.Macaron {
|
||||||
))
|
))
|
||||||
|
|
||||||
m.Use(macaron.Static(
|
m.Use(macaron.Static(
|
||||||
conf.AvatarUploadPath,
|
conf.Picture.AvatarUploadPath,
|
||||||
macaron.StaticOptions{
|
macaron.StaticOptions{
|
||||||
Prefix: db.USER_AVATAR_URL_PREFIX,
|
Prefix: db.USER_AVATAR_URL_PREFIX,
|
||||||
SkipLogging: conf.Server.DisableRouterLog,
|
SkipLogging: conf.Server.DisableRouterLog,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
m.Use(macaron.Static(
|
m.Use(macaron.Static(
|
||||||
conf.RepositoryAvatarUploadPath,
|
conf.Picture.RepositoryAvatarUploadPath,
|
||||||
macaron.StaticOptions{
|
macaron.StaticOptions{
|
||||||
Prefix: db.REPO_AVATAR_URL_PREFIX,
|
Prefix: db.REPO_AVATAR_URL_PREFIX,
|
||||||
SkipLogging: conf.Server.DisableRouterLog,
|
SkipLogging: conf.Server.DisableRouterLog,
|
||||||
|
@ -129,15 +129,15 @@ func newMacaron() *macaron.Macaron {
|
||||||
SubURL: conf.Server.Subpath,
|
SubURL: conf.Server.Subpath,
|
||||||
Files: localeFiles,
|
Files: localeFiles,
|
||||||
CustomDirectory: filepath.Join(conf.CustomDir(), "conf", "locale"),
|
CustomDirectory: filepath.Join(conf.CustomDir(), "conf", "locale"),
|
||||||
Langs: conf.Langs,
|
Langs: conf.I18n.Langs,
|
||||||
Names: conf.Names,
|
Names: conf.I18n.Names,
|
||||||
DefaultLang: "en-US",
|
DefaultLang: "en-US",
|
||||||
Redirect: true,
|
Redirect: true,
|
||||||
}))
|
}))
|
||||||
m.Use(cache.Cacher(cache.Options{
|
m.Use(cache.Cacher(cache.Options{
|
||||||
Adapter: conf.CacheAdapter,
|
Adapter: conf.Cache.Adapter,
|
||||||
AdapterConfig: conf.CacheConn,
|
AdapterConfig: conf.Cache.Host,
|
||||||
Interval: conf.CacheInterval,
|
Interval: conf.Cache.Interval,
|
||||||
}))
|
}))
|
||||||
m.Use(captcha.Captchaer(captcha.Options{
|
m.Use(captcha.Captchaer(captcha.Options{
|
||||||
SubURL: conf.Server.Subpath,
|
SubURL: conf.Server.Subpath,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -18,13 +17,12 @@ import (
|
||||||
_ "github.com/go-macaron/cache/memcache"
|
_ "github.com/go-macaron/cache/memcache"
|
||||||
_ "github.com/go-macaron/cache/redis"
|
_ "github.com/go-macaron/cache/redis"
|
||||||
_ "github.com/go-macaron/session/redis"
|
_ "github.com/go-macaron/session/redis"
|
||||||
|
"github.com/gogs/go-libravatar"
|
||||||
"github.com/mcuadros/go-version"
|
"github.com/mcuadros/go-version"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
|
|
||||||
"github.com/gogs/go-libravatar"
|
|
||||||
|
|
||||||
"gogs.io/gogs/internal/assets/conf"
|
"gogs.io/gogs/internal/assets/conf"
|
||||||
"gogs.io/gogs/internal/osutil"
|
"gogs.io/gogs/internal/osutil"
|
||||||
)
|
)
|
||||||
|
@ -184,18 +182,18 @@ func Init(customConf string) error {
|
||||||
Repository.Root = ensureAbs(Repository.Root)
|
Repository.Root = ensureAbs(Repository.Root)
|
||||||
Repository.Upload.TempPath = ensureAbs(Repository.Upload.TempPath)
|
Repository.Upload.TempPath = ensureAbs(Repository.Upload.TempPath)
|
||||||
|
|
||||||
// *******************************
|
// *****************************
|
||||||
// ----- Database settings -----
|
// ----- Database settings -----
|
||||||
// *******************************
|
// *****************************
|
||||||
|
|
||||||
if err = File.Section("database").MapTo(&Database); err != nil {
|
if err = File.Section("database").MapTo(&Database); err != nil {
|
||||||
return errors.Wrap(err, "mapping [database] section")
|
return errors.Wrap(err, "mapping [database] section")
|
||||||
}
|
}
|
||||||
Database.Path = ensureAbs(Database.Path)
|
Database.Path = ensureAbs(Database.Path)
|
||||||
|
|
||||||
// *******************************
|
// *****************************
|
||||||
// ----- Security settings -----
|
// ----- Security settings -----
|
||||||
// *******************************
|
// *****************************
|
||||||
|
|
||||||
if err = File.Section("security").MapTo(&Security); err != nil {
|
if err = File.Section("security").MapTo(&Security); err != nil {
|
||||||
return errors.Wrap(err, "mapping [security] section")
|
return errors.Wrap(err, "mapping [security] section")
|
||||||
|
@ -245,37 +243,40 @@ func Init(customConf string) error {
|
||||||
return errors.Wrap(err, "mapping [service] section")
|
return errors.Wrap(err, "mapping [service] section")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***********************************
|
// *************************
|
||||||
// ----- User settings -----
|
// ----- User settings -----
|
||||||
// ***********************************
|
// *************************
|
||||||
|
|
||||||
if err = File.Section("user").MapTo(&User); err != nil {
|
if err = File.Section("user").MapTo(&User); err != nil {
|
||||||
return errors.Wrap(err, "mapping [user] section")
|
return errors.Wrap(err, "mapping [user] section")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***********************************
|
// ****************************
|
||||||
// ----- Session settings -----
|
// ----- Session settings -----
|
||||||
// ***********************************
|
// ****************************
|
||||||
|
|
||||||
if err = File.Section("session").MapTo(&Session); err != nil {
|
if err = File.Section("session").MapTo(&Session); err != nil {
|
||||||
return errors.Wrap(err, "mapping [session] section")
|
return errors.Wrap(err, "mapping [session] section")
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeprecated()
|
// *******************************
|
||||||
|
// ----- Attachment settings -----
|
||||||
|
// *******************************
|
||||||
|
|
||||||
// TODO
|
if err = File.Section("attachment").MapTo(&Attachment); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [attachment] section")
|
||||||
sec := File.Section("attachment")
|
|
||||||
AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments"))
|
|
||||||
if !filepath.IsAbs(AttachmentPath) {
|
|
||||||
AttachmentPath = path.Join(workDir, AttachmentPath)
|
|
||||||
}
|
}
|
||||||
AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
|
Attachment.Path = ensureAbs(Attachment.Path)
|
||||||
AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
|
||||||
AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
|
||||||
AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
|
|
||||||
|
|
||||||
TimeFormat = map[string]string{
|
// *************************
|
||||||
|
// ----- Time settings -----
|
||||||
|
// *************************
|
||||||
|
|
||||||
|
if err = File.Section("time").MapTo(&Time); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [time] section")
|
||||||
|
}
|
||||||
|
|
||||||
|
Time.FormatLayout = map[string]string{
|
||||||
"ANSIC": time.ANSIC,
|
"ANSIC": time.ANSIC,
|
||||||
"UnixDate": time.UnixDate,
|
"UnixDate": time.UnixDate,
|
||||||
"RubyDate": time.RubyDate,
|
"RubyDate": time.RubyDate,
|
||||||
|
@ -291,89 +292,104 @@ func Init(customConf string) error {
|
||||||
"StampMilli": time.StampMilli,
|
"StampMilli": time.StampMilli,
|
||||||
"StampMicro": time.StampMicro,
|
"StampMicro": time.StampMicro,
|
||||||
"StampNano": time.StampNano,
|
"StampNano": time.StampNano,
|
||||||
}[File.Section("time").Key("FORMAT").MustString("RFC1123")]
|
}[Time.Format]
|
||||||
|
if Time.FormatLayout == "" {
|
||||||
|
return fmt.Errorf("unrecognized '[time] FORMAT': %s", Time.Format)
|
||||||
|
}
|
||||||
|
|
||||||
sec = File.Section("picture")
|
// ****************************
|
||||||
AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "avatars"))
|
// ----- Picture settings -----
|
||||||
if !filepath.IsAbs(AvatarUploadPath) {
|
// ****************************
|
||||||
AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
|
|
||||||
|
if err = File.Section("picture").MapTo(&Picture); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [picture] section")
|
||||||
}
|
}
|
||||||
RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "repo-avatars"))
|
Picture.AvatarUploadPath = ensureAbs(Picture.AvatarUploadPath)
|
||||||
if !filepath.IsAbs(RepositoryAvatarUploadPath) {
|
Picture.RepositoryAvatarUploadPath = ensureAbs(Picture.RepositoryAvatarUploadPath)
|
||||||
RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
|
|
||||||
}
|
switch Picture.GravatarSource {
|
||||||
switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
|
|
||||||
case "duoshuo":
|
|
||||||
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
|
|
||||||
case "gravatar":
|
case "gravatar":
|
||||||
GravatarSource = "https://secure.gravatar.com/avatar/"
|
Picture.GravatarSource = "https://secure.gravatar.com/avatar/"
|
||||||
case "libravatar":
|
case "libravatar":
|
||||||
GravatarSource = "https://seccdn.libravatar.org/avatar/"
|
Picture.GravatarSource = "https://seccdn.libravatar.org/avatar/"
|
||||||
default:
|
|
||||||
GravatarSource = source
|
|
||||||
}
|
}
|
||||||
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
|
|
||||||
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
|
|
||||||
if Server.OfflineMode {
|
if Server.OfflineMode {
|
||||||
DisableGravatar = true
|
Picture.DisableGravatar = true
|
||||||
EnableFederatedAvatar = false
|
Picture.EnableFederatedAvatar = false
|
||||||
}
|
}
|
||||||
if DisableGravatar {
|
if Picture.DisableGravatar {
|
||||||
EnableFederatedAvatar = false
|
Picture.EnableFederatedAvatar = false
|
||||||
|
}
|
||||||
|
if Picture.EnableFederatedAvatar {
|
||||||
|
gravatarURL, err := url.Parse(Picture.GravatarSource)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "parse Gravatar source %q", Picture.GravatarSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
if EnableFederatedAvatar {
|
Picture.LibravatarService = libravatar.New()
|
||||||
LibravatarService = libravatar.New()
|
if gravatarURL.Scheme == "https" {
|
||||||
parts := strings.Split(GravatarSource, "/")
|
Picture.LibravatarService.SetUseHTTPS(true)
|
||||||
if len(parts) >= 3 {
|
Picture.LibravatarService.SetSecureFallbackHost(gravatarURL.Host)
|
||||||
if parts[0] == "https:" {
|
|
||||||
LibravatarService.SetUseHTTPS(true)
|
|
||||||
LibravatarService.SetSecureFallbackHost(parts[2])
|
|
||||||
} else {
|
} else {
|
||||||
LibravatarService.SetUseHTTPS(false)
|
Picture.LibravatarService.SetUseHTTPS(false)
|
||||||
LibravatarService.SetFallbackHost(parts[2])
|
Picture.LibravatarService.SetFallbackHost(gravatarURL.Host)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = File.Section("http").MapTo(&HTTP); err != nil {
|
// ***************************
|
||||||
log.Fatal("Failed to map HTTP settings: %v", err)
|
// ----- Mirror settings -----
|
||||||
} else if err = File.Section("webhook").MapTo(&Webhook); err != nil {
|
// ***************************
|
||||||
log.Fatal("Failed to map Webhook settings: %v", err)
|
|
||||||
} else if err = File.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
|
if err = File.Section("mirror").MapTo(&Mirror); err != nil {
|
||||||
log.Fatal("Failed to map Release.Attachment settings: %v", err)
|
return errors.Wrap(err, "mapping [mirror] section")
|
||||||
} else if err = File.Section("markdown").MapTo(&Markdown); err != nil {
|
|
||||||
log.Fatal("Failed to map Markdown settings: %v", err)
|
|
||||||
} else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil {
|
|
||||||
log.Fatal("Failed to map Smartypants settings: %v", err)
|
|
||||||
} else if err = File.Section("admin").MapTo(&Admin); err != nil {
|
|
||||||
log.Fatal("Failed to map Admin settings: %v", err)
|
|
||||||
} else if err = File.Section("cron").MapTo(&Cron); err != nil {
|
|
||||||
log.Fatal("Failed to map Cron settings: %v", err)
|
|
||||||
} else if err = File.Section("git").MapTo(&Git); err != nil {
|
|
||||||
log.Fatal("Failed to map Git settings: %v", err)
|
|
||||||
} else if err = File.Section("mirror").MapTo(&Mirror); err != nil {
|
|
||||||
log.Fatal("Failed to map Mirror settings: %v", err)
|
|
||||||
} else if err = File.Section("api").MapTo(&API); err != nil {
|
|
||||||
log.Fatal("Failed to map API settings: %v", err)
|
|
||||||
} else if err = File.Section("ui").MapTo(&UI); err != nil {
|
|
||||||
log.Fatal("Failed to map UI settings: %v", err)
|
|
||||||
} else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil {
|
|
||||||
log.Fatal("Failed to map Prometheus settings: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if Mirror.DefaultInterval <= 0 {
|
if Mirror.DefaultInterval <= 0 {
|
||||||
Mirror.DefaultInterval = 24
|
Mirror.DefaultInterval = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
Langs = File.Section("i18n").Key("LANGS").Strings(",")
|
// *************************
|
||||||
Names = File.Section("i18n").Key("NAMES").Strings(",")
|
// ----- I18n settings -----
|
||||||
dateLangs = File.Section("i18n.datelang").KeysHash()
|
// *************************
|
||||||
|
|
||||||
ShowFooterBranding = File.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
|
I18n = new(i18n)
|
||||||
ShowFooterTemplateLoadTime = File.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
|
if err = File.Section("i18n").MapTo(I18n); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [i18n] section")
|
||||||
|
}
|
||||||
|
I18n.dateLangs = File.Section("i18n.datelang").KeysHash()
|
||||||
|
|
||||||
HasRobotsTxt = osutil.IsFile(path.Join(CustomDir(), "robots.txt"))
|
handleDeprecated()
|
||||||
|
|
||||||
|
if err = File.Section("cache").MapTo(&Cache); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [cache] section")
|
||||||
|
} else if err = File.Section("http").MapTo(&HTTP); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [http] section")
|
||||||
|
} else if err = File.Section("release").MapTo(&Release); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [release] section")
|
||||||
|
} else if err = File.Section("webhook").MapTo(&Webhook); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [webhook] section")
|
||||||
|
} else if err = File.Section("markdown").MapTo(&Markdown); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [markdown] section")
|
||||||
|
} else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [smartypants] section")
|
||||||
|
} else if err = File.Section("admin").MapTo(&Admin); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [admin] section")
|
||||||
|
} else if err = File.Section("cron").MapTo(&Cron); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [cron] section")
|
||||||
|
} else if err = File.Section("git").MapTo(&Git); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [git] section")
|
||||||
|
} else if err = File.Section("api").MapTo(&API); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [api] section")
|
||||||
|
} else if err = File.Section("ui").MapTo(&UI); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [ui] section")
|
||||||
|
} else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [prometheus] section")
|
||||||
|
} else if err = File.Section("other").MapTo(&Other); err != nil {
|
||||||
|
return errors.Wrap(err, "mapping [other] section")
|
||||||
|
}
|
||||||
|
|
||||||
|
HasRobotsTxt = osutil.IsFile(filepath.Join(CustomDir(), "robots.txt"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,325 +400,3 @@ func MustInit(customConf string) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
var (
|
|
||||||
HTTP struct {
|
|
||||||
AccessControlAllowOrigin string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Database settings
|
|
||||||
UseSQLite3 bool
|
|
||||||
UseMySQL bool
|
|
||||||
UsePostgreSQL bool
|
|
||||||
UseMSSQL bool
|
|
||||||
|
|
||||||
// Webhook settings
|
|
||||||
Webhook struct {
|
|
||||||
Types []string
|
|
||||||
QueueLength int
|
|
||||||
DeliverTimeout int
|
|
||||||
SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
|
|
||||||
PagingNum int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release settigns
|
|
||||||
Release struct {
|
|
||||||
Attachment struct {
|
|
||||||
Enabled bool
|
|
||||||
TempPath string
|
|
||||||
AllowedTypes []string `delim:"|"`
|
|
||||||
MaxSize int64
|
|
||||||
MaxFiles int
|
|
||||||
} `ini:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Markdown sttings
|
|
||||||
Markdown struct {
|
|
||||||
EnableHardLineBreak bool
|
|
||||||
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
|
|
||||||
FileExtensions []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smartypants settings
|
|
||||||
Smartypants struct {
|
|
||||||
Enabled bool
|
|
||||||
Fractions bool
|
|
||||||
Dashes bool
|
|
||||||
LatexDashes bool
|
|
||||||
AngledQuotes bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Admin settings
|
|
||||||
Admin struct {
|
|
||||||
DisableRegularOrgCreation bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Picture settings
|
|
||||||
AvatarUploadPath string
|
|
||||||
RepositoryAvatarUploadPath string
|
|
||||||
GravatarSource string
|
|
||||||
DisableGravatar bool
|
|
||||||
EnableFederatedAvatar bool
|
|
||||||
LibravatarService *libravatar.Libravatar
|
|
||||||
|
|
||||||
// Log settings
|
|
||||||
LogRootPath string
|
|
||||||
LogModes []string
|
|
||||||
LogConfigs []interface{}
|
|
||||||
|
|
||||||
// Attachment settings
|
|
||||||
AttachmentPath string
|
|
||||||
AttachmentAllowedTypes string
|
|
||||||
AttachmentMaxSize int64
|
|
||||||
AttachmentMaxFiles int
|
|
||||||
AttachmentEnabled bool
|
|
||||||
|
|
||||||
// Time settings
|
|
||||||
TimeFormat string
|
|
||||||
|
|
||||||
// Cache settings
|
|
||||||
CacheAdapter string
|
|
||||||
CacheInterval int
|
|
||||||
CacheConn string
|
|
||||||
|
|
||||||
// Cron tasks
|
|
||||||
Cron struct {
|
|
||||||
UpdateMirror struct {
|
|
||||||
Enabled bool
|
|
||||||
RunAtStart bool
|
|
||||||
Schedule string
|
|
||||||
} `ini:"cron.update_mirrors"`
|
|
||||||
RepoHealthCheck struct {
|
|
||||||
Enabled bool
|
|
||||||
RunAtStart bool
|
|
||||||
Schedule string
|
|
||||||
Timeout time.Duration
|
|
||||||
Args []string `delim:" "`
|
|
||||||
} `ini:"cron.repo_health_check"`
|
|
||||||
CheckRepoStats struct {
|
|
||||||
Enabled bool
|
|
||||||
RunAtStart bool
|
|
||||||
Schedule string
|
|
||||||
} `ini:"cron.check_repo_stats"`
|
|
||||||
RepoArchiveCleanup struct {
|
|
||||||
Enabled bool
|
|
||||||
RunAtStart bool
|
|
||||||
Schedule string
|
|
||||||
OlderThan time.Duration
|
|
||||||
} `ini:"cron.repo_archive_cleanup"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Git settings
|
|
||||||
Git struct {
|
|
||||||
Version string `ini:"-"`
|
|
||||||
DisableDiffHighlight bool
|
|
||||||
MaxGitDiffLines int
|
|
||||||
MaxGitDiffLineCharacters int
|
|
||||||
MaxGitDiffFiles int
|
|
||||||
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
|
||||||
Timeout struct {
|
|
||||||
Migrate int
|
|
||||||
Mirror int
|
|
||||||
Clone int
|
|
||||||
Pull int
|
|
||||||
GC int `ini:"GC"`
|
|
||||||
} `ini:"git.timeout"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mirror settings
|
|
||||||
Mirror struct {
|
|
||||||
DefaultInterval int
|
|
||||||
}
|
|
||||||
|
|
||||||
// API settings
|
|
||||||
API struct {
|
|
||||||
MaxResponseItems int
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI settings
|
|
||||||
UI struct {
|
|
||||||
ExplorePagingNum int
|
|
||||||
IssuePagingNum int
|
|
||||||
FeedMaxCommitNum int
|
|
||||||
ThemeColorMetaTag string
|
|
||||||
MaxDisplayFileSize int64
|
|
||||||
|
|
||||||
Admin struct {
|
|
||||||
UserPagingNum int
|
|
||||||
RepoPagingNum int
|
|
||||||
NoticePagingNum int
|
|
||||||
OrgPagingNum int
|
|
||||||
} `ini:"ui.admin"`
|
|
||||||
User struct {
|
|
||||||
RepoPagingNum int
|
|
||||||
NewsFeedPagingNum int
|
|
||||||
CommitsPagingNum int
|
|
||||||
} `ini:"ui.user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prometheus settings
|
|
||||||
Prometheus struct {
|
|
||||||
Enabled bool
|
|
||||||
EnableBasicAuth bool
|
|
||||||
BasicAuthUsername string
|
|
||||||
BasicAuthPassword string
|
|
||||||
}
|
|
||||||
|
|
||||||
// I18n settings
|
|
||||||
Langs []string
|
|
||||||
Names []string
|
|
||||||
dateLangs map[string]string
|
|
||||||
|
|
||||||
// Highlight settings are loaded in modules/template/hightlight.go
|
|
||||||
|
|
||||||
// Other settings
|
|
||||||
ShowFooterBranding bool
|
|
||||||
ShowFooterTemplateLoadTime bool
|
|
||||||
|
|
||||||
// Global setting objects
|
|
||||||
HasRobotsTxt bool
|
|
||||||
)
|
|
||||||
|
|
||||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
|
|
||||||
func DateLang(lang string) string {
|
|
||||||
name, ok := dateLangs[lang]
|
|
||||||
if ok {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
return "en"
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitLogging initializes the logging service of the application.
|
|
||||||
func InitLogging() {
|
|
||||||
LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
|
|
||||||
|
|
||||||
// Because we always create a console logger as the primary logger at init time,
|
|
||||||
// we need to remove it in case the user doesn't configure to use it after the
|
|
||||||
// logging service is initalized.
|
|
||||||
hasConsole := false
|
|
||||||
|
|
||||||
// Iterate over [log.*] sections to initialize individual logger.
|
|
||||||
LogModes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
|
|
||||||
LogConfigs = make([]interface{}, len(LogModes))
|
|
||||||
levelMappings := map[string]log.Level{
|
|
||||||
"trace": log.LevelTrace,
|
|
||||||
"info": log.LevelInfo,
|
|
||||||
"warn": log.LevelWarn,
|
|
||||||
"error": log.LevelError,
|
|
||||||
"fatal": log.LevelFatal,
|
|
||||||
}
|
|
||||||
|
|
||||||
type config struct {
|
|
||||||
Buffer int64
|
|
||||||
Config interface{}
|
|
||||||
}
|
|
||||||
for i, mode := range LogModes {
|
|
||||||
mode = strings.ToLower(strings.TrimSpace(mode))
|
|
||||||
secName := "log." + mode
|
|
||||||
sec, err := File.GetSection(secName)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
|
|
||||||
buffer := sec.Key("BUFFER_LEN").MustInt64(100)
|
|
||||||
c := new(config)
|
|
||||||
switch mode {
|
|
||||||
case log.DefaultConsoleName:
|
|
||||||
hasConsole = true
|
|
||||||
c = &config{
|
|
||||||
Buffer: buffer,
|
|
||||||
Config: log.ConsoleConfig{
|
|
||||||
Level: level,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = log.NewConsole(c.Buffer, c.Config)
|
|
||||||
|
|
||||||
case log.DefaultFileName:
|
|
||||||
logPath := filepath.Join(LogRootPath, "gogs.log")
|
|
||||||
logDir := filepath.Dir(logPath)
|
|
||||||
err = os.MkdirAll(logDir, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to create log directory %q: %v", logDir, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c = &config{
|
|
||||||
Buffer: buffer,
|
|
||||||
Config: log.FileConfig{
|
|
||||||
Level: level,
|
|
||||||
Filename: logPath,
|
|
||||||
FileRotationConfig: log.FileRotationConfig{
|
|
||||||
Rotate: sec.Key("LOG_ROTATE").MustBool(true),
|
|
||||||
Daily: sec.Key("DAILY_ROTATE").MustBool(true),
|
|
||||||
MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
|
||||||
MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
|
|
||||||
MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = log.NewFile(c.Buffer, c.Config)
|
|
||||||
|
|
||||||
case log.DefaultSlackName:
|
|
||||||
c = &config{
|
|
||||||
Buffer: buffer,
|
|
||||||
Config: log.SlackConfig{
|
|
||||||
Level: level,
|
|
||||||
URL: sec.Key("URL").String(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = log.NewSlack(c.Buffer, c.Config)
|
|
||||||
|
|
||||||
case log.DefaultDiscordName:
|
|
||||||
c = &config{
|
|
||||||
Buffer: buffer,
|
|
||||||
Config: log.DiscordConfig{
|
|
||||||
Level: level,
|
|
||||||
URL: sec.Key("URL").String(),
|
|
||||||
Username: sec.Key("USERNAME").String(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Failed to init %s logger: %v", mode, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
LogConfigs[i] = c
|
|
||||||
|
|
||||||
log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String())))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasConsole {
|
|
||||||
log.Remove(log.DefaultConsoleName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCacheService() {
|
|
||||||
CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
|
|
||||||
switch CacheAdapter {
|
|
||||||
case "memory":
|
|
||||||
CacheInterval = File.Section("cache").Key("INTERVAL").MustInt(60)
|
|
||||||
case "redis", "memcache":
|
|
||||||
CacheConn = strings.Trim(File.Section("cache").Key("HOST").String(), "\" ")
|
|
||||||
default:
|
|
||||||
log.Fatal("Unrecognized cache adapter %q", CacheAdapter)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Trace("Cache service is enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServices() {
|
|
||||||
newCacheService()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HookMode indicates whether program starts as Git server-side hook callback.
|
|
||||||
// All operations should be done synchronously to prevent program exits before finishing.
|
|
||||||
var HookMode bool
|
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
// Copyright 2020 The Gogs 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 conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Log settings
|
||||||
|
var Log struct {
|
||||||
|
RootPath string
|
||||||
|
Modes []string
|
||||||
|
Configs []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitLogging initializes the logging service of the application.
|
||||||
|
func InitLogging() {
|
||||||
|
Log.RootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
|
||||||
|
|
||||||
|
// Because we always create a console logger as the primary logger at init time,
|
||||||
|
// we need to remove it in case the user doesn't configure to use it after the
|
||||||
|
// logging service is initalized.
|
||||||
|
hasConsole := false
|
||||||
|
|
||||||
|
// Iterate over [log.*] sections to initialize individual logger.
|
||||||
|
Log.Modes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
|
||||||
|
Log.Configs = make([]interface{}, 0, len(Log.Modes))
|
||||||
|
levelMappings := map[string]log.Level{
|
||||||
|
"trace": log.LevelTrace,
|
||||||
|
"info": log.LevelInfo,
|
||||||
|
"warn": log.LevelWarn,
|
||||||
|
"error": log.LevelError,
|
||||||
|
"fatal": log.LevelFatal,
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
Buffer int64
|
||||||
|
Config interface{}
|
||||||
|
}
|
||||||
|
for _, mode := range Log.Modes {
|
||||||
|
mode = strings.ToLower(strings.TrimSpace(mode))
|
||||||
|
secName := "log." + mode
|
||||||
|
sec, err := File.GetSection(secName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
|
||||||
|
buffer := sec.Key("BUFFER_LEN").MustInt64(100)
|
||||||
|
var c *config
|
||||||
|
switch mode {
|
||||||
|
case log.DefaultConsoleName:
|
||||||
|
hasConsole = true
|
||||||
|
c = &config{
|
||||||
|
Buffer: buffer,
|
||||||
|
Config: log.ConsoleConfig{
|
||||||
|
Level: level,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = log.NewConsole(c.Buffer, c.Config)
|
||||||
|
|
||||||
|
case log.DefaultFileName:
|
||||||
|
logPath := filepath.Join(Log.RootPath, "gogs.log")
|
||||||
|
logDir := filepath.Dir(logPath)
|
||||||
|
err = os.MkdirAll(logDir, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to create log directory %q: %v", logDir, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c = &config{
|
||||||
|
Buffer: buffer,
|
||||||
|
Config: log.FileConfig{
|
||||||
|
Level: level,
|
||||||
|
Filename: logPath,
|
||||||
|
FileRotationConfig: log.FileRotationConfig{
|
||||||
|
Rotate: sec.Key("LOG_ROTATE").MustBool(true),
|
||||||
|
Daily: sec.Key("DAILY_ROTATE").MustBool(true),
|
||||||
|
MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
||||||
|
MaxLines: sec.Key("MAX_LINES").MustInt64(1000000),
|
||||||
|
MaxDays: sec.Key("MAX_DAYS").MustInt64(7),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = log.NewFile(c.Buffer, c.Config)
|
||||||
|
|
||||||
|
case log.DefaultSlackName:
|
||||||
|
c = &config{
|
||||||
|
Buffer: buffer,
|
||||||
|
Config: log.SlackConfig{
|
||||||
|
Level: level,
|
||||||
|
URL: sec.Key("URL").String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = log.NewSlack(c.Buffer, c.Config)
|
||||||
|
|
||||||
|
case log.DefaultDiscordName:
|
||||||
|
c = &config{
|
||||||
|
Buffer: buffer,
|
||||||
|
Config: log.DiscordConfig{
|
||||||
|
Level: level,
|
||||||
|
URL: sec.Key("URL").String(),
|
||||||
|
Username: sec.Key("USERNAME").String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = log.NewDiscord(c.Buffer, c.Config)
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to init %s logger: %v", mode, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Configs = append(Log.Configs, c)
|
||||||
|
log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String())))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasConsole {
|
||||||
|
log.Remove(log.DefaultConsoleName)
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,9 @@ package conf
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogs/go-libravatar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ℹ️ README: This file contains static values that should only be set at initialization time.
|
// ℹ️ README: This file contains static values that should only be set at initialization time.
|
||||||
|
@ -227,8 +230,199 @@ var (
|
||||||
// Deprecated: Use MaxLifeTime instead, will be removed in 0.13.
|
// Deprecated: Use MaxLifeTime instead, will be removed in 0.13.
|
||||||
SessionLifeTime int64
|
SessionLifeTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache settings
|
||||||
|
Cache struct {
|
||||||
|
Adapter string
|
||||||
|
Interval int
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTP settings
|
||||||
|
HTTP struct {
|
||||||
|
AccessControlAllowOrigin string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attachment settings
|
||||||
|
Attachment struct {
|
||||||
|
Enabled bool
|
||||||
|
Path string
|
||||||
|
AllowedTypes []string `delim:"|"`
|
||||||
|
MaxSize int64
|
||||||
|
MaxFiles int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release settigns
|
||||||
|
Release struct {
|
||||||
|
Attachment struct {
|
||||||
|
Enabled bool
|
||||||
|
AllowedTypes []string `delim:"|"`
|
||||||
|
MaxSize int64
|
||||||
|
MaxFiles int
|
||||||
|
} `ini:"release.attachment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time settings
|
||||||
|
Time struct {
|
||||||
|
Format string
|
||||||
|
|
||||||
|
// Derived from other static values
|
||||||
|
FormatLayout string `ini:"-"` // Actual layout of the Format.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Picture settings
|
||||||
|
Picture struct {
|
||||||
|
AvatarUploadPath string
|
||||||
|
RepositoryAvatarUploadPath string
|
||||||
|
GravatarSource string
|
||||||
|
DisableGravatar bool
|
||||||
|
EnableFederatedAvatar bool
|
||||||
|
|
||||||
|
// Derived from other static values
|
||||||
|
LibravatarService *libravatar.Libravatar `ini:"-"` // Initialized client for federated avatar.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mirror settings
|
||||||
|
Mirror struct {
|
||||||
|
DefaultInterval int
|
||||||
|
}
|
||||||
|
|
||||||
|
// I18n settings
|
||||||
|
I18n *i18n
|
||||||
|
|
||||||
|
// Webhook settings
|
||||||
|
Webhook struct {
|
||||||
|
Types []string
|
||||||
|
QueueLength int
|
||||||
|
DeliverTimeout int
|
||||||
|
SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
|
||||||
|
PagingNum int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Markdown sttings
|
||||||
|
Markdown struct {
|
||||||
|
EnableHardLineBreak bool
|
||||||
|
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
|
||||||
|
FileExtensions []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smartypants settings
|
||||||
|
Smartypants struct {
|
||||||
|
Enabled bool
|
||||||
|
Fractions bool
|
||||||
|
Dashes bool
|
||||||
|
LatexDashes bool
|
||||||
|
AngledQuotes bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin settings
|
||||||
|
Admin struct {
|
||||||
|
DisableRegularOrgCreation bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cron tasks
|
||||||
|
Cron struct {
|
||||||
|
UpdateMirror struct {
|
||||||
|
Enabled bool
|
||||||
|
RunAtStart bool
|
||||||
|
Schedule string
|
||||||
|
} `ini:"cron.update_mirrors"`
|
||||||
|
RepoHealthCheck struct {
|
||||||
|
Enabled bool
|
||||||
|
RunAtStart bool
|
||||||
|
Schedule string
|
||||||
|
Timeout time.Duration
|
||||||
|
Args []string `delim:" "`
|
||||||
|
} `ini:"cron.repo_health_check"`
|
||||||
|
CheckRepoStats struct {
|
||||||
|
Enabled bool
|
||||||
|
RunAtStart bool
|
||||||
|
Schedule string
|
||||||
|
} `ini:"cron.check_repo_stats"`
|
||||||
|
RepoArchiveCleanup struct {
|
||||||
|
Enabled bool
|
||||||
|
RunAtStart bool
|
||||||
|
Schedule string
|
||||||
|
OlderThan time.Duration
|
||||||
|
} `ini:"cron.repo_archive_cleanup"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git settings
|
||||||
|
Git struct {
|
||||||
|
Version string `ini:"-"`
|
||||||
|
DisableDiffHighlight bool
|
||||||
|
MaxGitDiffLines int
|
||||||
|
MaxGitDiffLineCharacters int
|
||||||
|
MaxGitDiffFiles int
|
||||||
|
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
||||||
|
Timeout struct {
|
||||||
|
Migrate int
|
||||||
|
Mirror int
|
||||||
|
Clone int
|
||||||
|
Pull int
|
||||||
|
GC int `ini:"GC"`
|
||||||
|
} `ini:"git.timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// API settings
|
||||||
|
API struct {
|
||||||
|
MaxResponseItems int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI settings
|
||||||
|
UI struct {
|
||||||
|
ExplorePagingNum int
|
||||||
|
IssuePagingNum int
|
||||||
|
FeedMaxCommitNum int
|
||||||
|
ThemeColorMetaTag string
|
||||||
|
MaxDisplayFileSize int64
|
||||||
|
|
||||||
|
Admin struct {
|
||||||
|
UserPagingNum int
|
||||||
|
RepoPagingNum int
|
||||||
|
NoticePagingNum int
|
||||||
|
OrgPagingNum int
|
||||||
|
} `ini:"ui.admin"`
|
||||||
|
User struct {
|
||||||
|
RepoPagingNum int
|
||||||
|
NewsFeedPagingNum int
|
||||||
|
CommitsPagingNum int
|
||||||
|
} `ini:"ui.user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prometheus settings
|
||||||
|
Prometheus struct {
|
||||||
|
Enabled bool
|
||||||
|
EnableBasicAuth bool
|
||||||
|
BasicAuthUsername string
|
||||||
|
BasicAuthPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other settings
|
||||||
|
Other struct {
|
||||||
|
ShowFooterBranding bool
|
||||||
|
ShowFooterTemplateLoadTime bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global setting
|
||||||
|
HasRobotsTxt bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type i18n struct {
|
||||||
|
Langs []string `delim:","`
|
||||||
|
Names []string `delim:","`
|
||||||
|
dateLangs map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
|
||||||
|
func (i *i18n) DateLang(lang string) string {
|
||||||
|
name, ok := i.dateLangs[lang]
|
||||||
|
if ok {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return "en"
|
||||||
|
}
|
||||||
|
|
||||||
// handleDeprecated transfers deprecated values to the new ones when set.
|
// handleDeprecated transfers deprecated values to the new ones when set.
|
||||||
func handleDeprecated() {
|
func handleDeprecated() {
|
||||||
if App.AppName != "" {
|
if App.AppName != "" {
|
||||||
|
@ -294,3 +488,15 @@ func handleDeprecated() {
|
||||||
Session.SessionLifeTime = 0
|
Session.SessionLifeTime = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HookMode indicates whether program starts as Git server-side hook callback.
|
||||||
|
// All operations should be done synchronously to prevent program exits before finishing.
|
||||||
|
var HookMode bool
|
||||||
|
|
||||||
|
// Indicates which database backend is currently being used.
|
||||||
|
var (
|
||||||
|
UseSQLite3 bool
|
||||||
|
UseMySQL bool
|
||||||
|
UsePostgreSQL bool
|
||||||
|
UseMSSQL bool
|
||||||
|
)
|
||||||
|
|
|
@ -312,7 +312,7 @@ func Contexter() macaron.Handler {
|
||||||
|
|
||||||
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
|
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
|
||||||
if c.Req.Method == "POST" && strings.Contains(c.Req.Header.Get("Content-Type"), "multipart/form-data") {
|
if c.Req.Method == "POST" && strings.Contains(c.Req.Header.Get("Content-Type"), "multipart/form-data") {
|
||||||
if err := c.Req.ParseMultipartForm(conf.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
|
if err := c.Req.ParseMultipartForm(conf.Attachment.MaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
|
||||||
c.ServerError("ParseMultipartForm", err)
|
c.ServerError("ParseMultipartForm", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ func Contexter() macaron.Handler {
|
||||||
log.Trace("CSRF Token: %v", c.Data["CSRFToken"])
|
log.Trace("CSRF Token: %v", c.Data["CSRFToken"])
|
||||||
|
|
||||||
c.Data["ShowRegistrationButton"] = !conf.Auth.DisableRegistration
|
c.Data["ShowRegistrationButton"] = !conf.Auth.DisableRegistration
|
||||||
c.Data["ShowFooterBranding"] = conf.ShowFooterBranding
|
c.Data["ShowFooterBranding"] = conf.Other.ShowFooterBranding
|
||||||
|
|
||||||
c.renderNoticeBanner()
|
c.renderNoticeBanner()
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
|
||||||
|
|
||||||
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
|
// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
|
||||||
func AttachmentLocalPath(uuid string) string {
|
func AttachmentLocalPath(uuid string) string {
|
||||||
return path.Join(conf.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
|
return path.Join(conf.Attachment.Path, uuid[0:1], uuid[1:2], uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalPath returns where attachment is stored in local file system.
|
// LocalPath returns where attachment is stored in local file system.
|
||||||
|
|
|
@ -39,7 +39,7 @@ func generateAndMigrateGitHooks(x *xorm.Engine) (err error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cleanup old update.log and http.log files.
|
// Cleanup old update.log and http.log files.
|
||||||
_ = filepath.Walk(conf.LogRootPath, func(path string, info os.FileInfo, err error) error {
|
_ = filepath.Walk(conf.Log.RootPath, func(path string, info os.FileInfo, err error) error {
|
||||||
if !info.IsDir() &&
|
if !info.IsDir() &&
|
||||||
(strings.HasPrefix(filepath.Base(path), "update.log") ||
|
(strings.HasPrefix(filepath.Base(path), "update.log") ||
|
||||||
strings.HasPrefix(filepath.Base(path), "http.log")) {
|
strings.HasPrefix(filepath.Base(path), "http.log")) {
|
||||||
|
|
|
@ -172,7 +172,7 @@ func SetEngine() (err error) {
|
||||||
// WARNING: for serv command, MUST remove the output to os.stdout,
|
// WARNING: for serv command, MUST remove the output to os.stdout,
|
||||||
// so use log file to instead print to stdout.
|
// so use log file to instead print to stdout.
|
||||||
sec := conf.File.Section("log.xorm")
|
sec := conf.File.Section("log.xorm")
|
||||||
logger, err := log.NewFileWriter(path.Join(conf.LogRootPath, "xorm.log"),
|
logger, err := log.NewFileWriter(path.Join(conf.Log.RootPath, "xorm.log"),
|
||||||
log.FileRotationConfig{
|
log.FileRotationConfig{
|
||||||
Rotate: sec.Key("ROTATE").MustBool(true),
|
Rotate: sec.Key("ROTATE").MustBool(true),
|
||||||
Daily: sec.Key("ROTATE_DAILY").MustBool(true),
|
Daily: sec.Key("ROTATE_DAILY").MustBool(true),
|
||||||
|
|
|
@ -296,7 +296,7 @@ func (repo *Repository) HTMLURL() string {
|
||||||
|
|
||||||
// CustomAvatarPath returns repository custom avatar file path.
|
// CustomAvatarPath returns repository custom avatar file path.
|
||||||
func (repo *Repository) CustomAvatarPath() string {
|
func (repo *Repository) CustomAvatarPath() string {
|
||||||
return filepath.Join(conf.RepositoryAvatarUploadPath, com.ToStr(repo.ID))
|
return filepath.Join(conf.Picture.RepositoryAvatarUploadPath, com.ToStr(repo.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelAvatarLink returns relative avatar link to the site domain,
|
// RelAvatarLink returns relative avatar link to the site domain,
|
||||||
|
@ -327,7 +327,7 @@ func (repo *Repository) UploadAvatar(data []byte) error {
|
||||||
return fmt.Errorf("decode image: %v", err)
|
return fmt.Errorf("decode image: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = os.MkdirAll(conf.RepositoryAvatarUploadPath, os.ModePerm)
|
_ = os.MkdirAll(conf.Picture.RepositoryAvatarUploadPath, os.ModePerm)
|
||||||
fw, err := os.Create(repo.CustomAvatarPath())
|
fw, err := os.Create(repo.CustomAvatarPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create custom avatar directory: %v", err)
|
return fmt.Errorf("create custom avatar directory: %v", err)
|
||||||
|
|
|
@ -216,7 +216,7 @@ func (u *User) GenerateActivateCode() string {
|
||||||
|
|
||||||
// CustomAvatarPath returns user custom avatar file path.
|
// CustomAvatarPath returns user custom avatar file path.
|
||||||
func (u *User) CustomAvatarPath() string {
|
func (u *User) CustomAvatarPath() string {
|
||||||
return filepath.Join(conf.AvatarUploadPath, com.ToStr(u.ID))
|
return filepath.Join(conf.Picture.AvatarUploadPath, com.ToStr(u.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateRandomAvatar generates a random avatar for user.
|
// GenerateRandomAvatar generates a random avatar for user.
|
||||||
|
@ -262,7 +262,7 @@ func (u *User) RelAvatarLink() string {
|
||||||
return defaultImgUrl
|
return defaultImgUrl
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, USER_AVATAR_URL_PREFIX, u.ID)
|
return fmt.Sprintf("%s/%s/%d", conf.Server.Subpath, USER_AVATAR_URL_PREFIX, u.ID)
|
||||||
case conf.DisableGravatar:
|
case conf.Picture.DisableGravatar:
|
||||||
if !com.IsExist(u.CustomAvatarPath()) {
|
if !com.IsExist(u.CustomAvatarPath()) {
|
||||||
if err := u.GenerateRandomAvatar(); err != nil {
|
if err := u.GenerateRandomAvatar(); err != nil {
|
||||||
log.Error("GenerateRandomAvatar: %v", err)
|
log.Error("GenerateRandomAvatar: %v", err)
|
||||||
|
@ -341,7 +341,7 @@ func (u *User) UploadAvatar(data []byte) error {
|
||||||
return fmt.Errorf("decode image: %v", err)
|
return fmt.Errorf("decode image: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = os.MkdirAll(conf.AvatarUploadPath, os.ModePerm)
|
_ = os.MkdirAll(conf.Picture.AvatarUploadPath, os.ModePerm)
|
||||||
fw, err := os.Create(u.CustomAvatarPath())
|
fw, err := os.Create(u.CustomAvatarPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create custom avatar directory: %v", err)
|
return fmt.Errorf("create custom avatar directory: %v", err)
|
||||||
|
|
|
@ -206,37 +206,36 @@ func Config(c *context.Context) {
|
||||||
c.Data["Auth"] = conf.Auth
|
c.Data["Auth"] = conf.Auth
|
||||||
c.Data["User"] = conf.User
|
c.Data["User"] = conf.User
|
||||||
c.Data["Session"] = conf.Session
|
c.Data["Session"] = conf.Session
|
||||||
|
c.Data["Cache"] = conf.Cache
|
||||||
c.Data["LogRootPath"] = conf.LogRootPath
|
|
||||||
|
|
||||||
c.Data["HTTP"] = conf.HTTP
|
c.Data["HTTP"] = conf.HTTP
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
c.Data["Attachment"] = conf.Attachment
|
||||||
|
c.Data["Release"] = conf.Release
|
||||||
|
c.Data["Time"] = conf.Time
|
||||||
|
c.Data["Picture"] = conf.Picture
|
||||||
|
c.Data["Mirror"] = conf.Mirror
|
||||||
|
|
||||||
|
// ???
|
||||||
c.Data["Webhook"] = conf.Webhook
|
c.Data["Webhook"] = conf.Webhook
|
||||||
|
|
||||||
c.Data["CacheAdapter"] = conf.CacheAdapter
|
|
||||||
c.Data["CacheInterval"] = conf.CacheInterval
|
|
||||||
c.Data["CacheConn"] = conf.CacheConn
|
|
||||||
|
|
||||||
c.Data["DisableGravatar"] = conf.DisableGravatar
|
|
||||||
c.Data["EnableFederatedAvatar"] = conf.EnableFederatedAvatar
|
|
||||||
|
|
||||||
c.Data["Git"] = conf.Git
|
c.Data["Git"] = conf.Git
|
||||||
|
|
||||||
|
c.Data["LogRootPath"] = conf.Log.RootPath
|
||||||
type logger struct {
|
type logger struct {
|
||||||
Mode, Config string
|
Mode, Config string
|
||||||
}
|
}
|
||||||
loggers := make([]*logger, len(conf.LogModes))
|
loggers := make([]*logger, len(conf.Log.Modes))
|
||||||
for i := range conf.LogModes {
|
for i := range conf.Log.Modes {
|
||||||
loggers[i] = &logger{
|
loggers[i] = &logger{
|
||||||
Mode: strings.Title(conf.LogModes[i]),
|
Mode: strings.Title(conf.Log.Modes[i]),
|
||||||
}
|
}
|
||||||
|
|
||||||
result, _ := jsoniter.MarshalIndent(conf.LogConfigs[i], "", " ")
|
result, _ := jsoniter.MarshalIndent(conf.Log.Configs[i], "", " ")
|
||||||
loggers[i].Config = string(result)
|
loggers[i].Config = string(result)
|
||||||
}
|
}
|
||||||
c.Data["Loggers"] = loggers
|
c.Data["Loggers"] = loggers
|
||||||
|
|
||||||
c.HTML(200, CONFIG)
|
c.Success(CONFIG)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Monitor(c *context.Context) {
|
func Monitor(c *context.Context) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ func GlobalInit(customConf string) error {
|
||||||
log.Trace("Work directory: %s", conf.WorkDir())
|
log.Trace("Work directory: %s", conf.WorkDir())
|
||||||
log.Trace("Custom path: %s", conf.CustomDir())
|
log.Trace("Custom path: %s", conf.CustomDir())
|
||||||
log.Trace("Custom config: %s", conf.CustomConf)
|
log.Trace("Custom config: %s", conf.CustomConf)
|
||||||
log.Trace("Log path: %s", conf.LogRootPath)
|
log.Trace("Log path: %s", conf.Log.RootPath)
|
||||||
log.Trace("Build time: %s", conf.BuildTime)
|
log.Trace("Build time: %s", conf.BuildTime)
|
||||||
log.Trace("Build commit: %s", conf.BuildCommit)
|
log.Trace("Build commit: %s", conf.BuildCommit)
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@ func GlobalInit(customConf string) error {
|
||||||
log.Trace("Email service is enabled")
|
log.Trace("Email service is enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.NewServices()
|
|
||||||
email.NewContext()
|
email.NewContext()
|
||||||
|
|
||||||
if conf.Security.InstallLock {
|
if conf.Security.InstallLock {
|
||||||
|
@ -172,7 +171,7 @@ func Install(c *context.Context) {
|
||||||
f.UseBuiltinSSHServer = conf.SSH.StartBuiltinServer
|
f.UseBuiltinSSHServer = conf.SSH.StartBuiltinServer
|
||||||
f.HTTPPort = conf.Server.HTTPPort
|
f.HTTPPort = conf.Server.HTTPPort
|
||||||
f.AppUrl = conf.Server.ExternalURL
|
f.AppUrl = conf.Server.ExternalURL
|
||||||
f.LogRootPath = conf.LogRootPath
|
f.LogRootPath = conf.Log.RootPath
|
||||||
|
|
||||||
// E-mail service settings
|
// E-mail service settings
|
||||||
if conf.Email.Enabled {
|
if conf.Email.Enabled {
|
||||||
|
@ -185,8 +184,8 @@ func Install(c *context.Context) {
|
||||||
|
|
||||||
// Server and other services settings
|
// Server and other services settings
|
||||||
f.OfflineMode = conf.Server.OfflineMode
|
f.OfflineMode = conf.Server.OfflineMode
|
||||||
f.DisableGravatar = conf.DisableGravatar
|
f.DisableGravatar = conf.Picture.DisableGravatar
|
||||||
f.EnableFederatedAvatar = conf.EnableFederatedAvatar
|
f.EnableFederatedAvatar = conf.Picture.EnableFederatedAvatar
|
||||||
f.DisableRegistration = conf.Auth.DisableRegistration
|
f.DisableRegistration = conf.Auth.DisableRegistration
|
||||||
f.EnableCaptcha = conf.Auth.EnableRegistrationCaptcha
|
f.EnableCaptcha = conf.Auth.EnableRegistrationCaptcha
|
||||||
f.RequireSignInView = conf.Auth.RequireSigninView
|
f.RequireSignInView = conf.Auth.RequireSigninView
|
||||||
|
|
|
@ -256,10 +256,10 @@ func Pulls(c *context.Context) {
|
||||||
|
|
||||||
func renderAttachmentSettings(c *context.Context) {
|
func renderAttachmentSettings(c *context.Context) {
|
||||||
c.Data["RequireDropzone"] = true
|
c.Data["RequireDropzone"] = true
|
||||||
c.Data["IsAttachmentEnabled"] = conf.AttachmentEnabled
|
c.Data["IsAttachmentEnabled"] = conf.Attachment.Enabled
|
||||||
c.Data["AttachmentAllowedTypes"] = conf.AttachmentAllowedTypes
|
c.Data["AttachmentAllowedTypes"] = conf.Attachment.AllowedTypes
|
||||||
c.Data["AttachmentMaxSize"] = conf.AttachmentMaxSize
|
c.Data["AttachmentMaxSize"] = conf.Attachment.MaxSize
|
||||||
c.Data["AttachmentMaxFiles"] = conf.AttachmentMaxFiles
|
c.Data["AttachmentMaxFiles"] = conf.Attachment.MaxFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
func RetrieveRepoMilestonesAndAssignees(c *context.Context, repo *db.Repository) {
|
func RetrieveRepoMilestonesAndAssignees(c *context.Context, repo *db.Repository) {
|
||||||
|
@ -429,7 +429,7 @@ func NewIssuePost(c *context.Context, f form.NewIssue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachments []string
|
var attachments []string
|
||||||
if conf.AttachmentEnabled {
|
if conf.Attachment.Enabled {
|
||||||
attachments = f.Files
|
attachments = f.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,12 +493,12 @@ func uploadAttachment(c *context.Context, allowedTypes []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadIssueAttachment(c *context.Context) {
|
func UploadIssueAttachment(c *context.Context) {
|
||||||
if !conf.AttachmentEnabled {
|
if !conf.Attachment.Enabled {
|
||||||
c.NotFound()
|
c.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadAttachment(c, strings.Split(conf.AttachmentAllowedTypes, ","))
|
uploadAttachment(c, conf.Attachment.AllowedTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewIssue(c *context.Context, isPullList bool) {
|
func viewIssue(c *context.Context, isPullList bool) {
|
||||||
|
@ -845,7 +845,7 @@ func NewComment(c *context.Context, f form.CreateComment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachments []string
|
var attachments []string
|
||||||
if conf.AttachmentEnabled {
|
if conf.Attachment.Enabled {
|
||||||
attachments = f.Files
|
attachments = f.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,7 +1130,7 @@ func NewMilestone(c *context.Context) {
|
||||||
c.Data["PageIsIssueList"] = true
|
c.Data["PageIsIssueList"] = true
|
||||||
c.Data["PageIsMilestones"] = true
|
c.Data["PageIsMilestones"] = true
|
||||||
c.Data["RequireDatetimepicker"] = true
|
c.Data["RequireDatetimepicker"] = true
|
||||||
c.Data["DateLang"] = conf.DateLang(c.Locale.Language())
|
c.Data["DateLang"] = conf.I18n.DateLang(c.Locale.Language())
|
||||||
c.HTML(200, MILESTONE_NEW)
|
c.HTML(200, MILESTONE_NEW)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,7 +1139,7 @@ func NewMilestonePost(c *context.Context, f form.CreateMilestone) {
|
||||||
c.Data["PageIsIssueList"] = true
|
c.Data["PageIsIssueList"] = true
|
||||||
c.Data["PageIsMilestones"] = true
|
c.Data["PageIsMilestones"] = true
|
||||||
c.Data["RequireDatetimepicker"] = true
|
c.Data["RequireDatetimepicker"] = true
|
||||||
c.Data["DateLang"] = conf.DateLang(c.Locale.Language())
|
c.Data["DateLang"] = conf.I18n.DateLang(c.Locale.Language())
|
||||||
|
|
||||||
if c.HasError() {
|
if c.HasError() {
|
||||||
c.HTML(200, MILESTONE_NEW)
|
c.HTML(200, MILESTONE_NEW)
|
||||||
|
@ -1175,7 +1175,7 @@ func EditMilestone(c *context.Context) {
|
||||||
c.Data["PageIsMilestones"] = true
|
c.Data["PageIsMilestones"] = true
|
||||||
c.Data["PageIsEditMilestone"] = true
|
c.Data["PageIsEditMilestone"] = true
|
||||||
c.Data["RequireDatetimepicker"] = true
|
c.Data["RequireDatetimepicker"] = true
|
||||||
c.Data["DateLang"] = conf.DateLang(c.Locale.Language())
|
c.Data["DateLang"] = conf.I18n.DateLang(c.Locale.Language())
|
||||||
|
|
||||||
m, err := db.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id"))
|
m, err := db.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1199,7 +1199,7 @@ func EditMilestonePost(c *context.Context, f form.CreateMilestone) {
|
||||||
c.Data["PageIsMilestones"] = true
|
c.Data["PageIsMilestones"] = true
|
||||||
c.Data["PageIsEditMilestone"] = true
|
c.Data["PageIsEditMilestone"] = true
|
||||||
c.Data["RequireDatetimepicker"] = true
|
c.Data["RequireDatetimepicker"] = true
|
||||||
c.Data["DateLang"] = conf.DateLang(c.Locale.Language())
|
c.Data["DateLang"] = conf.I18n.DateLang(c.Locale.Language())
|
||||||
|
|
||||||
if c.HasError() {
|
if c.HasError() {
|
||||||
c.HTML(200, MILESTONE_NEW)
|
c.HTML(200, MILESTONE_NEW)
|
||||||
|
|
|
@ -677,7 +677,7 @@ func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.AttachmentEnabled {
|
if conf.Attachment.Enabled {
|
||||||
attachments = f.Files
|
attachments = f.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,10 @@ func FuncMap() []template.FuncMap {
|
||||||
return conf.Server.Domain
|
return conf.Server.Domain
|
||||||
},
|
},
|
||||||
"DisableGravatar": func() bool {
|
"DisableGravatar": func() bool {
|
||||||
return conf.DisableGravatar
|
return conf.Picture.DisableGravatar
|
||||||
},
|
},
|
||||||
"ShowFooterTemplateLoadTime": func() bool {
|
"ShowFooterTemplateLoadTime": func() bool {
|
||||||
return conf.ShowFooterTemplateLoadTime
|
return conf.Other.ShowFooterTemplateLoadTime
|
||||||
},
|
},
|
||||||
"LoadTimes": func(startTime time.Time) string {
|
"LoadTimes": func(startTime time.Time) string {
|
||||||
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
||||||
|
|
|
@ -190,16 +190,16 @@ func HashEmail(email string) string {
|
||||||
// which includes app sub-url as prefix. However, it is possible
|
// which includes app sub-url as prefix. However, it is possible
|
||||||
// to return full URL if user enables Gravatar-like service.
|
// to return full URL if user enables Gravatar-like service.
|
||||||
func AvatarLink(email string) (url string) {
|
func AvatarLink(email string) (url string) {
|
||||||
if conf.EnableFederatedAvatar && conf.LibravatarService != nil &&
|
if conf.Picture.EnableFederatedAvatar && conf.Picture.LibravatarService != nil &&
|
||||||
strings.Contains(email, "@") {
|
strings.Contains(email, "@") {
|
||||||
var err error
|
var err error
|
||||||
url, err = conf.LibravatarService.FromEmail(email)
|
url, err = conf.Picture.LibravatarService.FromEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("AvatarLink.LibravatarService.FromEmail [%s]: %v", email, err)
|
log.Warn("AvatarLink.LibravatarService.FromEmail [%s]: %v", email, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(url) == 0 && !conf.DisableGravatar {
|
if len(url) == 0 && !conf.Picture.DisableGravatar {
|
||||||
url = conf.GravatarSource + HashEmail(email) + "?d=identicon"
|
url = conf.Picture.GravatarSource + HashEmail(email) + "?d=identicon"
|
||||||
}
|
}
|
||||||
if len(url) == 0 {
|
if len(url) == 0 {
|
||||||
url = conf.Server.Subpath + "/img/avatar_default.png"
|
url = conf.Server.Subpath + "/img/avatar_default.png"
|
||||||
|
@ -360,7 +360,7 @@ func RawTimeSince(t time.Time, lang string) string {
|
||||||
|
|
||||||
// TimeSince calculates the time interval and generate user-friendly string.
|
// TimeSince calculates the time interval and generate user-friendly string.
|
||||||
func TimeSince(t time.Time, lang string) template.HTML {
|
func TimeSince(t time.Time, lang string) template.HTML {
|
||||||
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`, t.Format(conf.TimeFormat), timeSince(t, lang)))
|
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`, t.Format(conf.Time.FormatLayout), timeSince(t, lang)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subtract deals with subtraction of all types of number.
|
// Subtract deals with subtraction of all types of number.
|
||||||
|
|
|
@ -62,11 +62,6 @@
|
||||||
|
|
||||||
<dt>{{.i18n.Tr "admin.config.server.landing_url"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.server.landing_url"}}</dt>
|
||||||
<dd><code>{{.Server.LandingURL}}</code></dd>
|
<dd><code>{{.Server.LandingURL}}</code></dd>
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
|
|
||||||
<dt>{{.i18n.Tr "admin.config.log_file_root_path"}}</dt>
|
|
||||||
<dd><code>{{.LogRootPath}}</code></dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -121,7 +116,13 @@
|
||||||
<dt>{{.i18n.Tr "admin.config.repo.script_type"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.repo.script_type"}}</dt>
|
||||||
<dd><code>{{.Repository.ScriptType}}</code></dd>
|
<dd><code>{{.Repository.ScriptType}}</code></dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.repo.ansi_chatset"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.repo.ansi_chatset"}}</dt>
|
||||||
<dd>{{if .Repository.ANSICharset}}{{.Repository.AnsiCharset}}{{else}}{{.i18n.Tr "admin.config.not_set"}}{{end}}</dd>
|
<dd>
|
||||||
|
{{if .Repository.ANSICharset}}
|
||||||
|
{{.Repository.AnsiCharset}}
|
||||||
|
{{else}}
|
||||||
|
<i>{{.i18n.Tr "admin.config.not_set"}}</i>
|
||||||
|
{{end}}
|
||||||
|
</dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.repo.force_private"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.repo.force_private"}}</dt>
|
||||||
<dd><i class="fa fa{{if .Repository.ForcePrivate}}-check{{end}}-square-o"></i></dd>
|
<dd><i class="fa fa{{if .Repository.ForcePrivate}}-check{{end}}-square-o"></i></dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.repo.max_creation_limit"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.repo.max_creation_limit"}}</dt>
|
||||||
|
@ -224,7 +225,13 @@
|
||||||
<dt>{{.i18n.Tr "admin.config.email.disable_helo"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.email.disable_helo"}}</dt>
|
||||||
<dd><i class="fa fa{{if .Email.DisableHELO}}-check{{end}}-square-o"></i></dd>
|
<dd><i class="fa fa{{if .Email.DisableHELO}}-check{{end}}-square-o"></i></dd>
|
||||||
<dt>{{.i18n.Tr "admin.config.email.helo_hostname"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.email.helo_hostname"}}</dt>
|
||||||
<dd>{{if .Email.HELOHostname}}{{.Email.HELOHostname}}{{else}}{{.i18n.Tr "admin.config.not_set"}}{{end}}</dd>
|
<dd>
|
||||||
|
{{if .Email.HELOHostname}}
|
||||||
|
{{.Email.HELOHostname}}
|
||||||
|
{{else}}
|
||||||
|
<i>{{.i18n.Tr "admin.config.not_set"}}</i>
|
||||||
|
{{end}}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
|
@ -323,13 +330,34 @@
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- HTTP Configuration -->
|
{{/* Cache settings */}}
|
||||||
|
<h4 class="ui top attached header">
|
||||||
|
{{.i18n.Tr "admin.config.cache_config"}}
|
||||||
|
</h4>
|
||||||
|
<div class="ui attached table segment">
|
||||||
|
<dl class="dl-horizontal admin-dl-horizontal">
|
||||||
|
<dt>{{.i18n.Tr "admin.config.cache.adapter"}}</dt>
|
||||||
|
<dd>{{.Cache.Adapter}}</dd>
|
||||||
|
<dt>{{.i18n.Tr "admin.config.cache.interval"}}</dt>
|
||||||
|
<dd>{{.Cache.Interval}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||||
|
<dt>{{.i18n.Tr "admin.config.cache.host"}}</dt>
|
||||||
|
<dd>
|
||||||
|
{{if .CacheConn}}
|
||||||
|
<code>{{.CacheConn}}</code>
|
||||||
|
{{else}}
|
||||||
|
<i>{{.i18n.Tr "admin.config.not_set"}}</i>
|
||||||
|
{{end}}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{/* HTTP settings */}}
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "admin.config.http_config"}}
|
{{.i18n.Tr "admin.config.http_config"}}
|
||||||
</h4>
|
</h4>
|
||||||
<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>{{.i18n.Tr "admin.config.http_access_control_allow_origin"}}</dt>
|
<dt>{{.i18n.Tr "admin.config.http.access_control_allow_origin"}}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{{if .HTTP.AccessControlAllowOrigin}}
|
{{if .HTTP.AccessControlAllowOrigin}}
|
||||||
<code>{{.HTTP.AccessControlAllowOrigin}}</code>
|
<code>{{.HTTP.AccessControlAllowOrigin}}</code>
|
||||||
|
@ -354,22 +382,6 @@
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="ui top attached header">
|
|
||||||
{{.i18n.Tr "admin.config.cache_config"}}
|
|
||||||
</h4>
|
|
||||||
<div class="ui attached table segment">
|
|
||||||
<dl class="dl-horizontal admin-dl-horizontal">
|
|
||||||
<dt>{{.i18n.Tr "admin.config.cache_adapter"}}</dt>
|
|
||||||
<dd>{{.CacheAdapter}}</dd>
|
|
||||||
<dt>{{.i18n.Tr "admin.config.cache_interval"}}</dt>
|
|
||||||
<dd>{{.CacheInterval}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
|
||||||
{{if .CacheConn}}
|
|
||||||
<dt>{{.i18n.Tr "admin.config.cache_conn"}}</dt>
|
|
||||||
<dd><code>{{.CacheConn}}</code></dd>
|
|
||||||
{{end}}
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "admin.config.picture_config"}}
|
{{.i18n.Tr "admin.config.picture_config"}}
|
||||||
</h4>
|
</h4>
|
||||||
|
@ -415,7 +427,14 @@
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{.i18n.Tr "admin.config.log_config"}}
|
{{.i18n.Tr "admin.config.log_config"}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached log-config segment">
|
<div class="ui attached log-config table segment">
|
||||||
|
<dl class="dl-horizontal admin-dl-horizontal">
|
||||||
|
<dt>{{.i18n.Tr "admin.config.log_file_root_path"}}</dt>
|
||||||
|
<dd><code>{{.LogRootPath}}</code></dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<table class="ui very basic table">
|
<table class="ui very basic table">
|
||||||
{{range .Loggers}}
|
{{range .Loggers}}
|
||||||
<tr>
|
<tr>
|
||||||
|
|
Loading…
Reference in New Issue