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.

576 lines
14 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
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
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
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
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
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
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
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
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
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
10 years ago
10 years ago
10 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 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) {
  65. ctx.Data["Title"] = "Log In"
  66. if base.OauthService != nil {
  67. ctx.Data["OauthEnabled"] = true
  68. ctx.Data["OauthGitHubEnabled"] = base.OauthService.GitHub.Enabled
  69. }
  70. var user *models.User
  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. var err error
  79. defer func() {
  80. if !isSucceed {
  81. log.Trace("%s auto-login cookie cleared: %s", ctx.Req.RequestURI, userName)
  82. ctx.SetCookie(base.CookieUserName, "", -1)
  83. ctx.SetCookie(base.CookieRememberName, "", -1)
  84. return
  85. }
  86. }()
  87. user, err = models.GetUserByName(userName)
  88. if err != nil {
  89. ctx.HTML(200, "user/signin")
  90. return
  91. }
  92. secret := base.EncodeMd5(user.Rands + user.Passwd)
  93. value, _ := ctx.GetSecureCookie(secret, base.CookieRememberName)
  94. if value != user.Name {
  95. ctx.HTML(200, "user/signin")
  96. return
  97. }
  98. isSucceed = true
  99. ctx.Session.Set("userId", user.Id)
  100. ctx.Session.Set("userName", user.Name)
  101. if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
  102. ctx.SetCookie("redirect_to", "", -1)
  103. ctx.Redirect(redirectTo)
  104. return
  105. }
  106. ctx.Redirect("/")
  107. }
  108. func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
  109. ctx.Data["Title"] = "Log In"
  110. if base.OauthService != nil {
  111. ctx.Data["OauthEnabled"] = true
  112. ctx.Data["OauthGitHubEnabled"] = base.OauthService.GitHub.Enabled
  113. }
  114. if ctx.HasError() {
  115. ctx.HTML(200, "user/signin")
  116. return
  117. }
  118. user, err := models.LoginUserPlain(form.UserName, form.Password)
  119. if err != nil {
  120. if err == models.ErrUserNotExist {
  121. log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password)
  122. ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
  123. return
  124. }
  125. ctx.Handle(500, "user.SignIn", err)
  126. return
  127. }
  128. if form.Remember == "on" {
  129. secret := base.EncodeMd5(user.Rands + user.Passwd)
  130. days := 86400 * base.LogInRememberDays
  131. ctx.SetCookie(base.CookieUserName, user.Name, days)
  132. ctx.SetSecureCookie(secret, base.CookieRememberName, user.Name, days)
  133. }
  134. // Bind with social account
  135. if sid, ok := ctx.Session.Get("socialId").(int64); ok {
  136. if err = models.BindUserOauth2(user.Id, sid); err != nil {
  137. log.Error("bind user error: %v", err)
  138. }
  139. ctx.Session.Delete("socialId")
  140. }
  141. ctx.Session.Set("userId", user.Id)
  142. ctx.Session.Set("userName", user.Name)
  143. if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
  144. ctx.SetCookie("redirect_to", "", -1)
  145. ctx.Redirect(redirectTo)
  146. return
  147. }
  148. ctx.Redirect("/")
  149. }
  150. func SignOut(ctx *middleware.Context) {
  151. ctx.Session.Delete("userId")
  152. ctx.Session.Delete("userName")
  153. ctx.Session.Delete("socialId")
  154. ctx.SetCookie(base.CookieUserName, "", -1)
  155. ctx.SetCookie(base.CookieRememberName, "", -1)
  156. ctx.Redirect("/")
  157. }
  158. func SignUp(ctx *middleware.Context) {
  159. ctx.Data["Title"] = "Sign Up"
  160. ctx.Data["PageIsSignUp"] = true
  161. if sid, ok := ctx.Session.Get("socialId").(int64); ok {
  162. var err error
  163. if _, err = models.GetOauth2ById(sid); err == nil {
  164. ctx.Data["IsSocialLogin"] = true
  165. // FIXME: don't set in error page
  166. ctx.Data["username"] = ctx.Session.Get("socialName")
  167. ctx.Data["email"] = ctx.Session.Get("socialEmail")
  168. } else {
  169. log.Error("unaccepted oauth error: %s", err) // FIXME: should it show in page
  170. }
  171. }
  172. if base.Service.DisenableRegisteration {
  173. ctx.Data["DisenableRegisteration"] = true
  174. ctx.HTML(200, "user/signup")
  175. return
  176. }
  177. log.Info("session: %v", ctx.Session.Get("socialId"))
  178. ctx.HTML(200, "user/signup")
  179. }
  180. func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
  181. ctx.Data["Title"] = "Sign Up"
  182. ctx.Data["PageIsSignUp"] = true
  183. if base.Service.DisenableRegisteration {
  184. ctx.Handle(403, "user.SignUpPost", nil)
  185. return
  186. }
  187. if form.Password != form.RetypePasswd {
  188. ctx.Data["HasError"] = true
  189. ctx.Data["Err_Password"] = true
  190. ctx.Data["Err_RetypePasswd"] = true
  191. ctx.Data["ErrorMsg"] = "Password and re-type password are not same"
  192. auth.AssignForm(form, ctx.Data)
  193. }
  194. if ctx.HasError() {
  195. ctx.HTML(200, "user/signup")
  196. return
  197. }
  198. u := &models.User{
  199. Name: form.UserName,
  200. Email: form.Email,
  201. Passwd: form.Password,
  202. IsActive: !base.Service.RegisterEmailConfirm,
  203. }
  204. var err error
  205. if u, err = models.RegisterUser(u); err != nil {
  206. switch err {
  207. case models.ErrUserAlreadyExist:
  208. ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
  209. case models.ErrEmailAlreadyUsed:
  210. ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form)
  211. case models.ErrUserNameIllegal:
  212. ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form)
  213. default:
  214. ctx.Handle(500, "user.SignUp", err)
  215. }
  216. return
  217. }
  218. log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName))
  219. // Bind Social Account
  220. if sid, ok := ctx.Session.Get("socialId").(int64); ok {
  221. models.BindUserOauth2(u.Id, sid)
  222. ctx.Session.Delete("socialId")
  223. }
  224. // Send confirmation e-mail.
  225. if base.Service.RegisterEmailConfirm && u.Id > 1 {
  226. mailer.SendRegisterMail(ctx.Render, u)
  227. ctx.Data["IsSendRegisterMail"] = true
  228. ctx.Data["Email"] = u.Email
  229. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  230. ctx.HTML(200, "user/active")
  231. if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
  232. log.Error("Set cache(MailResendLimit) fail: %v", err)
  233. }
  234. return
  235. }
  236. ctx.Redirect("/user/login")
  237. }
  238. func Delete(ctx *middleware.Context) {
  239. ctx.Data["Title"] = "Delete Account"
  240. ctx.Data["PageIsUserSetting"] = true
  241. ctx.Data["IsUserPageSettingDelete"] = true
  242. ctx.HTML(200, "user/delete")
  243. }
  244. func DeletePost(ctx *middleware.Context) {
  245. ctx.Data["Title"] = "Delete Account"
  246. ctx.Data["PageIsUserSetting"] = true
  247. ctx.Data["IsUserPageSettingDelete"] = true
  248. tmpUser := models.User{
  249. Passwd: ctx.Query("password"),
  250. Salt: ctx.User.Salt,
  251. }
  252. tmpUser.EncodePasswd()
  253. if tmpUser.Passwd != ctx.User.Passwd {
  254. ctx.Flash.Error("Password is not correct. Make sure you are owner of this account.")
  255. } else {
  256. if err := models.DeleteUser(ctx.User); err != nil {
  257. switch err {
  258. case models.ErrUserOwnRepos:
  259. ctx.Flash.Error("Your account still have ownership of repository, you have to delete or transfer them first.")
  260. default:
  261. ctx.Handle(500, "user.Delete", err)
  262. return
  263. }
  264. } else {
  265. ctx.Redirect("/")
  266. return
  267. }
  268. }
  269. ctx.Redirect("/user/delete")
  270. }
  271. const (
  272. TPL_FEED = `<i class="icon fa fa-%s"></i>
  273. <div class="info"><span class="meta">%s</span><br>%s</div>`
  274. )
  275. func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
  276. actions, err := models.GetFeeds(form.UserId, form.Page*20, false)
  277. if err != nil {
  278. ctx.JSON(500, err)
  279. }
  280. feeds := make([]string, len(actions))
  281. for i := range actions {
  282. feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType),
  283. base.TimeSince(actions[i].Created), base.ActionDesc(actions[i]))
  284. }
  285. ctx.JSON(200, &feeds)
  286. }
  287. func Issues(ctx *middleware.Context) {
  288. ctx.Data["Title"] = "Your Issues"
  289. ctx.Data["ViewType"] = "all"
  290. page, _ := base.StrTo(ctx.Query("page")).Int()
  291. repoId, _ := base.StrTo(ctx.Query("repoid")).Int64()
  292. ctx.Data["RepoId"] = repoId
  293. var posterId int64 = 0
  294. if ctx.Query("type") == "created_by" {
  295. posterId = ctx.User.Id
  296. ctx.Data["ViewType"] = "created_by"
  297. }
  298. // Get all repositories.
  299. repos, err := models.GetRepositories(ctx.User)
  300. if err != nil {
  301. ctx.Handle(200, "user.Issues(get repositories)", err)
  302. return
  303. }
  304. showRepos := make([]models.Repository, 0, len(repos))
  305. isShowClosed := ctx.Query("state") == "closed"
  306. var closedIssueCount, createdByCount, allIssueCount int
  307. // Get all issues.
  308. allIssues := make([]models.Issue, 0, 5*len(repos))
  309. for i, repo := range repos {
  310. issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "")
  311. if err != nil {
  312. ctx.Handle(200, "user.Issues(get issues)", err)
  313. return
  314. }
  315. allIssueCount += repo.NumIssues
  316. closedIssueCount += repo.NumClosedIssues
  317. // Set repository information to issues.
  318. for j := range issues {
  319. issues[j].Repo = &repos[i]
  320. }
  321. allIssues = append(allIssues, issues...)
  322. repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  323. if repos[i].NumOpenIssues > 0 {
  324. showRepos = append(showRepos, repos[i])
  325. }
  326. }
  327. showIssues := make([]models.Issue, 0, len(allIssues))
  328. ctx.Data["IsShowClosed"] = isShowClosed
  329. // Get posters and filter issues.
  330. for i := range allIssues {
  331. u, err := models.GetUserById(allIssues[i].PosterId)
  332. if err != nil {
  333. ctx.Handle(200, "user.Issues(get poster): %v", err)
  334. return
  335. }
  336. allIssues[i].Poster = u
  337. if u.Id == ctx.User.Id {
  338. createdByCount++
  339. }
  340. if repoId > 0 && repoId != allIssues[i].Repo.Id {
  341. continue
  342. }
  343. if isShowClosed == allIssues[i].IsClosed {
  344. showIssues = append(showIssues, allIssues[i])
  345. }
  346. }
  347. ctx.Data["Repos"] = showRepos
  348. ctx.Data["Issues"] = showIssues
  349. ctx.Data["AllIssueCount"] = allIssueCount
  350. ctx.Data["ClosedIssueCount"] = closedIssueCount
  351. ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
  352. ctx.Data["CreatedByCount"] = createdByCount
  353. ctx.HTML(200, "issue/user")
  354. }
  355. func Pulls(ctx *middleware.Context) {
  356. ctx.HTML(200, "user/pulls")
  357. }
  358. func Stars(ctx *middleware.Context) {
  359. ctx.HTML(200, "user/stars")
  360. }
  361. func Activate(ctx *middleware.Context) {
  362. code := ctx.Query("code")
  363. if len(code) == 0 {
  364. ctx.Data["IsActivatePage"] = true
  365. if ctx.User.IsActive {
  366. ctx.Handle(404, "user.Activate", nil)
  367. return
  368. }
  369. // Resend confirmation e-mail.
  370. if base.Service.RegisterEmailConfirm {
  371. if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
  372. ctx.Data["ResendLimited"] = true
  373. } else {
  374. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  375. mailer.SendActiveMail(ctx.Render, ctx.User)
  376. if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
  377. log.Error("Set cache(MailResendLimit) fail: %v", err)
  378. }
  379. }
  380. } else {
  381. ctx.Data["ServiceNotEnabled"] = true
  382. }
  383. ctx.HTML(200, "user/active")
  384. return
  385. }
  386. // Verify code.
  387. if user := models.VerifyUserActiveCode(code); user != nil {
  388. user.IsActive = true
  389. user.Rands = models.GetUserSalt()
  390. if err := models.UpdateUser(user); err != nil {
  391. ctx.Handle(404, "user.Activate", err)
  392. return
  393. }
  394. log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.Name)
  395. ctx.Session.Set("userId", user.Id)
  396. ctx.Session.Set("userName", user.Name)
  397. ctx.Redirect("/")
  398. return
  399. }
  400. ctx.Data["IsActivateFailed"] = true
  401. ctx.HTML(200, "user/active")
  402. }
  403. func ForgotPasswd(ctx *middleware.Context) {
  404. ctx.Data["Title"] = "Forgot Password"
  405. if base.MailService == nil {
  406. ctx.Data["IsResetDisable"] = true
  407. ctx.HTML(200, "user/forgot_passwd")
  408. return
  409. }
  410. ctx.Data["IsResetRequest"] = true
  411. ctx.HTML(200, "user/forgot_passwd")
  412. }
  413. func ForgotPasswdPost(ctx *middleware.Context) {
  414. ctx.Data["Title"] = "Forgot Password"
  415. if base.MailService == nil {
  416. ctx.Handle(403, "user.ForgotPasswdPost", nil)
  417. return
  418. }
  419. ctx.Data["IsResetRequest"] = true
  420. email := ctx.Query("email")
  421. u, err := models.GetUserByEmail(email)
  422. if err != nil {
  423. if err == models.ErrUserNotExist {
  424. ctx.RenderWithErr("This e-mail address does not associate to any account.", "user/forgot_passwd", nil)
  425. } else {
  426. ctx.Handle(500, "user.ResetPasswd(check existence)", err)
  427. }
  428. return
  429. }
  430. if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
  431. ctx.Data["ResendLimited"] = true
  432. ctx.HTML(200, "user/forgot_passwd")
  433. return
  434. }
  435. mailer.SendResetPasswdMail(ctx.Render, u)
  436. if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
  437. log.Error("Set cache(MailResendLimit) fail: %v", err)
  438. }
  439. ctx.Data["Email"] = email
  440. ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
  441. ctx.Data["IsResetSent"] = true
  442. ctx.HTML(200, "user/forgot_passwd")
  443. }
  444. func ResetPasswd(ctx *middleware.Context) {
  445. ctx.Data["Title"] = "Reset Password"
  446. code := ctx.Query("code")
  447. if len(code) == 0 {
  448. ctx.Error(404)
  449. return
  450. }
  451. ctx.Data["Code"] = code
  452. ctx.Data["IsResetForm"] = true
  453. ctx.HTML(200, "user/reset_passwd")
  454. }
  455. func ResetPasswdPost(ctx *middleware.Context) {
  456. ctx.Data["Title"] = "Reset Password"
  457. code := ctx.Query("code")
  458. if len(code) == 0 {
  459. ctx.Error(404)
  460. return
  461. }
  462. ctx.Data["Code"] = code
  463. if u := models.VerifyUserActiveCode(code); u != nil {
  464. // Validate password length.
  465. passwd := ctx.Query("passwd")
  466. if len(passwd) < 6 || len(passwd) > 30 {
  467. ctx.Data["IsResetForm"] = true
  468. ctx.RenderWithErr("Password length should be in 6 and 30.", "user/reset_passwd", nil)
  469. return
  470. }
  471. u.Passwd = passwd
  472. u.Rands = models.GetUserSalt()
  473. u.Salt = models.GetUserSalt()
  474. u.EncodePasswd()
  475. if err := models.UpdateUser(u); err != nil {
  476. ctx.Handle(500, "user.ResetPasswd(UpdateUser)", err)
  477. return
  478. }
  479. log.Trace("%s User password reset: %s", ctx.Req.RequestURI, u.Name)
  480. ctx.Redirect("/user/login")
  481. return
  482. }
  483. ctx.Data["IsResetFailed"] = true
  484. ctx.HTML(200, "user/reset_passwd")
  485. }