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.

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