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

user.go 13 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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 user
  5. import (
  6. "fmt"
  7. "net/url"
  8. "strings"
  9. "github.com/go-martini/martini"
  10. "github.com/gogits/gogs/models"
  11. "github.com/gogits/gogs/modules/auth"
  12. "github.com/gogits/gogs/modules/base"
  13. "github.com/gogits/gogs/modules/log"
  14. "github.com/gogits/gogs/modules/mailer"
  15. "github.com/gogits/gogs/modules/middleware"
  16. )
  17. func Dashboard(ctx *middleware.Context) {
  18. ctx.Data["Title"] = "Dashboard"
  19. ctx.Data["PageIsUserDashboard"] = true
  20. repos, err := models.GetRepositories(&models.User{Id: ctx.User.Id})
  21. if err != nil {
  22. ctx.Handle(200, "user.Dashboard", err)
  23. return
  24. }
  25. ctx.Data["MyRepos"] = repos
  26. feeds, err := models.GetFeeds(ctx.User.Id, 0, false)
  27. if err != nil {
  28. ctx.Handle(200, "user.Dashboard", err)
  29. return
  30. }
  31. ctx.Data["Feeds"] = feeds
  32. ctx.HTML(200, "user/dashboard")
  33. }
  34. func Profile(ctx *middleware.Context, params martini.Params) {
  35. ctx.Data["Title"] = "Profile"
  36. // TODO: Need to check view self or others.
  37. user, err := models.GetUserByName(params["username"])
  38. if err != nil {
  39. ctx.Handle(200, "user.Profile", err)
  40. return
  41. }
  42. ctx.Data["Owner"] = user
  43. tab := ctx.Query("tab")
  44. ctx.Data["TabName"] = tab
  45. switch tab {
  46. case "activity":
  47. feeds, err := models.GetFeeds(user.Id, 0, true)
  48. if err != nil {
  49. ctx.Handle(200, "user.Profile", err)
  50. return
  51. }
  52. ctx.Data["Feeds"] = feeds
  53. default:
  54. repos, err := models.GetRepositories(user)
  55. if err != nil {
  56. ctx.Handle(200, "user.Profile", err)
  57. return
  58. }
  59. ctx.Data["Repos"] = repos
  60. }
  61. ctx.Data["PageIsUserProfile"] = true
  62. ctx.HTML(200, "user/profile")
  63. }
  64. func SignIn(ctx *middleware.Context, form auth.LogInForm) {
  65. ctx.Data["Title"] = "Log In"
  66. if ctx.Req.Method == "GET" {
  67. if base.OauthService != nil {
  68. ctx.Data["OauthEnabled"] = true
  69. ctx.Data["OauthGitHubEnabled"] = base.OauthService.GitHub.Enabled
  70. }
  71. // Check auto-login.
  72. userName := ctx.GetCookie(base.CookieUserName)
  73. if len(userName) == 0 {
  74. ctx.HTML(200, "user/signin")
  75. return
  76. }
  77. isSucceed := false
  78. defer func() {
  79. if !isSucceed {
  80. log.Trace("%s auto-login cookie cleared: %s", ctx.Req.RequestURI, userName)
  81. ctx.SetCookie(base.CookieUserName, "", -1)
  82. ctx.SetCookie(base.CookieRememberName, "", -1)
  83. }
  84. }()
  85. user, err := models.GetUserByName(userName)
  86. if err != nil {
  87. ctx.HTML(200, "user/signin")
  88. return
  89. }
  90. secret := base.EncodeMd5(user.Rands + user.Passwd)
  91. value, _ := ctx.GetSecureCookie(secret, base.CookieRememberName)
  92. if value != user.Name {
  93. ctx.HTML(200, "user/signin")
  94. return
  95. }
  96. isSucceed = true
  97. ctx.Session.Set("userId", user.Id)
  98. ctx.Session.Set("userName", user.Name)
  99. redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
  100. if len(redirectTo) > 0 {
  101. ctx.SetCookie("redirect_to", "", -1)
  102. ctx.Redirect(redirectTo)
  103. } else {
  104. ctx.Redirect("/")
  105. }
  106. return
  107. }
  108. if ctx.HasError() {
  109. ctx.HTML(200, "user/signin")
  110. return
  111. }
  112. user, err := models.LoginUserPlain(form.UserName, form.Password)
  113. if err != nil {
  114. if err == models.ErrUserNotExist {
  115. log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password)
  116. ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
  117. return
  118. }
  119. ctx.Handle(200, "user.SignIn", err)
  120. return
  121. }
  122. if form.Remember == "on" {
  123. secret := base.EncodeMd5(user.Rands + user.Passwd)
  124. days := 86400 * base.LogInRememberDays
  125. ctx.SetCookie(base.CookieUserName, user.Name, days)
  126. ctx.SetSecureCookie(secret, base.CookieRememberName, user.Name, days)
  127. }
  128. ctx.Session.Set("userId", user.Id)
  129. ctx.Session.Set("userName", user.Name)
  130. redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
  131. if len(redirectTo) > 0 {
  132. ctx.SetCookie("redirect_to", "", -1)
  133. ctx.Redirect(redirectTo)
  134. } else {
  135. ctx.Redirect("/")
  136. }
  137. }
  138. func SignOut(ctx *middleware.Context) {
  139. ctx.Session.Delete("userId")
  140. ctx.Session.Delete("userName")
  141. ctx.SetCookie(base.CookieUserName, "", -1)
  142. ctx.SetCookie(base.CookieRememberName, "", -1)
  143. ctx.Redirect("/")
  144. }
  145. func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
  146. ctx.Data["Title"] = "Sign Up"
  147. ctx.Data["PageIsSignUp"] = true
  148. if base.Service.DisenableRegisteration {
  149. ctx.Data["DisenableRegisteration"] = true
  150. ctx.HTML(200, "user/signup")
  151. return
  152. }
  153. if ctx.Req.Method == "GET" {
  154. ctx.HTML(200, "user/signup")
  155. return
  156. }
  157. if form.Password != form.RetypePasswd {
  158. ctx.Data["HasError"] = true
  159. ctx.Data["Err_Password"] = true
  160. ctx.Data["Err_RetypePasswd"] = true
  161. ctx.Data["ErrorMsg"] = "Password and re-type password are not same"
  162. auth.AssignForm(form, ctx.Data)
  163. }
  164. if ctx.HasError() {
  165. ctx.HTML(200, "user/signup")
  166. return
  167. }
  168. u := &models.User{
  169. Name: form.UserName,
  170. Email: form.Email,
  171. Passwd: form.Password,
  172. IsActive: !base.Service.RegisterEmailConfirm,
  173. }
  174. var err error
  175. if u, err = models.RegisterUser(u); err != nil {
  176. switch err {
  177. case models.ErrUserAlreadyExist:
  178. ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
  179. case models.ErrEmailAlreadyUsed:
  180. ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form)
  181. case models.ErrUserNameIllegal:
  182. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form)
  183. default:
  184. ctx.Handle(200, "user.SignUp", err)
  185. }
  186. return
  187. }
  188. log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName))
  189. // Send confirmation e-mail.
  190. if base.Service.RegisterEmailConfirm && u.Id > 1 {
  191. mailer.SendRegisterMail(ctx.Render, u)
  192. ctx.Data["IsSendRegisterMail"] = true
  193. ctx.Data["Email"] = u.Email
  194. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  195. ctx.HTML(200, "user/active")
  196. if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
  197. log.Error("Set cache(MailResendLimit) fail: %v", err)
  198. }
  199. return
  200. }
  201. ctx.Redirect("/user/login")
  202. }
  203. func Delete(ctx *middleware.Context) {
  204. ctx.Data["Title"] = "Delete Account"
  205. ctx.Data["PageIsUserSetting"] = true
  206. ctx.Data["IsUserPageSettingDelete"] = true
  207. if ctx.Req.Method == "GET" {
  208. ctx.HTML(200, "user/delete")
  209. return
  210. }
  211. tmpUser := models.User{Passwd: ctx.Query("password")}
  212. tmpUser.EncodePasswd()
  213. if len(tmpUser.Passwd) == 0 || tmpUser.Passwd != ctx.User.Passwd {
  214. ctx.Data["HasError"] = true
  215. ctx.Data["ErrorMsg"] = "Password is not correct. Make sure you are owner of this account."
  216. } else {
  217. if err := models.DeleteUser(ctx.User); err != nil {
  218. ctx.Data["HasError"] = true
  219. switch err {
  220. case models.ErrUserOwnRepos:
  221. ctx.Data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first."
  222. default:
  223. ctx.Handle(200, "user.Delete", err)
  224. return
  225. }
  226. } else {
  227. ctx.Redirect("/")
  228. return
  229. }
  230. }
  231. ctx.HTML(200, "user/delete")
  232. }
  233. const (
  234. TPL_FEED = `<i class="icon fa fa-%s"></i>
  235. <div class="info"><span class="meta">%s</span><br>%s</div>`
  236. )
  237. func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
  238. actions, err := models.GetFeeds(form.UserId, form.Page*20, false)
  239. if err != nil {
  240. ctx.JSON(500, err)
  241. }
  242. feeds := make([]string, len(actions))
  243. for i := range actions {
  244. feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType),
  245. base.TimeSince(actions[i].Created), base.ActionDesc(actions[i]))
  246. }
  247. ctx.JSON(200, &feeds)
  248. }
  249. func Issues(ctx *middleware.Context) {
  250. ctx.Data["Title"] = "Your Issues"
  251. ctx.Data["ViewType"] = "all"
  252. page, _ := base.StrTo(ctx.Query("page")).Int()
  253. repoId, _ := base.StrTo(ctx.Query("repoid")).Int64()
  254. ctx.Data["RepoId"] = repoId
  255. var posterId int64 = 0
  256. if ctx.Query("type") == "created_by" {
  257. posterId = ctx.User.Id
  258. ctx.Data["ViewType"] = "created_by"
  259. }
  260. // Get all repositories.
  261. repos, err := models.GetRepositories(ctx.User)
  262. if err != nil {
  263. ctx.Handle(200, "user.Issues(get repositories)", err)
  264. return
  265. }
  266. showRepos := make([]models.Repository, 0, len(repos))
  267. isShowClosed := ctx.Query("state") == "closed"
  268. var closedIssueCount, createdByCount, allIssueCount int
  269. // Get all issues.
  270. allIssues := make([]models.Issue, 0, 5*len(repos))
  271. for i, repo := range repos {
  272. issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "")
  273. if err != nil {
  274. ctx.Handle(200, "user.Issues(get issues)", err)
  275. return
  276. }
  277. allIssueCount += repo.NumIssues
  278. closedIssueCount += repo.NumClosedIssues
  279. // Set repository information to issues.
  280. for j := range issues {
  281. issues[j].Repo = &repos[i]
  282. }
  283. allIssues = append(allIssues, issues...)
  284. repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  285. if repos[i].NumOpenIssues > 0 {
  286. showRepos = append(showRepos, repos[i])
  287. }
  288. }
  289. showIssues := make([]models.Issue, 0, len(allIssues))
  290. ctx.Data["IsShowClosed"] = isShowClosed
  291. // Get posters and filter issues.
  292. for i := range allIssues {
  293. u, err := models.GetUserById(allIssues[i].PosterId)
  294. if err != nil {
  295. ctx.Handle(200, "user.Issues(get poster): %v", err)
  296. return
  297. }
  298. allIssues[i].Poster = u
  299. if u.Id == ctx.User.Id {
  300. createdByCount++
  301. }
  302. if repoId > 0 && repoId != allIssues[i].Repo.Id {
  303. continue
  304. }
  305. if isShowClosed == allIssues[i].IsClosed {
  306. showIssues = append(showIssues, allIssues[i])
  307. }
  308. }
  309. ctx.Data["Repos"] = showRepos
  310. ctx.Data["Issues"] = showIssues
  311. ctx.Data["AllIssueCount"] = allIssueCount
  312. ctx.Data["ClosedIssueCount"] = closedIssueCount
  313. ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
  314. ctx.Data["CreatedByCount"] = createdByCount
  315. ctx.HTML(200, "issue/user")
  316. }
  317. func Pulls(ctx *middleware.Context) {
  318. ctx.HTML(200, "user/pulls")
  319. }
  320. func Stars(ctx *middleware.Context) {
  321. ctx.HTML(200, "user/stars")
  322. }
  323. func Activate(ctx *middleware.Context) {
  324. code := ctx.Query("code")
  325. if len(code) == 0 {
  326. ctx.Data["IsActivatePage"] = true
  327. if ctx.User.IsActive {
  328. ctx.Handle(404, "user.Activate", nil)
  329. return
  330. }
  331. // Resend confirmation e-mail.
  332. if base.Service.RegisterEmailConfirm {
  333. if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
  334. ctx.Data["ResendLimited"] = true
  335. } else {
  336. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  337. mailer.SendActiveMail(ctx.Render, ctx.User)
  338. }
  339. } else {
  340. ctx.Data["ServiceNotEnabled"] = true
  341. }
  342. ctx.HTML(200, "user/active")
  343. return
  344. }
  345. // Verify code.
  346. if user := models.VerifyUserActiveCode(code); user != nil {
  347. user.IsActive = true
  348. user.Rands = models.GetUserSalt()
  349. if err := models.UpdateUser(user); err != nil {
  350. ctx.Handle(404, "user.Activate", err)
  351. return
  352. }
  353. log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.Name)
  354. ctx.Session.Set("userId", user.Id)
  355. ctx.Session.Set("userName", user.Name)
  356. ctx.Redirect("/")
  357. return
  358. }
  359. ctx.Data["IsActivateFailed"] = true
  360. ctx.HTML(200, "user/active")
  361. }
  362. func ForgotPasswd(ctx *middleware.Context) {
  363. ctx.Data["Title"] = "Forgot Password"
  364. if base.MailService == nil {
  365. ctx.Data["IsResetDisable"] = true
  366. ctx.HTML(200, "user/forgot_passwd")
  367. return
  368. }
  369. ctx.Data["IsResetRequest"] = true
  370. if ctx.Req.Method == "GET" {
  371. ctx.HTML(200, "user/forgot_passwd")
  372. return
  373. }
  374. email := ctx.Query("email")
  375. u, err := models.GetUserByEmail(email)
  376. if err != nil {
  377. if err == models.ErrUserNotExist {
  378. ctx.RenderWithErr("This e-mail address does not associate to any account.", "user/forgot_passwd", nil)
  379. } else {
  380. ctx.Handle(404, "user.ResetPasswd(check existence)", err)
  381. }
  382. return
  383. }
  384. mailer.SendResetPasswdMail(ctx.Render, u)
  385. ctx.Data["Email"] = email
  386. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  387. ctx.Data["IsResetSent"] = true
  388. ctx.HTML(200, "user/forgot_passwd")
  389. }
  390. func ResetPasswd(ctx *middleware.Context) {
  391. code := ctx.Query("code")
  392. if len(code) == 0 {
  393. ctx.Error(404)
  394. return
  395. }
  396. ctx.Data["Code"] = code
  397. if ctx.Req.Method == "GET" {
  398. ctx.Data["IsResetForm"] = true
  399. ctx.HTML(200, "user/reset_passwd")
  400. return
  401. }
  402. if u := models.VerifyUserActiveCode(code); u != nil {
  403. // Validate password length.
  404. passwd := ctx.Query("passwd")
  405. if len(passwd) < 6 || len(passwd) > 30 {
  406. ctx.Data["IsResetForm"] = true
  407. ctx.RenderWithErr("Password length should be in 6 and 30.", "user/reset_passwd", nil)
  408. return
  409. }
  410. u.Passwd = passwd
  411. u.Rands = models.GetUserSalt()
  412. u.Salt = models.GetUserSalt()
  413. u.EncodePasswd()
  414. if err := models.UpdateUser(u); err != nil {
  415. ctx.Handle(404, "user.ResetPasswd(UpdateUser)", err)
  416. return
  417. }
  418. log.Trace("%s User password reset: %s", ctx.Req.RequestURI, u.Name)
  419. ctx.Redirect("/user/login")
  420. return
  421. }
  422. ctx.Data["IsResetFailed"] = true
  423. ctx.HTML(200, "user/reset_passwd")
  424. }