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.

385 lines
12 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
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
8 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
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
8 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package routers
  5. import (
  6. "errors"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "github.com/Unknwon/com"
  13. "github.com/go-xorm/xorm"
  14. "gopkg.in/ini.v1"
  15. "gopkg.in/macaron.v1"
  16. "github.com/go-gitea/git"
  17. "github.com/go-gitea/gitea/models"
  18. "github.com/go-gitea/gitea/modules/auth"
  19. "github.com/go-gitea/gitea/modules/base"
  20. "github.com/go-gitea/gitea/modules/context"
  21. "github.com/go-gitea/gitea/modules/cron"
  22. "github.com/go-gitea/gitea/modules/log"
  23. "github.com/go-gitea/gitea/modules/mailer"
  24. "github.com/go-gitea/gitea/modules/markdown"
  25. "github.com/go-gitea/gitea/modules/setting"
  26. "github.com/go-gitea/gitea/modules/ssh"
  27. "github.com/go-gitea/gitea/modules/template/highlight"
  28. "github.com/go-gitea/gitea/modules/user"
  29. )
  30. const (
  31. INSTALL base.TplName = "install"
  32. )
  33. func checkRunMode() {
  34. switch setting.Cfg.Section("").Key("RUN_MODE").String() {
  35. case "prod":
  36. macaron.Env = macaron.PROD
  37. macaron.ColorLog = false
  38. setting.ProdMode = true
  39. default:
  40. git.Debug = true
  41. }
  42. log.Info("Run Mode: %s", strings.Title(macaron.Env))
  43. }
  44. func NewServices() {
  45. setting.NewServices()
  46. mailer.NewContext()
  47. }
  48. // GlobalInit is for global configuration reload-able.
  49. func GlobalInit() {
  50. setting.NewContext()
  51. log.Trace("Custom path: %s", setting.CustomPath)
  52. log.Trace("Log path: %s", setting.LogRootPath)
  53. models.LoadConfigs()
  54. NewServices()
  55. if setting.InstallLock {
  56. highlight.NewContext()
  57. markdown.BuildSanitizer()
  58. if err := models.NewEngine(); err != nil {
  59. log.Fatal(4, "Fail to initialize ORM engine: %v", err)
  60. }
  61. models.HasEngine = true
  62. models.LoadRepoConfig()
  63. models.NewRepoContext()
  64. // Booting long running goroutines.
  65. cron.NewContext()
  66. models.InitSyncMirrors()
  67. models.InitDeliverHooks()
  68. models.InitTestPullRequests()
  69. log.NewGitLogger(path.Join(setting.LogRootPath, "http.log"))
  70. }
  71. if models.EnableSQLite3 {
  72. log.Info("SQLite3 Supported")
  73. }
  74. if models.EnableTiDB {
  75. log.Info("TiDB Supported")
  76. }
  77. if setting.SupportMiniWinService {
  78. log.Info("Builtin Windows Service Supported")
  79. }
  80. checkRunMode()
  81. if setting.InstallLock && setting.SSH.StartBuiltinServer {
  82. ssh.Listen(setting.SSH.ListenPort)
  83. log.Info("SSH server started on :%v", setting.SSH.ListenPort)
  84. }
  85. }
  86. func InstallInit(ctx *context.Context) {
  87. if setting.InstallLock {
  88. ctx.Handle(404, "Install", errors.New("Installation is prohibited"))
  89. return
  90. }
  91. ctx.Data["Title"] = ctx.Tr("install.install")
  92. ctx.Data["PageIsInstall"] = true
  93. dbOpts := []string{"MySQL", "PostgreSQL"}
  94. if models.EnableSQLite3 {
  95. dbOpts = append(dbOpts, "SQLite3")
  96. }
  97. if models.EnableTiDB {
  98. dbOpts = append(dbOpts, "TiDB")
  99. }
  100. ctx.Data["DbOptions"] = dbOpts
  101. }
  102. func Install(ctx *context.Context) {
  103. form := auth.InstallForm{}
  104. // Database settings
  105. form.DbHost = models.DbCfg.Host
  106. form.DbUser = models.DbCfg.User
  107. form.DbName = models.DbCfg.Name
  108. form.DbPath = models.DbCfg.Path
  109. ctx.Data["CurDbOption"] = "MySQL"
  110. switch models.DbCfg.Type {
  111. case "postgres":
  112. ctx.Data["CurDbOption"] = "PostgreSQL"
  113. case "sqlite3":
  114. if models.EnableSQLite3 {
  115. ctx.Data["CurDbOption"] = "SQLite3"
  116. }
  117. case "tidb":
  118. if models.EnableTiDB {
  119. ctx.Data["CurDbOption"] = "TiDB"
  120. }
  121. }
  122. // Application general settings
  123. form.AppName = setting.AppName
  124. form.RepoRootPath = setting.RepoRootPath
  125. // Note(unknwon): it's hard for Windows users change a running user,
  126. // so just use current one if config says default.
  127. if setting.IsWindows && setting.RunUser == "git" {
  128. form.RunUser = user.CurrentUsername()
  129. } else {
  130. form.RunUser = setting.RunUser
  131. }
  132. form.Domain = setting.Domain
  133. form.SSHPort = setting.SSH.Port
  134. form.HTTPPort = setting.HTTPPort
  135. form.AppUrl = setting.AppUrl
  136. form.LogRootPath = setting.LogRootPath
  137. // E-mail service settings
  138. if setting.MailService != nil {
  139. form.SMTPHost = setting.MailService.Host
  140. form.SMTPFrom = setting.MailService.From
  141. form.SMTPEmail = setting.MailService.User
  142. }
  143. form.RegisterConfirm = setting.Service.RegisterEmailConfirm
  144. form.MailNotify = setting.Service.EnableNotifyMail
  145. // Server and other services settings
  146. form.OfflineMode = setting.OfflineMode
  147. form.DisableGravatar = setting.DisableGravatar
  148. form.EnableFederatedAvatar = setting.EnableFederatedAvatar
  149. form.DisableRegistration = setting.Service.DisableRegistration
  150. form.EnableCaptcha = setting.Service.EnableCaptcha
  151. form.RequireSignInView = setting.Service.RequireSignInView
  152. auth.AssignForm(form, ctx.Data)
  153. ctx.HTML(200, INSTALL)
  154. }
  155. func InstallPost(ctx *context.Context, form auth.InstallForm) {
  156. ctx.Data["CurDbOption"] = form.DbType
  157. if ctx.HasError() {
  158. if ctx.HasValue("Err_SMTPEmail") {
  159. ctx.Data["Err_SMTP"] = true
  160. }
  161. if ctx.HasValue("Err_AdminName") ||
  162. ctx.HasValue("Err_AdminPasswd") ||
  163. ctx.HasValue("Err_AdminEmail") {
  164. ctx.Data["Err_Admin"] = true
  165. }
  166. ctx.HTML(200, INSTALL)
  167. return
  168. }
  169. if _, err := exec.LookPath("git"); err != nil {
  170. ctx.RenderWithErr(ctx.Tr("install.test_git_failed", err), INSTALL, &form)
  171. return
  172. }
  173. // Pass basic check, now test configuration.
  174. // Test database setting.
  175. dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3", "TiDB": "tidb"}
  176. models.DbCfg.Type = dbTypes[form.DbType]
  177. models.DbCfg.Host = form.DbHost
  178. models.DbCfg.User = form.DbUser
  179. models.DbCfg.Passwd = form.DbPasswd
  180. models.DbCfg.Name = form.DbName
  181. models.DbCfg.SSLMode = form.SSLMode
  182. models.DbCfg.Path = form.DbPath
  183. if (models.DbCfg.Type == "sqlite3" || models.DbCfg.Type == "tidb") &&
  184. len(models.DbCfg.Path) == 0 {
  185. ctx.Data["Err_DbPath"] = true
  186. ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), INSTALL, &form)
  187. return
  188. } else if models.DbCfg.Type == "tidb" &&
  189. strings.ContainsAny(path.Base(models.DbCfg.Path), ".-") {
  190. ctx.Data["Err_DbPath"] = true
  191. ctx.RenderWithErr(ctx.Tr("install.err_invalid_tidb_name"), INSTALL, &form)
  192. return
  193. }
  194. // Set test engine.
  195. var x *xorm.Engine
  196. if err := models.NewTestEngine(x); err != nil {
  197. if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
  198. ctx.Data["Err_DbType"] = true
  199. ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form)
  200. } else {
  201. ctx.Data["Err_DbSetting"] = true
  202. ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), INSTALL, &form)
  203. }
  204. return
  205. }
  206. // Test repository root path.
  207. form.RepoRootPath = strings.Replace(form.RepoRootPath, "\\", "/", -1)
  208. if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
  209. ctx.Data["Err_RepoRootPath"] = true
  210. ctx.RenderWithErr(ctx.Tr("install.invalid_repo_path", err), INSTALL, &form)
  211. return
  212. }
  213. // Test log root path.
  214. form.LogRootPath = strings.Replace(form.LogRootPath, "\\", "/", -1)
  215. if err := os.MkdirAll(form.LogRootPath, os.ModePerm); err != nil {
  216. ctx.Data["Err_LogRootPath"] = true
  217. ctx.RenderWithErr(ctx.Tr("install.invalid_log_root_path", err), INSTALL, &form)
  218. return
  219. }
  220. currentUser, match := setting.IsRunUserMatchCurrentUser(form.RunUser)
  221. if !match {
  222. ctx.Data["Err_RunUser"] = true
  223. ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, currentUser), INSTALL, &form)
  224. return
  225. }
  226. // Check logic loophole between disable self-registration and no admin account.
  227. if form.DisableRegistration && len(form.AdminName) == 0 {
  228. ctx.Data["Err_Services"] = true
  229. ctx.Data["Err_Admin"] = true
  230. ctx.RenderWithErr(ctx.Tr("install.no_admin_and_disable_registration"), INSTALL, form)
  231. return
  232. }
  233. // Check admin password.
  234. if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 {
  235. ctx.Data["Err_Admin"] = true
  236. ctx.Data["Err_AdminPasswd"] = true
  237. ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), INSTALL, form)
  238. return
  239. }
  240. if form.AdminPasswd != form.AdminConfirmPasswd {
  241. ctx.Data["Err_Admin"] = true
  242. ctx.Data["Err_AdminPasswd"] = true
  243. ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form)
  244. return
  245. }
  246. if form.AppUrl[len(form.AppUrl)-1] != '/' {
  247. form.AppUrl += "/"
  248. }
  249. // Save settings.
  250. cfg := ini.Empty()
  251. if com.IsFile(setting.CustomConf) {
  252. // Keeps custom settings if there is already something.
  253. if err := cfg.Append(setting.CustomConf); err != nil {
  254. log.Error(4, "Fail to load custom conf '%s': %v", setting.CustomConf, err)
  255. }
  256. }
  257. cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
  258. cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
  259. cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
  260. cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
  261. cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
  262. cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
  263. cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
  264. cfg.Section("").Key("APP_NAME").SetValue(form.AppName)
  265. cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
  266. cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
  267. cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
  268. cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort)
  269. cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
  270. if form.SSHPort == 0 {
  271. cfg.Section("server").Key("DISABLE_SSH").SetValue("true")
  272. } else {
  273. cfg.Section("server").Key("DISABLE_SSH").SetValue("false")
  274. cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(form.SSHPort))
  275. }
  276. if len(strings.TrimSpace(form.SMTPHost)) > 0 {
  277. cfg.Section("mailer").Key("ENABLED").SetValue("true")
  278. cfg.Section("mailer").Key("HOST").SetValue(form.SMTPHost)
  279. cfg.Section("mailer").Key("FROM").SetValue(form.SMTPFrom)
  280. cfg.Section("mailer").Key("USER").SetValue(form.SMTPEmail)
  281. cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd)
  282. } else {
  283. cfg.Section("mailer").Key("ENABLED").SetValue("false")
  284. }
  285. cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm))
  286. cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify))
  287. cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(form.OfflineMode))
  288. cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(form.DisableGravatar))
  289. cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(form.EnableFederatedAvatar))
  290. cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration))
  291. cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha))
  292. cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView))
  293. cfg.Section("").Key("RUN_MODE").SetValue("prod")
  294. cfg.Section("session").Key("PROVIDER").SetValue("file")
  295. cfg.Section("log").Key("MODE").SetValue("file")
  296. cfg.Section("log").Key("LEVEL").SetValue("Info")
  297. cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath)
  298. cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
  299. cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
  300. os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
  301. if err := cfg.SaveTo(setting.CustomConf); err != nil {
  302. ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form)
  303. return
  304. }
  305. GlobalInit()
  306. // Create admin account
  307. if len(form.AdminName) > 0 {
  308. u := &models.User{
  309. Name: form.AdminName,
  310. Email: form.AdminEmail,
  311. Passwd: form.AdminPasswd,
  312. IsAdmin: true,
  313. IsActive: true,
  314. }
  315. if err := models.CreateUser(u); err != nil {
  316. if !models.IsErrUserAlreadyExist(err) {
  317. setting.InstallLock = false
  318. ctx.Data["Err_AdminName"] = true
  319. ctx.Data["Err_AdminEmail"] = true
  320. ctx.RenderWithErr(ctx.Tr("install.invalid_admin_setting", err), INSTALL, &form)
  321. return
  322. }
  323. log.Info("Admin account already exist")
  324. u, _ = models.GetUserByName(u.Name)
  325. }
  326. // Auto-login for admin
  327. ctx.Session.Set("uid", u.ID)
  328. ctx.Session.Set("uname", u.Name)
  329. }
  330. log.Info("First-time run install finished!")
  331. ctx.Flash.Success(ctx.Tr("install.install_success"))
  332. ctx.Redirect(form.AppUrl + "user/login")
  333. }