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.

profile.go 7.5 kB

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