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.

376 lines
8.9 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
  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. "bytes"
  7. "fmt"
  8. "strings"
  9. "github.com/Unknwon/com"
  10. "github.com/gogits/gogs/models"
  11. "github.com/gogits/gogs/modules/base"
  12. "github.com/gogits/gogs/modules/log"
  13. "github.com/gogits/gogs/modules/middleware"
  14. "github.com/gogits/gogs/modules/setting"
  15. )
  16. const (
  17. DASHBOARD base.TplName = "user/dashboard/dashboard"
  18. PULLS base.TplName = "user/dashboard/pulls"
  19. ISSUES base.TplName = "user/issues"
  20. STARS base.TplName = "user/stars"
  21. PROFILE base.TplName = "user/profile"
  22. )
  23. func Dashboard(ctx *middleware.Context) {
  24. ctx.Data["Title"] = ctx.Tr("dashboard")
  25. ctx.Data["PageIsDashboard"] = true
  26. ctx.Data["PageIsNews"] = true
  27. var ctxUser *models.User
  28. // Check context type.
  29. orgName := ctx.Params(":org")
  30. if len(orgName) > 0 {
  31. // Organization.
  32. org, err := models.GetUserByName(orgName)
  33. if err != nil {
  34. if err == models.ErrUserNotExist {
  35. ctx.Handle(404, "GetUserByName", err)
  36. } else {
  37. ctx.Handle(500, "GetUserByName", err)
  38. }
  39. return
  40. }
  41. ctxUser = org
  42. } else {
  43. // Normal user.
  44. ctxUser = ctx.User
  45. collaborates, err := models.GetCollaborativeRepos(ctxUser.Name)
  46. if err != nil {
  47. ctx.Handle(500, "GetCollaborativeRepos", err)
  48. return
  49. }
  50. ctx.Data["CollaborateCount"] = len(collaborates)
  51. ctx.Data["CollaborativeRepos"] = collaborates
  52. }
  53. ctx.Data["ContextUser"] = ctxUser
  54. if err := ctx.User.GetOrganizations(); err != nil {
  55. ctx.Handle(500, "GetOrganizations", err)
  56. return
  57. }
  58. ctx.Data["Orgs"] = ctx.User.Orgs
  59. repos, err := models.GetRepositories(ctxUser.Id, true)
  60. if err != nil {
  61. ctx.Handle(500, "GetRepositories", err)
  62. return
  63. }
  64. ctx.Data["Repos"] = repos
  65. // Get mirror repositories.
  66. mirrors := make([]*models.Repository, 0, len(repos)/2)
  67. for _, repo := range repos {
  68. if repo.IsMirror {
  69. if err = repo.GetMirror(); err != nil {
  70. ctx.Handle(500, "GetMirror: "+repo.Name, err)
  71. return
  72. }
  73. mirrors = append(mirrors, repo)
  74. }
  75. }
  76. ctx.Data["MirrorCount"] = len(mirrors)
  77. ctx.Data["Mirrors"] = mirrors
  78. // Get feeds.
  79. actions, err := models.GetFeeds(ctxUser.Id, 0, false)
  80. if err != nil {
  81. ctx.Handle(500, "GetFeeds", err)
  82. return
  83. }
  84. // Check access of private repositories.
  85. feeds := make([]*models.Action, 0, len(actions))
  86. for _, act := range actions {
  87. if act.IsPrivate {
  88. if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
  89. models.READABLE); !has {
  90. continue
  91. }
  92. }
  93. // FIXME: cache results?
  94. u, err := models.GetUserByName(act.ActUserName)
  95. if err != nil {
  96. if err == models.ErrUserNotExist {
  97. continue
  98. }
  99. ctx.Handle(500, "GetUserByName", err)
  100. return
  101. }
  102. act.ActAvatar = u.AvatarLink()
  103. feeds = append(feeds, act)
  104. }
  105. ctx.Data["Feeds"] = feeds
  106. ctx.HTML(200, DASHBOARD)
  107. }
  108. func Pulls(ctx *middleware.Context) {
  109. ctx.Data["Title"] = ctx.Tr("pull_requests")
  110. ctx.Data["PageIsDashboard"] = true
  111. ctx.Data["PageIsPulls"] = true
  112. if err := ctx.User.GetOrganizations(); err != nil {
  113. ctx.Handle(500, "GetOrganizations", err)
  114. return
  115. }
  116. ctx.Data["ContextUser"] = ctx.User
  117. ctx.HTML(200, PULLS)
  118. }
  119. func ShowSSHKeys(ctx *middleware.Context, uid int64) {
  120. keys, err := models.ListPublicKeys(uid)
  121. if err != nil {
  122. ctx.Handle(500, "ListPublicKeys", err)
  123. return
  124. }
  125. var buf bytes.Buffer
  126. for i := range keys {
  127. buf.WriteString(keys[i].OmitEmail())
  128. }
  129. ctx.RenderData(200, buf.Bytes())
  130. }
  131. func Profile(ctx *middleware.Context) {
  132. ctx.Data["Title"] = "Profile"
  133. ctx.Data["PageIsUserProfile"] = true
  134. uname := ctx.Params(":username")
  135. // Special handle for FireFox requests favicon.ico.
  136. if uname == "favicon.ico" {
  137. ctx.Redirect(setting.AppSubUrl + "/img/favicon.png")
  138. return
  139. }
  140. isShowKeys := false
  141. if strings.HasSuffix(uname, ".keys") {
  142. isShowKeys = true
  143. uname = strings.TrimSuffix(uname, ".keys")
  144. }
  145. u, err := models.GetUserByName(uname)
  146. if err != nil {
  147. if err == models.ErrUserNotExist {
  148. ctx.Handle(404, "GetUserByName", err)
  149. } else {
  150. ctx.Handle(500, "GetUserByName", err)
  151. }
  152. return
  153. }
  154. // Show SSH keys.
  155. if isShowKeys {
  156. ShowSSHKeys(ctx, u.Id)
  157. return
  158. }
  159. if u.IsOrganization() {
  160. ctx.Redirect(setting.AppSubUrl + "/org/" + u.Name)
  161. return
  162. }
  163. // For security reason, hide e-mail address for anonymous visitors.
  164. if !ctx.IsSigned {
  165. u.Email = ""
  166. }
  167. ctx.Data["Owner"] = u
  168. tab := ctx.Query("tab")
  169. ctx.Data["TabName"] = tab
  170. switch tab {
  171. case "activity":
  172. actions, err := models.GetFeeds(u.Id, 0, false)
  173. if err != nil {
  174. ctx.Handle(500, "GetFeeds", err)
  175. return
  176. }
  177. feeds := make([]*models.Action, 0, len(actions))
  178. for _, act := range actions {
  179. if act.IsPrivate {
  180. if !ctx.IsSigned {
  181. continue
  182. }
  183. if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
  184. models.READABLE); !has {
  185. continue
  186. }
  187. }
  188. // FIXME: cache results?
  189. u, err := models.GetUserByName(act.ActUserName)
  190. if err != nil {
  191. if err == models.ErrUserNotExist {
  192. continue
  193. }
  194. ctx.Handle(500, "GetUserByName", err)
  195. return
  196. }
  197. act.ActAvatar = u.AvatarLink()
  198. feeds = append(feeds, act)
  199. }
  200. ctx.Data["Feeds"] = feeds
  201. default:
  202. ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id)
  203. if err != nil {
  204. ctx.Handle(500, "GetRepositories", err)
  205. return
  206. }
  207. }
  208. ctx.HTML(200, PROFILE)
  209. }
  210. func Email2User(ctx *middleware.Context) {
  211. u, err := models.GetUserByEmail(ctx.Query("email"))
  212. if err != nil {
  213. if err == models.ErrUserNotExist {
  214. ctx.Handle(404, "user.Email2User(GetUserByEmail)", err)
  215. } else {
  216. ctx.Handle(500, "user.Email2User(GetUserByEmail)", err)
  217. }
  218. return
  219. }
  220. ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
  221. }
  222. func Issues(ctx *middleware.Context) {
  223. ctx.Data["Title"] = "Your Issues"
  224. viewType := ctx.Query("type")
  225. types := []string{"assigned", "created_by"}
  226. if !com.IsSliceContainsStr(types, viewType) {
  227. viewType = "all"
  228. }
  229. isShowClosed := ctx.Query("state") == "closed"
  230. var filterMode int
  231. switch viewType {
  232. case "assigned":
  233. filterMode = models.FM_ASSIGN
  234. case "created_by":
  235. filterMode = models.FM_CREATE
  236. }
  237. repoId, _ := com.StrTo(ctx.Query("repoid")).Int64()
  238. issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode)
  239. // Get all repositories.
  240. repos, err := models.GetRepositories(ctx.User.Id, true)
  241. if err != nil {
  242. ctx.Handle(500, "user.Issues(GetRepositories)", err)
  243. return
  244. }
  245. repoIds := make([]int64, 0, len(repos))
  246. showRepos := make([]*models.Repository, 0, len(repos))
  247. for _, repo := range repos {
  248. if repo.NumIssues == 0 {
  249. continue
  250. }
  251. repoIds = append(repoIds, repo.Id)
  252. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  253. issueStats.AllCount += int64(repo.NumOpenIssues)
  254. if isShowClosed {
  255. if repo.NumClosedIssues > 0 {
  256. if filterMode == models.FM_CREATE {
  257. repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  258. }
  259. showRepos = append(showRepos, repo)
  260. }
  261. } else {
  262. if repo.NumOpenIssues > 0 {
  263. if filterMode == models.FM_CREATE {
  264. repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  265. }
  266. showRepos = append(showRepos, repo)
  267. }
  268. }
  269. }
  270. if repoId > 0 {
  271. repoIds = []int64{repoId}
  272. }
  273. page, _ := com.StrTo(ctx.Query("page")).Int()
  274. // Get all issues.
  275. var ius []*models.IssueUser
  276. switch viewType {
  277. case "assigned":
  278. fallthrough
  279. case "created_by":
  280. ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode)
  281. default:
  282. ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page)
  283. }
  284. if err != nil {
  285. ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err)
  286. return
  287. }
  288. issues := make([]*models.Issue, len(ius))
  289. for i := range ius {
  290. issues[i], err = models.GetIssueById(ius[i].IssueId)
  291. if err != nil {
  292. if err == models.ErrIssueNotExist {
  293. log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueId)
  294. continue
  295. } else {
  296. ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueId), err)
  297. return
  298. }
  299. }
  300. issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId)
  301. if err != nil {
  302. if err == models.ErrRepoNotExist {
  303. log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId)
  304. continue
  305. } else {
  306. ctx.Handle(500, fmt.Sprintf("user.Issues(GetRepositoryById #%d)", issues[i].RepoId), err)
  307. return
  308. }
  309. }
  310. if err = issues[i].Repo.GetOwner(); err != nil {
  311. ctx.Handle(500, "user.Issues(GetOwner)", err)
  312. return
  313. }
  314. if err = issues[i].GetPoster(); err != nil {
  315. ctx.Handle(500, "user.Issues(GetUserById)", err)
  316. return
  317. }
  318. }
  319. ctx.Data["RepoId"] = repoId
  320. ctx.Data["Repos"] = showRepos
  321. ctx.Data["Issues"] = issues
  322. ctx.Data["ViewType"] = viewType
  323. ctx.Data["IssueStats"] = issueStats
  324. ctx.Data["IsShowClosed"] = isShowClosed
  325. if isShowClosed {
  326. ctx.Data["State"] = "closed"
  327. ctx.Data["ShowCount"] = issueStats.ClosedCount
  328. } else {
  329. ctx.Data["ShowCount"] = issueStats.OpenCount
  330. }
  331. ctx.HTML(200, ISSUES)
  332. }