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

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