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.

profile.go 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package user
  6. import (
  7. "fmt"
  8. "path"
  9. "strings"
  10. "github.com/Unknwon/paginater"
  11. "code.gitea.io/gitea/models"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/util"
  16. "code.gitea.io/gitea/routers/repo"
  17. )
  18. const (
  19. tplFollowers base.TplName = "user/meta/followers"
  20. tplStars base.TplName = "user/meta/stars"
  21. )
  22. // GetUserByName get user by name
  23. func GetUserByName(ctx *context.Context, name string) *models.User {
  24. user, err := models.GetUserByName(name)
  25. if err != nil {
  26. if models.IsErrUserNotExist(err) {
  27. ctx.NotFound("GetUserByName", nil)
  28. } else {
  29. ctx.ServerError("GetUserByName", err)
  30. }
  31. return nil
  32. }
  33. return user
  34. }
  35. // GetUserByParams returns user whose name is presented in URL paramenter.
  36. func GetUserByParams(ctx *context.Context) *models.User {
  37. return GetUserByName(ctx, ctx.Params(":username"))
  38. }
  39. // Profile render user's profile page
  40. func Profile(ctx *context.Context) {
  41. uname := ctx.Params(":username")
  42. // Special handle for FireFox requests favicon.ico.
  43. if uname == "favicon.ico" {
  44. ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
  45. return
  46. } else if strings.HasSuffix(uname, ".png") {
  47. ctx.Error(404)
  48. return
  49. }
  50. isShowKeys := false
  51. if strings.HasSuffix(uname, ".keys") {
  52. isShowKeys = true
  53. }
  54. ctxUser := GetUserByName(ctx, strings.TrimSuffix(uname, ".keys"))
  55. if ctx.Written() {
  56. return
  57. }
  58. // Show SSH keys.
  59. if isShowKeys {
  60. ShowSSHKeys(ctx, ctxUser.ID)
  61. return
  62. }
  63. if ctxUser.IsOrganization() {
  64. showOrgProfile(ctx)
  65. return
  66. }
  67. // Show OpenID URIs
  68. openIDs, err := models.GetUserOpenIDs(ctxUser.ID)
  69. if err != nil {
  70. ctx.ServerError("GetUserOpenIDs", err)
  71. return
  72. }
  73. ctx.Data["Title"] = ctxUser.DisplayName()
  74. ctx.Data["PageIsUserProfile"] = true
  75. ctx.Data["Owner"] = ctxUser
  76. ctx.Data["OpenIDs"] = openIDs
  77. ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap
  78. ctx.Data["HeatmapUser"] = ctxUser.Name
  79. showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
  80. orgs, err := models.GetOrgsByUserID(ctxUser.ID, showPrivate)
  81. if err != nil {
  82. ctx.ServerError("GetOrgsByUserIDDesc", err)
  83. return
  84. }
  85. ctx.Data["Orgs"] = orgs
  86. ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User)
  87. tab := ctx.Query("tab")
  88. ctx.Data["TabName"] = tab
  89. page := ctx.QueryInt("page")
  90. if page <= 0 {
  91. page = 1
  92. }
  93. topicOnly := ctx.QueryBool("topic")
  94. var (
  95. repos []*models.Repository
  96. count int64
  97. orderBy models.SearchOrderBy
  98. )
  99. ctx.Data["SortType"] = ctx.Query("sort")
  100. switch ctx.Query("sort") {
  101. case "newest":
  102. orderBy = models.SearchOrderByNewest
  103. case "oldest":
  104. orderBy = models.SearchOrderByOldest
  105. case "recentupdate":
  106. orderBy = models.SearchOrderByRecentUpdated
  107. case "leastupdate":
  108. orderBy = models.SearchOrderByLeastUpdated
  109. case "reversealphabetically":
  110. orderBy = models.SearchOrderByAlphabeticallyReverse
  111. case "alphabetically":
  112. orderBy = models.SearchOrderByAlphabetically
  113. case "moststars":
  114. orderBy = models.SearchOrderByStarsReverse
  115. case "feweststars":
  116. orderBy = models.SearchOrderByStars
  117. case "mostforks":
  118. orderBy = models.SearchOrderByForksReverse
  119. case "fewestforks":
  120. orderBy = models.SearchOrderByForks
  121. default:
  122. ctx.Data["SortType"] = "recentupdate"
  123. orderBy = models.SearchOrderByRecentUpdated
  124. }
  125. keyword := strings.Trim(ctx.Query("q"), " ")
  126. ctx.Data["Keyword"] = keyword
  127. switch tab {
  128. case "activity":
  129. retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
  130. IncludePrivate: showPrivate,
  131. OnlyPerformedBy: true,
  132. IncludeDeleted: false,
  133. })
  134. if ctx.Written() {
  135. return
  136. }
  137. case "stars":
  138. ctx.Data["PageIsProfileStarList"] = true
  139. if len(keyword) == 0 {
  140. repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
  141. if err != nil {
  142. ctx.ServerError("GetStarredRepos", err)
  143. return
  144. }
  145. count, err = ctxUser.GetStarredRepoCount(showPrivate)
  146. if err != nil {
  147. ctx.ServerError("GetStarredRepoCount", err)
  148. return
  149. }
  150. } else {
  151. repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
  152. Keyword: keyword,
  153. OwnerID: ctxUser.ID,
  154. OrderBy: orderBy,
  155. Private: showPrivate,
  156. Page: page,
  157. PageSize: setting.UI.User.RepoPagingNum,
  158. Starred: true,
  159. Collaborate: util.OptionalBoolFalse,
  160. TopicOnly: topicOnly,
  161. })
  162. if err != nil {
  163. ctx.ServerError("SearchRepositoryByName", err)
  164. return
  165. }
  166. }
  167. ctx.Data["Repos"] = repos
  168. ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
  169. ctx.Data["Total"] = count
  170. default:
  171. if len(keyword) == 0 {
  172. var total int
  173. repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
  174. if err != nil {
  175. ctx.ServerError("GetRepositories", err)
  176. return
  177. }
  178. ctx.Data["Repos"] = repos
  179. if showPrivate {
  180. total = ctxUser.NumRepos
  181. } else {
  182. count, err := models.GetPublicRepositoryCount(ctxUser)
  183. if err != nil {
  184. ctx.ServerError("GetPublicRepositoryCount", err)
  185. return
  186. }
  187. total = int(count)
  188. }
  189. ctx.Data["Page"] = paginater.New(total, setting.UI.User.RepoPagingNum, page, 5)
  190. ctx.Data["Total"] = total
  191. } else {
  192. repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
  193. Keyword: keyword,
  194. OwnerID: ctxUser.ID,
  195. OrderBy: orderBy,
  196. Private: showPrivate,
  197. Page: page,
  198. IsProfile: true,
  199. PageSize: setting.UI.User.RepoPagingNum,
  200. Collaborate: util.OptionalBoolFalse,
  201. TopicOnly: topicOnly,
  202. })
  203. if err != nil {
  204. ctx.ServerError("SearchRepositoryByName", err)
  205. return
  206. }
  207. ctx.Data["Repos"] = repos
  208. ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
  209. ctx.Data["Total"] = count
  210. }
  211. }
  212. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
  213. ctx.HTML(200, tplProfile)
  214. }
  215. // Followers render user's followers page
  216. func Followers(ctx *context.Context) {
  217. u := GetUserByParams(ctx)
  218. if ctx.Written() {
  219. return
  220. }
  221. ctx.Data["Title"] = u.DisplayName()
  222. ctx.Data["CardsTitle"] = ctx.Tr("user.followers")
  223. ctx.Data["PageIsFollowers"] = true
  224. ctx.Data["Owner"] = u
  225. repo.RenderUserCards(ctx, u.NumFollowers, u.GetFollowers, tplFollowers)
  226. }
  227. // Following render user's followering page
  228. func Following(ctx *context.Context) {
  229. u := GetUserByParams(ctx)
  230. if ctx.Written() {
  231. return
  232. }
  233. ctx.Data["Title"] = u.DisplayName()
  234. ctx.Data["CardsTitle"] = ctx.Tr("user.following")
  235. ctx.Data["PageIsFollowing"] = true
  236. ctx.Data["Owner"] = u
  237. repo.RenderUserCards(ctx, u.NumFollowing, u.GetFollowing, tplFollowers)
  238. }
  239. // Action response for follow/unfollow user request
  240. func Action(ctx *context.Context) {
  241. u := GetUserByParams(ctx)
  242. if ctx.Written() {
  243. return
  244. }
  245. var err error
  246. switch ctx.Params(":action") {
  247. case "follow":
  248. err = models.FollowUser(ctx.User.ID, u.ID)
  249. case "unfollow":
  250. err = models.UnfollowUser(ctx.User.ID, u.ID)
  251. }
  252. if err != nil {
  253. ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  254. return
  255. }
  256. ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink())
  257. }