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.

account.go 11KB

Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
3 years ago
Refactor: Move login out of models (#16199) `models` does far too much. In particular it handles all `UserSignin`. It shouldn't be responsible for calling LDAP, SMTP or PAM for signing in. Therefore we should move this code out of `models`. This code has to depend on `models` - therefore it belongs in `services`. There is a package in `services` called `auth` and clearly this functionality belongs in there. Plan: - [x] Change `auth.Auth` to `auth.Method` - as they represent methods of authentication. - [x] Move `models.UserSignIn` into `auth` - [x] Move `models.ExternalUserLogin` - [x] Move most of the `LoginVia*` methods to `auth` or subpackages - [x] Move Resynchronize functionality to `auth` - Involved some restructuring of `models/ssh_key.go` to reduce the size of this massive file and simplify its files. - [x] Move the rest of the LDAP functionality in to the ldap subpackage - [x] Re-factor the login sources to express an interfaces `auth.Source`? - I've done this through some smaller interfaces Authenticator and Synchronizable - which would allow us to extend things in future - [x] Now LDAP is out of models - need to think about modules/auth/ldap and I think all of that functionality might just be moveable - [x] Similarly a lot Oauth2 functionality need not be in models too and should be moved to services/auth/source/oauth2 - [x] modules/auth/oauth2/oauth2.go uses xorm... This is naughty - probably need to move this into models. - [x] models/oauth2.go - mostly should be in modules/auth/oauth2 or services/auth/source/oauth2 - [x] More simplifications of login_source.go may need to be done - Allow wiring in of notify registration - *this can now easily be done - but I think we should do it in another PR* - see #16178 - More refactors...? - OpenID should probably become an auth Method but I think that can be left for another PR - Methods should also probably be cleaned up - again another PR I think. - SSPI still needs more refactors.* Rename auth.Auth auth.Method * Restructure ssh_key.go - move functions from models/user.go that relate to ssh_key to ssh_key - split ssh_key.go to try create clearer function domains for allow for future refactors here. Signed-off-by: Andrew Thornton <art27@cantab.net>
2 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
3 years ago
Move macaron to chi (#14293) Use [chi](https://github.com/go-chi/chi) instead of the forked [macaron](https://gitea.com/macaron/macaron). Since macaron and chi have conflicts with session share, this big PR becomes a have-to thing. According my previous idea, we can replace macaron step by step but I'm wrong. :( Below is a list of big changes on this PR. - [x] Define `context.ResponseWriter` interface with an implementation `context.Response`. - [x] Use chi instead of macaron, and also a customize `Route` to wrap chi so that the router usage is similar as before. - [x] Create different routers for `web`, `api`, `internal` and `install` so that the codes will be more clear and no magic . - [x] Use https://github.com/unrolled/render instead of macaron's internal render - [x] Use https://github.com/NYTimes/gziphandler instead of https://gitea.com/macaron/gzip - [x] Use https://gitea.com/go-chi/session which is a modified version of https://gitea.com/macaron/session and removed `nodb` support since it will not be maintained. **BREAK** - [x] Use https://gitea.com/go-chi/captcha which is a modified version of https://gitea.com/macaron/captcha - [x] Use https://gitea.com/go-chi/cache which is a modified version of https://gitea.com/macaron/cache - [x] Use https://gitea.com/go-chi/binding which is a modified version of https://gitea.com/macaron/binding - [x] Use https://github.com/go-chi/cors instead of https://gitea.com/macaron/cors - [x] Dropped https://gitea.com/macaron/i18n and make a new one in `code.gitea.io/gitea/modules/translation` - [x] Move validation form structs from `code.gitea.io/gitea/modules/auth` to `code.gitea.io/gitea/modules/forms` to avoid dependency cycle. - [x] Removed macaron log service because it's not need any more. **BREAK** - [x] All form structs have to be get by `web.GetForm(ctx)` in the route function but not as a function parameter on routes definition. - [x] Move Git HTTP protocol implementation to use routers directly. - [x] Fix the problem that chi routes don't support trailing slash but macaron did. - [x] `/api/v1/swagger` now will be redirect to `/api/swagger` but not render directly so that `APIContext` will not create a html render. Notices: - Chi router don't support request with trailing slash - Integration test `TestUserHeatmap` maybe mysql version related. It's failed on my macOS(mysql 5.7.29 installed via brew) but succeed on CI. Co-authored-by: 6543 <6543@obermui.de>
3 years ago
Add Package Registry (#16510) * Added package store settings. * Added models. * Added generic package registry. * Added tests. * Added NuGet package registry. * Moved service index to api file. * Added NPM package registry. * Added Maven package registry. * Added PyPI package registry. * Summary is deprecated. * Changed npm name. * Sanitize project url. * Allow only scoped packages. * Added user interface. * Changed method name. * Added missing migration file. * Set page info. * Added documentation. * Added documentation links. * Fixed wrong error message. * Lint template files. * Fixed merge errors. * Fixed unit test storage path. * Switch to json module. * Added suggestions. * Added package webhook. * Add package api. * Fixed swagger file. * Fixed enum and comments. * Fixed NuGet pagination. * Print test names. * Added api tests. * Fixed access level. * Fix User unmarshal. * Added RubyGems package registry. * Fix lint. * Implemented io.Writer. * Added support for sha256/sha512 checksum files. * Improved maven-metadata.xml support. * Added support for symbol package uploads. * Added tests. * Added overview docs. * Added npm dependencies and keywords. * Added no-packages information. * Display file size. * Display asset count. * Fixed filter alignment. * Added package icons. * Formatted instructions. * Allow anonymous package downloads. * Fixed comments. * Fixed postgres test. * Moved file. * Moved models to models/packages. * Use correct error response format per client. * Use simpler search form. * Fixed IsProd. * Restructured data model. * Prevent empty filename. * Fix swagger. * Implemented user/org registry. * Implemented UI. * Use GetUserByIDCtx. * Use table for dependencies. * make svg * Added support for unscoped npm packages. * Add support for npm dist tags. * Added tests for npm tags. * Unlink packages if repository gets deleted. * Prevent user/org delete if a packages exist. * Use package unlink in repository service. * Added support for composer packages. * Restructured package docs. * Added missing tests. * Fixed generic content page. * Fixed docs. * Fixed swagger. * Added missing type. * Fixed ambiguous column. * Organize content store by sha256 hash. * Added admin package management. * Added support for sorting. * Add support for multiple identical versions/files. * Added missing repository unlink. * Added file properties. * make fmt * lint * Added Conan package registry. * Updated docs. * Unify package names. * Added swagger enum. * Use longer TEXT column type. * Removed version composite key. * Merged package and container registry. * Removed index. * Use dedicated package router. * Moved files to new location. * Updated docs. * Fixed JOIN order. * Fixed GROUP BY statement. * Fixed GROUP BY #2. * Added symbol server support. * Added more tests. * Set NOT NULL. * Added setting to disable package registries. * Moved auth into service. * refactor * Use ctx everywhere. * Added package cleanup task. * Changed packages path. * Added container registry. * Refactoring * Updated comparison. * Fix swagger. * Fixed table order. * Use token auth for npm routes. * Enabled ReverseProxy auth. * Added packages link for orgs. * Fixed anonymous org access. * Enable copy button for setup instructions. * Merge error * Added suggestions. * Fixed merge. * Handle "generic". * Added link for TODO. * Added suggestions. * Changed temporary buffer filename. * Added suggestions. * Apply suggestions from code review Co-authored-by: Thomas Boerger <thomas@webhippie.de> * Update docs/content/doc/packages/nuget.en-us.md Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Thomas Boerger <thomas@webhippie.de>
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package setting
  5. import (
  6. "errors"
  7. "net/http"
  8. "time"
  9. "code.gitea.io/gitea/models"
  10. user_model "code.gitea.io/gitea/models/user"
  11. "code.gitea.io/gitea/modules/auth/password"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/timeutil"
  17. "code.gitea.io/gitea/modules/web"
  18. "code.gitea.io/gitea/services/auth"
  19. "code.gitea.io/gitea/services/auth/source/db"
  20. "code.gitea.io/gitea/services/auth/source/smtp"
  21. "code.gitea.io/gitea/services/forms"
  22. "code.gitea.io/gitea/services/mailer"
  23. "code.gitea.io/gitea/services/user"
  24. )
  25. const (
  26. tplSettingsAccount base.TplName = "user/settings/account"
  27. )
  28. // Account renders change user's password, user's email and user suicide page
  29. func Account(ctx *context.Context) {
  30. ctx.Data["Title"] = ctx.Tr("settings.account")
  31. ctx.Data["PageIsSettingsAccount"] = true
  32. ctx.Data["Email"] = ctx.Doer.Email
  33. ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
  34. loadAccountData(ctx)
  35. ctx.HTML(http.StatusOK, tplSettingsAccount)
  36. }
  37. // AccountPost response for change user's password
  38. func AccountPost(ctx *context.Context) {
  39. form := web.GetForm(ctx).(*forms.ChangePasswordForm)
  40. ctx.Data["Title"] = ctx.Tr("settings")
  41. ctx.Data["PageIsSettingsAccount"] = true
  42. if ctx.HasError() {
  43. loadAccountData(ctx)
  44. ctx.HTML(http.StatusOK, tplSettingsAccount)
  45. return
  46. }
  47. if len(form.Password) < setting.MinPasswordLength {
  48. ctx.Flash.Error(ctx.Tr("auth.password_too_short", setting.MinPasswordLength))
  49. } else if ctx.Doer.IsPasswordSet() && !ctx.Doer.ValidatePassword(form.OldPassword) {
  50. ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
  51. } else if form.Password != form.Retype {
  52. ctx.Flash.Error(ctx.Tr("form.password_not_match"))
  53. } else if !password.IsComplexEnough(form.Password) {
  54. ctx.Flash.Error(password.BuildComplexityError(ctx.Locale))
  55. } else if pwned, err := password.IsPwned(ctx, form.Password); pwned || err != nil {
  56. errMsg := ctx.Tr("auth.password_pwned")
  57. if err != nil {
  58. log.Error(err.Error())
  59. errMsg = ctx.Tr("auth.password_pwned_err")
  60. }
  61. ctx.Flash.Error(errMsg)
  62. } else {
  63. var err error
  64. if err = ctx.Doer.SetPassword(form.Password); err != nil {
  65. ctx.ServerError("UpdateUser", err)
  66. return
  67. }
  68. if err := user_model.UpdateUserCols(ctx, ctx.Doer, "salt", "passwd_hash_algo", "passwd"); err != nil {
  69. ctx.ServerError("UpdateUser", err)
  70. return
  71. }
  72. log.Trace("User password updated: %s", ctx.Doer.Name)
  73. ctx.Flash.Success(ctx.Tr("settings.change_password_success"))
  74. }
  75. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  76. }
  77. // EmailPost response for change user's email
  78. func EmailPost(ctx *context.Context) {
  79. form := web.GetForm(ctx).(*forms.AddEmailForm)
  80. ctx.Data["Title"] = ctx.Tr("settings")
  81. ctx.Data["PageIsSettingsAccount"] = true
  82. // Make emailaddress primary.
  83. if ctx.FormString("_method") == "PRIMARY" {
  84. if err := user_model.MakeEmailPrimary(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil {
  85. ctx.ServerError("MakeEmailPrimary", err)
  86. return
  87. }
  88. log.Trace("Email made primary: %s", ctx.Doer.Name)
  89. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  90. return
  91. }
  92. // Send activation Email
  93. if ctx.FormString("_method") == "SENDACTIVATION" {
  94. var address string
  95. if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
  96. log.Error("Send activation: activation still pending")
  97. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  98. return
  99. }
  100. id := ctx.FormInt64("id")
  101. email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, id)
  102. if err != nil {
  103. log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.Doer.ID, id, err)
  104. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  105. return
  106. }
  107. if email == nil {
  108. log.Warn("Send activation failed: EmailAddress[%d] not found for user: %-v", id, ctx.Doer)
  109. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  110. return
  111. }
  112. if email.IsActivated {
  113. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  114. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  115. return
  116. }
  117. if email.IsPrimary {
  118. if ctx.Doer.IsActive && !setting.Service.RegisterEmailConfirm {
  119. log.Debug("Send activation failed: email %s is already activated for user: %-v", email.Email, ctx.Doer)
  120. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  121. return
  122. }
  123. // Only fired when the primary email is inactive (Wrong state)
  124. mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
  125. } else {
  126. mailer.SendActivateEmailMail(ctx.Doer, email)
  127. }
  128. address = email.Email
  129. if setting.CacheService.Enabled {
  130. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  131. log.Error("Set cache(MailResendLimit) fail: %v", err)
  132. }
  133. }
  134. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  135. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  136. return
  137. }
  138. // Set Email Notification Preference
  139. if ctx.FormString("_method") == "NOTIFICATION" {
  140. preference := ctx.FormString("preference")
  141. if !(preference == user_model.EmailNotificationsEnabled ||
  142. preference == user_model.EmailNotificationsOnMention ||
  143. preference == user_model.EmailNotificationsDisabled ||
  144. preference == user_model.EmailNotificationsAndYourOwn) {
  145. log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.Doer.Name)
  146. ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
  147. return
  148. }
  149. if err := user_model.SetEmailNotifications(ctx, ctx.Doer, preference); err != nil {
  150. log.Error("Set Email Notifications failed: %v", err)
  151. ctx.ServerError("SetEmailNotifications", err)
  152. return
  153. }
  154. log.Trace("Email notifications preference made %s: %s", preference, ctx.Doer.Name)
  155. ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
  156. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  157. return
  158. }
  159. if ctx.HasError() {
  160. loadAccountData(ctx)
  161. ctx.HTML(http.StatusOK, tplSettingsAccount)
  162. return
  163. }
  164. email := &user_model.EmailAddress{
  165. UID: ctx.Doer.ID,
  166. Email: form.Email,
  167. IsActivated: !setting.Service.RegisterEmailConfirm,
  168. }
  169. if err := user_model.AddEmailAddress(ctx, email); err != nil {
  170. if user_model.IsErrEmailAlreadyUsed(err) {
  171. loadAccountData(ctx)
  172. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
  173. return
  174. } else if user_model.IsErrEmailCharIsNotSupported(err) ||
  175. user_model.IsErrEmailInvalid(err) {
  176. loadAccountData(ctx)
  177. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
  178. return
  179. }
  180. ctx.ServerError("AddEmailAddress", err)
  181. return
  182. }
  183. // Send confirmation email
  184. if setting.Service.RegisterEmailConfirm {
  185. mailer.SendActivateEmailMail(ctx.Doer, email)
  186. if setting.CacheService.Enabled {
  187. if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
  188. log.Error("Set cache(MailResendLimit) fail: %v", err)
  189. }
  190. }
  191. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
  192. } else {
  193. ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
  194. }
  195. log.Trace("Email address added: %s", email.Email)
  196. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  197. }
  198. // DeleteEmail response for delete user's email
  199. func DeleteEmail(ctx *context.Context) {
  200. if err := user_model.DeleteEmailAddress(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil {
  201. ctx.ServerError("DeleteEmail", err)
  202. return
  203. }
  204. log.Trace("Email address deleted: %s", ctx.Doer.Name)
  205. ctx.Flash.Success(ctx.Tr("settings.email_deletion_success"))
  206. ctx.JSONRedirect(setting.AppSubURL + "/user/settings/account")
  207. }
  208. // DeleteAccount render user suicide page and response for delete user himself
  209. func DeleteAccount(ctx *context.Context) {
  210. ctx.Data["Title"] = ctx.Tr("settings")
  211. ctx.Data["PageIsSettingsAccount"] = true
  212. if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil {
  213. switch {
  214. case user_model.IsErrUserNotExist(err):
  215. loadAccountData(ctx)
  216. ctx.RenderWithErr(ctx.Tr("form.user_not_exist"), tplSettingsAccount, nil)
  217. case errors.Is(err, smtp.ErrUnsupportedLoginType):
  218. loadAccountData(ctx)
  219. ctx.RenderWithErr(ctx.Tr("form.unsupported_login_type"), tplSettingsAccount, nil)
  220. case errors.As(err, &db.ErrUserPasswordNotSet{}):
  221. loadAccountData(ctx)
  222. ctx.RenderWithErr(ctx.Tr("form.unset_password"), tplSettingsAccount, nil)
  223. case errors.As(err, &db.ErrUserPasswordInvalid{}):
  224. loadAccountData(ctx)
  225. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsAccount, nil)
  226. default:
  227. ctx.ServerError("UserSignIn", err)
  228. }
  229. return
  230. }
  231. // admin should not delete themself
  232. if ctx.Doer.IsAdmin {
  233. ctx.Flash.Error(ctx.Tr("form.admin_cannot_delete_self"))
  234. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  235. return
  236. }
  237. if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil {
  238. switch {
  239. case models.IsErrUserOwnRepos(err):
  240. ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
  241. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  242. case models.IsErrUserHasOrgs(err):
  243. ctx.Flash.Error(ctx.Tr("form.still_has_org"))
  244. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  245. case models.IsErrUserOwnPackages(err):
  246. ctx.Flash.Error(ctx.Tr("form.still_own_packages"))
  247. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  248. case models.IsErrDeleteLastAdminUser(err):
  249. ctx.Flash.Error(ctx.Tr("auth.last_admin"))
  250. ctx.Redirect(setting.AppSubURL + "/user/settings/account")
  251. default:
  252. ctx.ServerError("DeleteUser", err)
  253. }
  254. } else {
  255. log.Trace("Account deleted: %s", ctx.Doer.Name)
  256. ctx.Redirect(setting.AppSubURL + "/")
  257. }
  258. }
  259. func loadAccountData(ctx *context.Context) {
  260. emlist, err := user_model.GetEmailAddresses(ctx, ctx.Doer.ID)
  261. if err != nil {
  262. ctx.ServerError("GetEmailAddresses", err)
  263. return
  264. }
  265. type UserEmail struct {
  266. user_model.EmailAddress
  267. CanBePrimary bool
  268. }
  269. pendingActivation := setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName)
  270. emails := make([]*UserEmail, len(emlist))
  271. for i, em := range emlist {
  272. var email UserEmail
  273. email.EmailAddress = *em
  274. email.CanBePrimary = em.IsActivated
  275. emails[i] = &email
  276. }
  277. ctx.Data["Emails"] = emails
  278. ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotifications()
  279. ctx.Data["ActivationsPending"] = pendingActivation
  280. ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
  281. if setting.Service.UserDeleteWithCommentsMaxTime != 0 {
  282. ctx.Data["UserDeleteWithCommentsMaxTime"] = setting.Service.UserDeleteWithCommentsMaxTime.String()
  283. ctx.Data["UserDeleteWithComments"] = ctx.Doer.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now())
  284. }
  285. }