You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

959 lines
29 KiB

11 years ago
// Copyright 2014 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.
11 years ago
package setting
11 years ago
import (
"net/mail"
"net/url"
11 years ago
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
11 years ago
"strings"
"time"
11 years ago
"github.com/Unknwon/com"
_ "github.com/go-macaron/cache/memcache"
_ "github.com/go-macaron/cache/redis"
"github.com/go-macaron/session"
_ "github.com/go-macaron/session/redis"
"github.com/mcuadros/go-version"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1"
11 years ago
"github.com/gogs/go-libravatar"
"github.com/gogs/gogs/pkg/bindata"
"github.com/gogs/gogs/pkg/process"
"github.com/gogs/gogs/pkg/user"
11 years ago
)
11 years ago
type Scheme string
11 years ago
11 years ago
const (
SCHEME_HTTP Scheme = "http"
SCHEME_HTTPS Scheme = "https"
SCHEME_FCGI Scheme = "fcgi"
SCHEME_UNIX_SOCKET Scheme = "unix"
11 years ago
)
11 years ago
10 years ago
type LandingPage string
const (
LANDING_PAGE_HOME LandingPage = "/"
LANDING_PAGE_EXPLORE LandingPage = "/explore"
)
11 years ago
var (
// Build information should only be set by -ldflags.
9 years ago
BuildTime string
BuildGitHash string
// App settings
AppVer string
AppName string
AppURL string
AppSubURL string
AppSubURLDepth int // Number of slashes
AppPath string
AppDataPath string
11 years ago
// Server settings
Protocol Scheme
Domain string
HTTPAddr string
HTTPPort string
LocalURL string
OfflineMode bool
DisableRouterLog bool
CertFile string
KeyFile string
TLSMinVersion string
StaticRootPath string
EnableGzip bool
LandingPageURL LandingPage
UnixSocketPermission uint32
11 years ago
HTTP struct {
AccessControlAllowOrigin string
}
SSH struct {
Disabled bool `ini:"DISABLE_SSH"`
StartBuiltinServer bool `ini:"START_SSH_SERVER"`
Domain string `ini:"SSH_DOMAIN"`
Port int `ini:"SSH_PORT"`
ListenHost string `ini:"SSH_LISTEN_HOST"`
ListenPort int `ini:"SSH_LISTEN_PORT"`
RootPath string `ini:"SSH_ROOT_PATH"`
RewriteAuthorizedKeysAtStart bool `ini:"REWRITE_AUTHORIZED_KEYS_AT_START"`
ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"`
KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
KeygenPath string `ini:"SSH_KEYGEN_PATH"`
MinimumKeySizeCheck bool `ini:"MINIMUM_KEY_SIZE_CHECK"`
MinimumKeySizes map[string]int `ini:"-"`
}
// Security settings
InstallLock bool
SecretKey string
LoginRememberDays int
CookieUserName string
CookieRememberName string
CookieSecure bool
ReverseProxyAuthUser string
EnableLoginStatusCookie bool
LoginStatusCookieName string
11 years ago
// Database settings
UseSQLite3 bool
UseMySQL bool
UsePostgreSQL bool
UseMSSQL bool
// Repository settings
Repository struct {
AnsiCharset string
ForcePrivate bool
MaxCreationLimit int
MirrorQueueLength int
PullRequestQueueLength int
PreferredLicenses []string
DisableHTTPGit bool `ini:"DISABLE_HTTP_GIT"`
EnableLocalPathMigration bool
CommitsFetchConcurrency int
EnableRawFileRenderMode bool
// Repository editor settings
Editor struct {
LineWrapExtensions []string
PreviewableFileModes []string
} `ini:"-"`
// Repository upload settings
Upload struct {
Enabled bool
TempPath string
AllowedTypes []string `delim:"|"`
FileMaxSize int64
MaxFiles int
} `ini:"-"`
}
RepoRootPath string
ScriptType string
// 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
11 years ago
// Log settings
11 years ago
LogRootPath string
LogModes []string
LogConfigs []interface{}
11 years ago
// Attachment settings
AttachmentPath string
AttachmentAllowedTypes string
AttachmentMaxSize int64
AttachmentMaxFiles int
AttachmentEnabled bool
// Time settings
TimeFormat string
// Cache settings
CacheAdapter string
CacheInterval int
CacheConn string
11 years ago
// Session settings
SessionConfig session.Options
CSRFCookieName string
11 years ago
// 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
ShowFooterVersion bool
ShowFooterTemplateLoadTime bool
SupportMiniWinService bool
// Global setting objects
10 years ago
Cfg *ini.File
CustomPath string // Custom directory path
CustomConf string
ProdMode bool
RunUser string
IsWindows bool
HasRobotsTxt bool
11 years ago
)
// 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"
}
// execPath returns the executable path.
func execPath() (string, error) {
11 years ago
file, err := exec.LookPath(os.Args[0])
if err != nil {
return "", err
}
return filepath.Abs(file)
}
func init() {
IsWindows = runtime.GOOS == "windows"
log.New(log.CONSOLE, log.ConsoleConfig{})
var err error
if AppPath, err = execPath(); err != nil {
log.Fatal(2, "Fail to get app path: %v\n", err)
11 years ago
}
// Note: we don't use path.Dir here because it does not handle case
// which path starts with two "/" in Windows: "//psf/Home/..."
AppPath = strings.Replace(AppPath, "\\", "/", -1)
}
// WorkDir returns absolute path of work directory.
func WorkDir() (string, error) {
wd := os.Getenv("GOGS_WORK_DIR")
if len(wd) > 0 {
return wd, nil
}
i := strings.LastIndex(AppPath, "/")
if i == -1 {
return AppPath, nil
}
return AppPath[:i], nil
11 years ago
}
func forcePathSeparator(path string) {
if strings.Contains(path, "\\") {
log.Fatal(2, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
}
}
// IsRunUserMatchCurrentUser returns false if configured run user does not match
// actual user that runs the app. The first return value is the actual user name.
// This check is ignored under Windows since SSH remote login is not the main
// method to login on Windows.
func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
if IsWindows {
return "", true
}
currentUser := user.CurrentUsername()
return currentUser, runUser == currentUser
}
// getOpenSSHVersion parses and returns string representation of OpenSSH version
// returned by command "ssh -V".
func getOpenSSHVersion() string {
// Note: somehow version is printed to stderr
_, stderr, err := process.Exec("getOpenSSHVersion", "ssh", "-V")
if err != nil {
log.Fatal(2, "Fail to get OpenSSH version: %v - %s", err, stderr)
}
// Trim unused information: https://github.com/gogs/gogs/issues/4507#issuecomment-305150441
version := strings.TrimRight(strings.Fields(stderr)[0], ",1234567890")
version = strings.TrimSuffix(strings.TrimPrefix(version, "OpenSSH_"), "p")
return version
}
9 years ago
// NewContext initializes configuration context.
11 years ago
// NOTE: do not print any log except error.
9 years ago
func NewContext() {
11 years ago
workDir, err := WorkDir()
if err != nil {
log.Fatal(2, "Fail to get work directory: %v", err)
11 years ago
}
Cfg, err = ini.LoadSources(ini.LoadOptions{
IgnoreInlineComment: true,
}, bindata.MustAsset("conf/app.ini"))
11 years ago
if err != nil {
log.Fatal(2, "Fail to parse 'conf/app.ini': %v", err)
11 years ago
}
CustomPath = os.Getenv("GOGS_CUSTOM")
if len(CustomPath) == 0 {
10 years ago
CustomPath = workDir + "/custom"
11 years ago
}
if len(CustomConf) == 0 {
10 years ago
CustomConf = CustomPath + "/conf/app.ini"
}
if com.IsFile(CustomConf) {
if err = Cfg.Append(CustomConf); err != nil {
log.Fatal(2, "Fail to load custom conf '%s': %v", CustomConf, err)
11 years ago
}
} else {
9 years ago
log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf)
11 years ago
}
Cfg.NameMapper = ini.AllCapsUnderscore
11 years ago
9 years ago
homeDir, err := com.HomeDir()
if err != nil {
log.Fatal(2, "Fail to get home directory: %v", err)
9 years ago
}
homeDir = strings.Replace(homeDir, "\\", "/", -1)
10 years ago
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
forcePathSeparator(LogRootPath)
10 years ago
sec := Cfg.Section("server")
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs")
AppURL = sec.Key("ROOT_URL").MustString("http://localhost:3000/")
if AppURL[len(AppURL)-1] != '/' {
AppURL += "/"
10 years ago
}
11 years ago
// Check if has app suburl.
url, err := url.Parse(AppURL)
if err != nil {
log.Fatal(2, "Invalid ROOT_URL '%s': %s", AppURL, err)
}
// Suburl should start with '/' and end without '/', such as '/{subpath}'.
// This value is empty if site does not have sub-url.
AppSubURL = strings.TrimSuffix(url.Path, "/")
AppSubURLDepth = strings.Count(AppSubURL, "/")
Protocol = SCHEME_HTTP
10 years ago
if sec.Key("PROTOCOL").String() == "https" {
Protocol = SCHEME_HTTPS
10 years ago
CertFile = sec.Key("CERT_FILE").String()
KeyFile = sec.Key("KEY_FILE").String()
TLSMinVersion = sec.Key("TLS_MIN_VERSION").String()
10 years ago
} else if sec.Key("PROTOCOL").String() == "fcgi" {
Protocol = SCHEME_FCGI
} else if sec.Key("PROTOCOL").String() == "unix" {
Protocol = SCHEME_UNIX_SOCKET
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
if err != nil || UnixSocketPermissionParsed > 0777 {
log.Fatal(2, "Fail to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
}
UnixSocketPermission = uint32(UnixSocketPermissionParsed)
}
10 years ago
Domain = sec.Key("DOMAIN").MustString("localhost")
HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/")
10 years ago
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
10 years ago
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
switch sec.Key("LANDING_PAGE").MustString("home") {
10 years ago
case "explore":
LandingPageURL = LANDING_PAGE_EXPLORE
10 years ago
default:
LandingPageURL = LANDING_PAGE_HOME
10 years ago
}
SSH.RootPath = path.Join(homeDir, ".ssh")
SSH.RewriteAuthorizedKeysAtStart = sec.Key("REWRITE_AUTHORIZED_KEYS_AT_START").MustBool()
SSH.ServerCiphers = sec.Key("SSH_SERVER_CIPHERS").Strings(",")
SSH.KeyTestPath = os.TempDir()
if err = Cfg.Section("server").MapTo(&SSH); err != nil {
log.Fatal(2, "Fail to map SSH settings: %v", err)
}
if SSH.Disabled {
SSH.StartBuiltinServer = false
SSH.MinimumKeySizeCheck = false
}
if !SSH.Disabled && !SSH.StartBuiltinServer {
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
log.Fatal(2, "Fail to create '%s': %v", SSH.RootPath, err)
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
log.Fatal(2, "Fail to create '%s': %v", SSH.KeyTestPath, err)
}
}
if SSH.StartBuiltinServer {
SSH.RewriteAuthorizedKeysAtStart = false
}
// Check if server is eligible for minimum key size check when user choose to enable.
// Windows server and OpenSSH version lower than 5.1 (https://github.com/gogs/gogs/issues/4507)
// are forced to be disabled because the "ssh-keygen" in Windows does not print key type.
if SSH.MinimumKeySizeCheck &&
(IsWindows || version.Compare(getOpenSSHVersion(), "5.1", "<")) {
SSH.MinimumKeySizeCheck = false
log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
1. Windows server
2. OpenSSH version is lower than 5.1`)
}
if SSH.MinimumKeySizeCheck {
SSH.MinimumKeySizes = map[string]int{}
for _, key := range Cfg.Section("ssh.minimum_key_sizes").Keys() {
if key.MustInt() != -1 {
SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt()
}
}
}
10 years ago
sec = Cfg.Section("security")
InstallLock = sec.Key("INSTALL_LOCK").MustBool()
SecretKey = sec.Key("SECRET_KEY").String()
LoginRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
10 years ago
CookieUserName = sec.Key("COOKIE_USERNAME").String()
CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
10 years ago
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
EnableLoginStatusCookie = sec.Key("ENABLE_LOGIN_STATUS_COOKIE").MustBool(false)
LoginStatusCookieName = sec.Key("LOGIN_STATUS_COOKIE_NAME").MustString("login_status")
10 years ago
sec = Cfg.Section("attachment")
AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
if !filepath.IsAbs(AttachmentPath) {
AttachmentPath = path.Join(workDir, AttachmentPath)
}
AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4)
AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5)
AttachmentEnabled = sec.Key("ENABLED").MustBool(true)
TimeFormat = map[string]string{
"ANSIC": time.ANSIC,
"UnixDate": time.UnixDate,
"RubyDate": time.RubyDate,
"RFC822": time.RFC822,
"RFC822Z": time.RFC822Z,
"RFC850": time.RFC850,
"RFC1123": time.RFC1123,
"RFC1123Z": time.RFC1123Z,
"RFC3339": time.RFC3339,
"RFC3339Nano": time.RFC3339Nano,
"Kitchen": time.Kitchen,
"Stamp": time.Stamp,
"StampMilli": time.StampMilli,
"StampMicro": time.StampMicro,
"StampNano": time.StampNano,
10 years ago
}[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
10 years ago
RunUser = Cfg.Section("").Key("RUN_USER").String()
11 years ago
// Does not check run user when the install lock is off.
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
if !match {
log.Fatal(2, "Expect user '%s' but current user is: %s", RunUser, currentUser)
}
11 years ago
}
ProdMode = Cfg.Section("").Key("RUN_MODE").String() == "prod"
// Determine and create root git repository path.
10 years ago
sec = Cfg.Section("repository")
RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
forcePathSeparator(RepoRootPath)
if !filepath.IsAbs(RepoRootPath) {
RepoRootPath = path.Join(workDir, RepoRootPath)
} else {
RepoRootPath = path.Clean(RepoRootPath)
}
10 years ago
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
log.Fatal(2, "Fail to map Repository settings: %v", err)
} else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
log.Fatal(2, "Fail to map Repository.Editor settings: %v", err)
} else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
log.Fatal(2, "Fail to map Repository.Upload settings: %v", err)
}
11 years ago
if !filepath.IsAbs(Repository.Upload.TempPath) {
Repository.Upload.TempPath = path.Join(workDir, Repository.Upload.TempPath)
Squashed commit of the following: commit 0afcb843d7ffd596991c4885cab768273a6eb42c Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 17:13:29 2016 -0600 Removed Upload stats as the upload table is just a temporary table commit 7ecd73ff5535612d79d471409173ee7f1fcfa157 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 08:42:41 2016 -0600 Fix for CodeMirror mode commit c29b9ab531e2e7af0fb5db24dc17e51027dd1174 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 08:03:33 2016 -0600 Made tabbing in editor use spaces commit 23af384c53206a8a40e11e45bf49d7a149c4adcd Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:56:46 2016 -0600 Fix for data-url commit cfb8a97591cb6fc0a92e49563b7b764c524db0e9 Merge: 7fc8a89 991ce42 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:42:53 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go public/js/gogs.js commit 7fc8a89cb495478225b02d613e647f99a1489634 Merge: fd3d86c c03d040 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:40:00 2016 -0600 Merge branch 'feature-create-and-edit-repo-file' of github.com:richmahn/gogs into feature-create-and-edit-repo-file commit fd3d86ca6bbc02cfda566a504ffd6b03db4f75ef Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Sun Jul 31 07:39:44 2016 -0600 Code cleanup commit c03d0401c1049eeeccc32ab1f9c3303c130be5ee Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 29 15:38:23 2016 -0600 Code cleanup commit 98e1206ccf9f9a4503c020e3a7830cf9f861dfae Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 18:36:01 2016 -0600 Code cleanup and fixes commit c2895dc742f25f8412879c9fa15e18f27f42f194 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 18:24:04 2016 -0600 Fixes per Unknwon's requests commit 6aa7e46b21ad4c96e562daa2eac26a8fb408f8ef Merge: 889e9fa ad7ea88 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Thu Jul 28 17:13:43 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go modules/setting/setting.go commit 889e9faf1bd8559a4979c8f46005d488c1a234d4 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:09:18 2016 -0600 Fix in gogs.js commit 47603edf223f147b114be65f3bd27bc1e88827a5 Merge: bb57912 cf85e9e Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:07:36 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go public/js/gogs.js commit bb5791255867a71c11a77b639db050ad09c597a4 Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 22 14:02:18 2016 -0600 Update for using CodeMirror mode addon commit d10d128c51039be19e2af9c66c63db66a9f2ec6d Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Tue Jul 19 16:12:57 2016 -0600 Update for Edit commit 34a34982025144e3225e389f7849eb6273c1d576 Merge: fa1b752 1c7dcdd Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Tue Jul 19 11:52:02 2016 -0600 Merge remote-tracking branch 'gogits/develop' into feature-create-and-edit-repo-file Conflicts: modules/bindata/bindata.go commit fa1b752be29cd455c5184ddac2ffe80b3489763e Author: Richard Mahn <richard_mahn@wycliffeassociates.org> Date: Fri Jul 15 18:35:42 2016 -0600 Feature for editing, creating, uploading and deleting files
9 years ago
}
10 years ago
sec = Cfg.Section("picture")
AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars"))
forcePathSeparator(AvatarUploadPath)
if !filepath.IsAbs(AvatarUploadPath) {
AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
}
repo: support avatars (#5221) * First code for repository avatars * Last code for repository avatars - add new option for repo avatars location on filesystem - add route catch in web - add new fields to repo model - add migration - update settings handlers - update repo header template * Update locale messages * Add repo avatars to home page * Add repo avatars to organization right panel * Show repo avatars in repo list * Remove AvatarEamil field, remove Gravatar support, use generic locale messages * Fix migration * Fix seed and not used tool * Revert public css changes, add them to less files * Latest lessc (2.6.0) don't put result into file but output to stdout So redirect output to file * Simplify things: - migration don't needed, and table changes too - just upload file to repo avatar storage - or generate random image * Fix repo image seed - name not unique * Get rid of not needed model fields * Class value is enough, remove height attribute * Don't generate random avatar for repository - use html and semantic ui icons if no avatar found * Update styles and templates for repo - use repo icon as default avatar - use globe icon for public repos - add micro style for repo avatars at dashboard * Remvoe redundant empty line * Fix nl2br filter - must return string * Fix css style for micro-repo-avatar in dashboard list * Remove `|len`, works fine w/o it. * Update after review 2: - use static route for repository avatar - format images settings block in settings * Update after review 2: - no random avatar for repo * Update after review 2: - no random avatar for repo 2 - update imports - update UploadAvatar* functions * Update after review 2: - update templates * Fix trace call * Remove unused immport since we use static route for repo avatars.
7 years ago
RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "repo-avatars"))
forcePathSeparator(RepositoryAvatarUploadPath)
if !filepath.IsAbs(RepositoryAvatarUploadPath) {
RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath)
}
switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
case "duoshuo":
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
case "gravatar":
GravatarSource = "https://secure.gravatar.com/avatar/"
case "libravatar":
GravatarSource = "https://seccdn.libravatar.org/avatar/"
default:
GravatarSource = source
}
10 years ago
DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true)
if OfflineMode {
DisableGravatar = true
Add support for federated avatars (#3320) * Add support for federated avatars Fixes #3105 Removes avatar fetching duplication code Adds an "Enable Federated Avatar" checkbox in user settings (defaults to unchecked) Moves avatar settings all in the same form, making local and remote avatars mutually exclusive Renames UploadAvatarForm to AvatarForm as it's not anymore only for uploading * Run gofmt on all modified files * Move Avatar form in its own page * Add go-libravatar dependency to vendor/ dir Hopefully helps with accepting the contribution. See also #3214 * Revert "Add go-libravatar dependency to vendor/ dir" This reverts commit a8cb93ae640bbb90f7d25012fc257bda9fae9b82. * Make federated avatar setting a global configuration Removes the per-user setting * Move avatar handling back to base tool, disable federated avatar in offline mode * Format, handle error * Properly set fallback host * Use unsupported github.com mirror for importing go-libravatar * Remove comment showing life exists outside of github.com ... pity, but contribution would not be accepted otherwise * Use Combo for Get and Post methods over /avatar * FEDERATED_AVATAR -> ENABLE_FEDERATED_AVATAR * Fix persistance of federated avatar lookup checkbox at install time * Federated Avatars -> Enable Federated Avatars * Use len(string) == 0 instead of string == "" * Move import line where it belong See https://github.com/Unknwon/go-code-convention/blob/master/en-US/import_packages.md Pity the import url is still the unofficial one, but oh well... * Save a line (and waste much more expensive time) * Remove redundant parens * Remove an empty line * Remove empty lines * Reorder lines to make diff smaller * Remove another newline Unknwon review got me start a fight against newlines * Move DISABLE_GRAVATAR and ENABLE_FEDERATED_AVATAR after OFFLINE_MODE On re-reading the diff I figured what Unknwon meant here: https://github.com/gogits/gogs/pull/3320/files#r73741106 * Remove newlines that weren't there before my intervention
9 years ago
EnableFederatedAvatar = false
}
if DisableGravatar {
EnableFederatedAvatar = false
}
Add support for federated avatars (#3320) * Add support for federated avatars Fixes #3105 Removes avatar fetching duplication code Adds an "Enable Federated Avatar" checkbox in user settings (defaults to unchecked) Moves avatar settings all in the same form, making local and remote avatars mutually exclusive Renames UploadAvatarForm to AvatarForm as it's not anymore only for uploading * Run gofmt on all modified files * Move Avatar form in its own page * Add go-libravatar dependency to vendor/ dir Hopefully helps with accepting the contribution. See also #3214 * Revert "Add go-libravatar dependency to vendor/ dir" This reverts commit a8cb93ae640bbb90f7d25012fc257bda9fae9b82. * Make federated avatar setting a global configuration Removes the per-user setting * Move avatar handling back to base tool, disable federated avatar in offline mode * Format, handle error * Properly set fallback host * Use unsupported github.com mirror for importing go-libravatar * Remove comment showing life exists outside of github.com ... pity, but contribution would not be accepted otherwise * Use Combo for Get and Post methods over /avatar * FEDERATED_AVATAR -> ENABLE_FEDERATED_AVATAR * Fix persistance of federated avatar lookup checkbox at install time * Federated Avatars -> Enable Federated Avatars * Use len(string) == 0 instead of string == "" * Move import line where it belong See https://github.com/Unknwon/go-code-convention/blob/master/en-US/import_packages.md Pity the import url is still the unofficial one, but oh well... * Save a line (and waste much more expensive time) * Remove redundant parens * Remove an empty line * Remove empty lines * Reorder lines to make diff smaller * Remove another newline Unknwon review got me start a fight against newlines * Move DISABLE_GRAVATAR and ENABLE_FEDERATED_AVATAR after OFFLINE_MODE On re-reading the diff I figured what Unknwon meant here: https://github.com/gogits/gogs/pull/3320/files#r73741106 * Remove newlines that weren't there before my intervention
9 years ago
if EnableFederatedAvatar {
Add support for federated avatars (#3320) * Add support for federated avatars Fixes #3105 Removes avatar fetching duplication code Adds an "Enable Federated Avatar" checkbox in user settings (defaults to unchecked) Moves avatar settings all in the same form, making local and remote avatars mutually exclusive Renames UploadAvatarForm to AvatarForm as it's not anymore only for uploading * Run gofmt on all modified files * Move Avatar form in its own page * Add go-libravatar dependency to vendor/ dir Hopefully helps with accepting the contribution. See also #3214 * Revert "Add go-libravatar dependency to vendor/ dir" This reverts commit a8cb93ae640bbb90f7d25012fc257bda9fae9b82. * Make federated avatar setting a global configuration Removes the per-user setting * Move avatar handling back to base tool, disable federated avatar in offline mode * Format, handle error * Properly set fallback host * Use unsupported github.com mirror for importing go-libravatar * Remove comment showing life exists outside of github.com ... pity, but contribution would not be accepted otherwise * Use Combo for Get and Post methods over /avatar * FEDERATED_AVATAR -> ENABLE_FEDERATED_AVATAR * Fix persistance of federated avatar lookup checkbox at install time * Federated Avatars -> Enable Federated Avatars * Use len(string) == 0 instead of string == "" * Move import line where it belong See https://github.com/Unknwon/go-code-convention/blob/master/en-US/import_packages.md Pity the import url is still the unofficial one, but oh well... * Save a line (and waste much more expensive time) * Remove redundant parens * Remove an empty line * Remove empty lines * Reorder lines to make diff smaller * Remove another newline Unknwon review got me start a fight against newlines * Move DISABLE_GRAVATAR and ENABLE_FEDERATED_AVATAR after OFFLINE_MODE On re-reading the diff I figured what Unknwon meant here: https://github.com/gogits/gogs/pull/3320/files#r73741106 * Remove newlines that weren't there before my intervention
9 years ago
LibravatarService = libravatar.New()
parts := strings.Split(GravatarSource, "/")
if len(parts) >= 3 {
if parts[0] == "https:" {
LibravatarService.SetUseHTTPS(true)
LibravatarService.SetSecureFallbackHost(parts[2])
} else {
LibravatarService.SetUseHTTPS(false)
LibravatarService.SetFallbackHost(parts[2])
}
}
}
if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
log.Fatal(2, "Failed to map HTTP settings: %v", err)
} else if err = Cfg.Section("webhook").MapTo(&Webhook); err != nil {
log.Fatal(2, "Failed to map Webhook settings: %v", err)
} else if err = Cfg.Section("release.attachment").MapTo(&Release.Attachment); err != nil {
log.Fatal(2, "Failed to map Release.Attachment settings: %v", err)
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
log.Fatal(2, "Failed to map Markdown settings: %v", err)
} else if err = Cfg.Section("smartypants").MapTo(&Smartypants); err != nil {
log.Fatal(2, "Failed to map Smartypants settings: %v", err)
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
log.Fatal(2, "Failed to map Admin settings: %v", err)
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil {
log.Fatal(2, "Failed to map Cron settings: %v", err)
} else if err = Cfg.Section("git").MapTo(&Git); err != nil {
log.Fatal(2, "Failed to map Git settings: %v", err)
} else if err = Cfg.Section("mirror").MapTo(&Mirror); err != nil {
log.Fatal(2, "Failed to map Mirror settings: %v", err)
} else if err = Cfg.Section("api").MapTo(&API); err != nil {
log.Fatal(2, "Failed to map API settings: %v", err)
} else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
log.Fatal(2, "Failed to map UI settings: %v", err)
} else if err = Cfg.Section("prometheus").MapTo(&Prometheus); err != nil {
log.Fatal(2, "Failed to map Prometheus settings: %v", err)
}
if Mirror.DefaultInterval <= 0 {
Mirror.DefaultInterval = 24
}
10 years ago
Langs = Cfg.Section("i18n").Key("LANGS").Strings(",")
Names = Cfg.Section("i18n").Key("NAMES").Strings(",")
dateLangs = Cfg.Section("i18n.datelang").KeysHash()
ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool()
ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool()
ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool()
HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
11 years ago
}
11 years ago
var Service struct {
ActiveCodeLives int
ResetPwdCodeLives int
10 years ago
RegisterEmailConfirm bool
DisableRegistration bool
ShowRegistrationButton bool
10 years ago
RequireSignInView bool
EnableNotifyMail bool
EnableReverseProxyAuth bool
EnableReverseProxyAutoRegister bool
EnableCaptcha bool
11 years ago
}
11 years ago
func newService() {
sec := Cfg.Section("service")
Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
11 years ago
}
func newLogService() {
9 years ago
if len(BuildTime) > 0 {
log.Trace("Build Time: %s", BuildTime)
log.Trace("Build Git Hash: %s", BuildGitHash)
9 years ago
}
// Because we always create a console logger as primary logger before all settings are loaded,
// thus if user doesn't set console logger, we should remove it after other loggers are created.
hasConsole := false
// Get and check log modes.
10 years ago
LogModes = strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",")
LogConfigs = make([]interface{}, len(LogModes))
levelNames := map[string]log.LEVEL{
"trace": log.TRACE,
"info": log.INFO,
"warn": log.WARN,
"error": log.ERROR,
"fatal": log.FATAL,
}
for i, mode := range LogModes {
mode = strings.ToLower(strings.TrimSpace(mode))
10 years ago
sec, err := Cfg.GetSection("log." + mode)
if err != nil {
log.Fatal(2, "Unknown logger mode: %s", mode)
}
validLevels := []string{"trace", "info", "warn", "error", "fatal"}
name := Cfg.Section("log." + mode).Key("LEVEL").Validate(func(v string) string {
v = strings.ToLower(v)
if com.IsSliceContainsStr(validLevels, v) {
return v
}
return "trace"
})
level := levelNames[name]
// Generate log configuration.
switch log.MODE(mode) {
case log.CONSOLE:
hasConsole = true
LogConfigs[i] = log.ConsoleConfig{
Level: level,
BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
}
case log.FILE:
logPath := path.Join(LogRootPath, "gogs.log")
if err = os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
log.Fatal(2, "Fail to create log directory '%s': %v", path.Dir(logPath), err)
}
LogConfigs[i] = log.FileConfig{
Level: level,
BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
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),
},
}
case log.SLACK:
LogConfigs[i] = log.SlackConfig{
Level: level,
BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
URL: sec.Key("URL").String(),
}
case log.DISCORD:
LogConfigs[i] = log.DiscordConfig{
Level: level,
BufferSize: Cfg.Section("log").Key("BUFFER_LEN").MustInt64(100),
URL: sec.Key("URL").String(),
Username: sec.Key("USERNAME").String(),
}
}
log.New(log.MODE(mode), LogConfigs[i])
log.Trace("Log Mode: %s (%s)", strings.Title(mode), strings.Title(name))
}
// Make sure everyone gets version info printed.
log.Info("%s %s", AppName, AppVer)
if !hasConsole {
log.Delete(log.CONSOLE)
11 years ago
}
}
func newCacheService() {
10 years ago
CacheAdapter = Cfg.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
11 years ago
switch CacheAdapter {
case "memory":
CacheInterval = Cfg.Section("cache").Key("INTERVAL").MustInt(60)
11 years ago
case "redis", "memcache":
10 years ago
CacheConn = strings.Trim(Cfg.Section("cache").Key("HOST").String(), "\" ")
11 years ago
default:
log.Fatal(2, "Unknown cache adapter: %s", CacheAdapter)
11 years ago
}
log.Info("Cache Service Enabled")
}
func newSessionService() {
10 years ago
SessionConfig.Provider = Cfg.Section("session").Key("PROVIDER").In("memory",
[]string{"memory", "file", "redis", "mysql"})
10 years ago
SessionConfig.ProviderConfig = strings.Trim(Cfg.Section("session").Key("PROVIDER_CONFIG").String(), "\" ")
SessionConfig.CookieName = Cfg.Section("session").Key("COOKIE_NAME").MustString("i_like_gogs")
SessionConfig.CookiePath = AppSubURL
10 years ago
SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(3600)
10 years ago
SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
11 years ago
log.Info("Session Service Enabled")
}
11 years ago
// Mailer represents mail service.
type Mailer struct {
QueueLength int
SubjectPrefix string
Host string
From string
FromEmail string
User, Passwd string
DisableHelo bool
HeloHostname string
SkipVerify bool
UseCertificate bool
CertFile, KeyFile string
UsePlainText bool
11 years ago
}
var (
MailService *Mailer
11 years ago
)
// newMailService initializes mail service options from configuration.
// No non-error log will be printed in hook mode.
11 years ago
func newMailService() {
10 years ago
sec := Cfg.Section("mailer")
if !sec.Key("ENABLED").MustBool() {
11 years ago
return
}
MailService = &Mailer{
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString("[" + AppName + "] "),
Host: sec.Key("HOST").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
CertFile: sec.Key("CERT_FILE").String(),
KeyFile: sec.Key("KEY_FILE").String(),
UsePlainText: sec.Key("USE_PLAIN_TEXT").MustBool(),
11 years ago
}
10 years ago
MailService.From = sec.Key("FROM").MustString(MailService.User)
if len(MailService.From) > 0 {
parsed, err := mail.ParseAddress(MailService.From)
if err != nil {
log.Fatal(2, "Invalid mailer.FROM (%s): %v", MailService.From, err)
}
MailService.FromEmail = parsed.Address
}
if HookMode {
return
}
11 years ago
log.Info("Mail Service Enabled")
}
func newRegisterMailService() {
10 years ago
if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
11 years ago
return
} else if MailService == nil {
log.Warn("Register Mail Service: Mail Service is not enabled")
return
}
Service.RegisterEmailConfirm = true
log.Info("Register Mail Service Enabled")
}
// newNotifyMailService initializes notification email service options from configuration.
// No non-error log will be printed in hook mode.
11 years ago
func newNotifyMailService() {
10 years ago
if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
11 years ago
return
} else if MailService == nil {
log.Warn("Notify Mail Service: Mail Service is not enabled")
return
}
11 years ago
Service.EnableNotifyMail = true
if HookMode {
return
}
11 years ago
log.Info("Notify Mail Service Enabled")
}
func NewService() {
newService()
}
11 years ago
func NewServices() {
11 years ago
newService()
newLogService()
newCacheService()
newSessionService()
newMailService()
newRegisterMailService()
newNotifyMailService()
}
// HookMode indicates whether program starts as Git server-side hook callback.
var HookMode bool
// NewPostReceiveHookServices initializes all services that are needed by
// Git server-side post-receive hook callback.
func NewPostReceiveHookServices() {
HookMode = true
newService()
newMailService()
newNotifyMailService()
}