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 8.8 kB

10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
10 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. ctx.Handle(500, "GetUserByName", err)
  97. return
  98. }
  99. act.ActAvatar = u.AvatarLink()
  100. feeds = append(feeds, act)
  101. }
  102. ctx.Data["Feeds"] = feeds
  103. ctx.HTML(200, DASHBOARD)
  104. }
  105. func Pulls(ctx *middleware.Context) {
  106. ctx.Data["Title"] = ctx.Tr("pull_requests")
  107. ctx.Data["PageIsDashboard"] = true
  108. ctx.Data["PageIsPulls"] = true
  109. if err := ctx.User.GetOrganizations(); err != nil {
  110. ctx.Handle(500, "GetOrganizations", err)
  111. return
  112. }
  113. ctx.Data["ContextUser"] = ctx.User
  114. ctx.HTML(200, PULLS)
  115. }
  116. func ShowSSHKeys(ctx *middleware.Context, uid int64) {
  117. keys, err := models.ListPublicKeys(uid)
  118. if err != nil {
  119. ctx.Handle(500, "ListPublicKeys", err)
  120. return
  121. }
  122. var buf bytes.Buffer
  123. for i := range keys {
  124. buf.WriteString(keys[i].OmitEmail())
  125. }
  126. ctx.RenderData(200, buf.Bytes())
  127. }
  128. func Profile(ctx *middleware.Context) {
  129. ctx.Data["Title"] = "Profile"
  130. ctx.Data["PageIsUserProfile"] = true
  131. uname := ctx.Params(":username")
  132. // Special handle for FireFox requests favicon.ico.
  133. if uname == "favicon.ico" {
  134. ctx.Redirect(setting.AppSubUrl + "/img/favicon.png")
  135. return
  136. }
  137. isShowKeys := false
  138. if strings.HasSuffix(uname, ".keys") {
  139. isShowKeys = true
  140. uname = strings.TrimSuffix(uname, ".keys")
  141. }
  142. u, err := models.GetUserByName(uname)
  143. if err != nil {
  144. if err == models.ErrUserNotExist {
  145. ctx.Handle(404, "GetUserByName", err)
  146. } else {
  147. ctx.Handle(500, "GetUserByName", err)
  148. }
  149. return
  150. }
  151. // Show SSH keys.
  152. if isShowKeys {
  153. ShowSSHKeys(ctx, u.Id)
  154. return
  155. }
  156. if u.IsOrganization() {
  157. ctx.Redirect(setting.AppSubUrl + "/org/" + u.Name)
  158. return
  159. }
  160. // For security reason, hide e-mail address for anonymous visitors.
  161. if !ctx.IsSigned {
  162. u.Email = ""
  163. }
  164. ctx.Data["Owner"] = u
  165. tab := ctx.Query("tab")
  166. ctx.Data["TabName"] = tab
  167. switch tab {
  168. case "activity":
  169. actions, err := models.GetFeeds(u.Id, 0, false)
  170. if err != nil {
  171. ctx.Handle(500, "GetFeeds", err)
  172. return
  173. }
  174. feeds := make([]*models.Action, 0, len(actions))
  175. for _, act := range actions {
  176. // FIXME: cache results?
  177. u, err := models.GetUserByName(act.ActUserName)
  178. if err != nil {
  179. ctx.Handle(500, "GetUserByName", err)
  180. return
  181. }
  182. act.ActAvatar = u.AvatarLink()
  183. feeds = append(feeds, act)
  184. }
  185. ctx.Data["Feeds"] = feeds
  186. default:
  187. ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id)
  188. if err != nil {
  189. ctx.Handle(500, "GetRepositories", err)
  190. return
  191. }
  192. }
  193. ctx.HTML(200, PROFILE)
  194. }
  195. func Email2User(ctx *middleware.Context) {
  196. u, err := models.GetUserByEmail(ctx.Query("email"))
  197. if err != nil {
  198. if err == models.ErrUserNotExist {
  199. ctx.Handle(404, "user.Email2User(GetUserByEmail)", err)
  200. } else {
  201. ctx.Handle(500, "user.Email2User(GetUserByEmail)", err)
  202. }
  203. return
  204. }
  205. ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
  206. }
  207. func Issues(ctx *middleware.Context) {
  208. ctx.Data["Title"] = "Your Issues"
  209. viewType := ctx.Query("type")
  210. types := []string{"assigned", "created_by"}
  211. if !com.IsSliceContainsStr(types, viewType) {
  212. viewType = "all"
  213. }
  214. isShowClosed := ctx.Query("state") == "closed"
  215. var filterMode int
  216. switch viewType {
  217. case "assigned":
  218. filterMode = models.FM_ASSIGN
  219. case "created_by":
  220. filterMode = models.FM_CREATE
  221. }
  222. repoId, _ := com.StrTo(ctx.Query("repoid")).Int64()
  223. issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode)
  224. // Get all repositories.
  225. repos, err := models.GetRepositories(ctx.User.Id, true)
  226. if err != nil {
  227. ctx.Handle(500, "user.Issues(GetRepositories)", err)
  228. return
  229. }
  230. repoIds := make([]int64, 0, len(repos))
  231. showRepos := make([]*models.Repository, 0, len(repos))
  232. for _, repo := range repos {
  233. if repo.NumIssues == 0 {
  234. continue
  235. }
  236. repoIds = append(repoIds, repo.Id)
  237. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  238. issueStats.AllCount += int64(repo.NumOpenIssues)
  239. if isShowClosed {
  240. if repo.NumClosedIssues > 0 {
  241. if filterMode == models.FM_CREATE {
  242. repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  243. }
  244. showRepos = append(showRepos, repo)
  245. }
  246. } else {
  247. if repo.NumOpenIssues > 0 {
  248. if filterMode == models.FM_CREATE {
  249. repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  250. }
  251. showRepos = append(showRepos, repo)
  252. }
  253. }
  254. }
  255. if repoId > 0 {
  256. repoIds = []int64{repoId}
  257. }
  258. page, _ := com.StrTo(ctx.Query("page")).Int()
  259. // Get all issues.
  260. var ius []*models.IssueUser
  261. switch viewType {
  262. case "assigned":
  263. fallthrough
  264. case "created_by":
  265. ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode)
  266. default:
  267. ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page)
  268. }
  269. if err != nil {
  270. ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err)
  271. return
  272. }
  273. issues := make([]*models.Issue, len(ius))
  274. for i := range ius {
  275. issues[i], err = models.GetIssueById(ius[i].IssueId)
  276. if err != nil {
  277. if err == models.ErrIssueNotExist {
  278. log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueId)
  279. continue
  280. } else {
  281. ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueId), err)
  282. return
  283. }
  284. }
  285. issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId)
  286. if err != nil {
  287. if err == models.ErrRepoNotExist {
  288. log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId)
  289. continue
  290. } else {
  291. ctx.Handle(500, fmt.Sprintf("user.Issues(GetRepositoryById #%d)", issues[i].RepoId), err)
  292. return
  293. }
  294. }
  295. if err = issues[i].Repo.GetOwner(); err != nil {
  296. ctx.Handle(500, "user.Issues(GetOwner)", err)
  297. return
  298. }
  299. if err = issues[i].GetPoster(); err != nil {
  300. ctx.Handle(500, "user.Issues(GetUserById)", err)
  301. return
  302. }
  303. }
  304. ctx.Data["RepoId"] = repoId
  305. ctx.Data["Repos"] = showRepos
  306. ctx.Data["Issues"] = issues
  307. ctx.Data["ViewType"] = viewType
  308. ctx.Data["IssueStats"] = issueStats
  309. ctx.Data["IsShowClosed"] = isShowClosed
  310. if isShowClosed {
  311. ctx.Data["State"] = "closed"
  312. ctx.Data["ShowCount"] = issueStats.ClosedCount
  313. } else {
  314. ctx.Data["ShowCount"] = issueStats.OpenCount
  315. }
  316. ctx.HTML(200, ISSUES)
  317. }