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

10 years ago
10 years ago
11 years ago
10 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
10 years ago
10 years ago
10 years ago
10 years ago
10 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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. }
  136. ctx.RenderData(200, buf.Bytes())
  137. }
  138. func Profile(ctx *middleware.Context) {
  139. ctx.Data["Title"] = "Profile"
  140. ctx.Data["PageIsUserProfile"] = true
  141. uname := ctx.Params(":username")
  142. // Special handle for FireFox requests favicon.ico.
  143. if uname == "favicon.ico" {
  144. ctx.Redirect(setting.AppSubUrl + "/img/favicon.png")
  145. return
  146. }
  147. isShowKeys := false
  148. if strings.HasSuffix(uname, ".keys") {
  149. isShowKeys = true
  150. uname = strings.TrimSuffix(uname, ".keys")
  151. }
  152. u, err := models.GetUserByName(uname)
  153. if err != nil {
  154. if err == models.ErrUserNotExist {
  155. ctx.Handle(404, "GetUserByName", err)
  156. } else {
  157. ctx.Handle(500, "GetUserByName", err)
  158. }
  159. return
  160. }
  161. // Show SSH keys.
  162. if isShowKeys {
  163. ShowSSHKeys(ctx, u.Id)
  164. return
  165. }
  166. if u.IsOrganization() {
  167. ctx.Redirect(setting.AppSubUrl + "/org/" + u.Name)
  168. return
  169. }
  170. // For security reason, hide e-mail address for anonymous visitors.
  171. if !ctx.IsSigned {
  172. u.Email = ""
  173. }
  174. ctx.Data["Owner"] = u
  175. tab := ctx.Query("tab")
  176. ctx.Data["TabName"] = tab
  177. switch tab {
  178. case "activity":
  179. actions, err := models.GetFeeds(u.Id, 0, false)
  180. if err != nil {
  181. ctx.Handle(500, "GetFeeds", err)
  182. return
  183. }
  184. feeds := make([]*models.Action, 0, len(actions))
  185. for _, act := range actions {
  186. if act.IsPrivate {
  187. if !ctx.IsSigned {
  188. continue
  189. }
  190. // This prevents having to retrieve the repository for each action
  191. repo := &models.Repository{Id: act.RepoID, IsPrivate: true}
  192. if act.RepoUserName != ctx.User.LowerName {
  193. if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has {
  194. continue
  195. }
  196. }
  197. }
  198. // FIXME: cache results?
  199. u, err := models.GetUserByName(act.ActUserName)
  200. if err != nil {
  201. if err == models.ErrUserNotExist {
  202. continue
  203. }
  204. ctx.Handle(500, "GetUserByName", err)
  205. return
  206. }
  207. act.ActAvatar = u.AvatarLink()
  208. feeds = append(feeds, act)
  209. }
  210. ctx.Data["Feeds"] = feeds
  211. default:
  212. ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id)
  213. if err != nil {
  214. ctx.Handle(500, "GetRepositories", err)
  215. return
  216. }
  217. }
  218. ctx.HTML(200, PROFILE)
  219. }
  220. func Email2User(ctx *middleware.Context) {
  221. u, err := models.GetUserByEmail(ctx.Query("email"))
  222. if err != nil {
  223. if err == models.ErrUserNotExist {
  224. ctx.Handle(404, "user.Email2User(GetUserByEmail)", err)
  225. } else {
  226. ctx.Handle(500, "user.Email2User(GetUserByEmail)", err)
  227. }
  228. return
  229. }
  230. ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
  231. }
  232. func Issues(ctx *middleware.Context) {
  233. ctx.Data["Title"] = ctx.Tr("issues")
  234. ctx.Data["PageIsDashboard"] = true
  235. ctx.Data["PageIsIssues"] = true
  236. viewType := ctx.Query("type")
  237. types := []string{"assigned", "created_by"}
  238. if !com.IsSliceContainsStr(types, viewType) {
  239. viewType = "all"
  240. }
  241. isShowClosed := ctx.Query("state") == "closed"
  242. var filterMode int
  243. switch viewType {
  244. case "assigned":
  245. filterMode = models.FM_ASSIGN
  246. case "created_by":
  247. filterMode = models.FM_CREATE
  248. }
  249. repoId, _ := com.StrTo(ctx.Query("repoid")).Int64()
  250. issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode)
  251. // Get all repositories.
  252. repos, err := models.GetRepositories(ctx.User.Id, true)
  253. if err != nil {
  254. ctx.Handle(500, "user.Issues(GetRepositories)", err)
  255. return
  256. }
  257. repoIds := make([]int64, 0, len(repos))
  258. showRepos := make([]*models.Repository, 0, len(repos))
  259. for _, repo := range repos {
  260. if repo.NumIssues == 0 {
  261. continue
  262. }
  263. repoIds = append(repoIds, repo.Id)
  264. repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
  265. issueStats.AllCount += int64(repo.NumOpenIssues)
  266. if isShowClosed {
  267. if repo.NumClosedIssues > 0 {
  268. if filterMode == models.FM_CREATE {
  269. repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  270. }
  271. showRepos = append(showRepos, repo)
  272. }
  273. } else {
  274. if repo.NumOpenIssues > 0 {
  275. if filterMode == models.FM_CREATE {
  276. repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed))
  277. }
  278. showRepos = append(showRepos, repo)
  279. }
  280. }
  281. }
  282. if repoId > 0 {
  283. repoIds = []int64{repoId}
  284. }
  285. page, _ := com.StrTo(ctx.Query("page")).Int()
  286. // Get all issues.
  287. var ius []*models.IssueUser
  288. switch viewType {
  289. case "assigned":
  290. fallthrough
  291. case "created_by":
  292. ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode)
  293. default:
  294. ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page)
  295. }
  296. if err != nil {
  297. ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err)
  298. return
  299. }
  300. issues := make([]*models.Issue, len(ius))
  301. for i := range ius {
  302. issues[i], err = models.GetIssueById(ius[i].IssueId)
  303. if err != nil {
  304. if err == models.ErrIssueNotExist {
  305. log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueId)
  306. continue
  307. } else {
  308. ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueId), err)
  309. return
  310. }
  311. }
  312. issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId)
  313. if err != nil {
  314. if models.IsErrRepoNotExist(err) {
  315. log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId)
  316. continue
  317. } else {
  318. ctx.Handle(500, fmt.Sprintf("user.Issues(GetRepositoryById #%d)", issues[i].RepoId), err)
  319. return
  320. }
  321. }
  322. if err = issues[i].Repo.GetOwner(); err != nil {
  323. ctx.Handle(500, "user.Issues(GetOwner)", err)
  324. return
  325. }
  326. if err = issues[i].GetPoster(); err != nil {
  327. ctx.Handle(500, "user.Issues(GetUserById)", err)
  328. return
  329. }
  330. }
  331. ctx.Data["RepoId"] = repoId
  332. ctx.Data["Repos"] = showRepos
  333. ctx.Data["Issues"] = issues
  334. ctx.Data["ViewType"] = viewType
  335. ctx.Data["IssueStats"] = issueStats
  336. ctx.Data["IsShowClosed"] = isShowClosed
  337. if isShowClosed {
  338. ctx.Data["State"] = "closed"
  339. ctx.Data["ShowCount"] = issueStats.ClosedCount
  340. } else {
  341. ctx.Data["ShowCount"] = issueStats.OpenCount
  342. }
  343. ctx.Data["ContextUser"] = ctx.User
  344. ctx.HTML(200, ISSUES)
  345. }