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

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
Restricted users (#6274) * Restricted users (#4334): initial implementation * Add User.IsRestricted & UI to edit it * Pass user object instead of user id to places where IsRestricted flag matters * Restricted users: maintain access rows for all referenced repos (incl public) * Take logged in user & IsRestricted flag into account in org/repo listings, searches and accesses * Add basic repo access tests for restricted users Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Mention restricted users in the faq Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert unnecessary change `.isUserPartOfOrg` -> `.IsUserPartOfOrg` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Remove unnecessary `org.IsOrganization()` call Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert to an `int64` keyed `accessMap` * Add type `userAccess` * Add convenience func updateUserAccess() * Turn accessMap into a `map[int64]userAccess` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * or even better: `map[int64]*userAccess` * updateUserAccess(): use tighter syntax as suggested by lafriks * even tighter * Avoid extra loop * Don't disclose limited orgs to unauthenticated users * Don't assume block only applies to orgs * Use an array of `VisibleType` for filtering * fix yet another thinko * Ok - no need for u * Revert "Ok - no need for u" This reverts commit 5c3e886aabd5acd997a3b35687d322439732c200. Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv>
5 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
Restricted users (#6274) * Restricted users (#4334): initial implementation * Add User.IsRestricted & UI to edit it * Pass user object instead of user id to places where IsRestricted flag matters * Restricted users: maintain access rows for all referenced repos (incl public) * Take logged in user & IsRestricted flag into account in org/repo listings, searches and accesses * Add basic repo access tests for restricted users Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Mention restricted users in the faq Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert unnecessary change `.isUserPartOfOrg` -> `.IsUserPartOfOrg` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Remove unnecessary `org.IsOrganization()` call Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert to an `int64` keyed `accessMap` * Add type `userAccess` * Add convenience func updateUserAccess() * Turn accessMap into a `map[int64]userAccess` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * or even better: `map[int64]*userAccess` * updateUserAccess(): use tighter syntax as suggested by lafriks * even tighter * Avoid extra loop * Don't disclose limited orgs to unauthenticated users * Don't assume block only applies to orgs * Use an array of `VisibleType` for filtering * fix yet another thinko * Ok - no need for u * Revert "Ok - no need for u" This reverts commit 5c3e886aabd5acd997a3b35687d322439732c200. Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv>
5 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
API add/generalize pagination (#9452) * paginate results * fixed deadlock * prevented breaking change * updated swagger * go fmt * fixed find topic * go mod tidy * go mod vendor with go1.13.5 * fixed repo find topics * fixed unit test * added Limit method to Engine struct; use engine variable when provided; fixed gitignore * use ItemsPerPage for default pagesize; fix GetWatchers, getOrgUsersByOrgID and GetStargazers; fix GetAllCommits headers; reverted some changed behaviors * set Page value on Home route * improved memory allocations * fixed response headers * removed logfiles * fixed import order * import order * improved swagger * added function to get models.ListOptions from context * removed pagesize diff on unit test * fixed imports * removed unnecessary struct field * fixed go fmt * scoped PR * code improvements * code improvements * go mod tidy * fixed import order * fixed commit statuses session * fixed files headers * fixed headers; added pagination for notifications * go mod tidy * go fmt * removed Private from user search options; added setting.UI.IssuePagingNum as default valeu on repo's issues list * Apply suggestions from code review Co-Authored-By: 6543 <6543@obermui.de> Co-Authored-By: zeripath <art27@cantab.net> * fixed build error * CI.restart() * fixed merge conflicts resolve * fixed conflicts resolve * improved FindTrackedTimesOptions.ToOptions() method * added backwards compatibility on ListReleases request; fixed issue tracked time ToSession * fixed build error; fixed swagger template * fixed swagger template * fixed ListReleases backwards compatibility * added page to user search route Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath <art27@cantab.net>
5 years ago
Restricted users (#6274) * Restricted users (#4334): initial implementation * Add User.IsRestricted & UI to edit it * Pass user object instead of user id to places where IsRestricted flag matters * Restricted users: maintain access rows for all referenced repos (incl public) * Take logged in user & IsRestricted flag into account in org/repo listings, searches and accesses * Add basic repo access tests for restricted users Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Mention restricted users in the faq Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert unnecessary change `.isUserPartOfOrg` -> `.IsUserPartOfOrg` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Remove unnecessary `org.IsOrganization()` call Signed-off-by: Manush Dodunekov <manush@stendahls.se> * Revert to an `int64` keyed `accessMap` * Add type `userAccess` * Add convenience func updateUserAccess() * Turn accessMap into a `map[int64]userAccess` Signed-off-by: Manush Dodunekov <manush@stendahls.se> * or even better: `map[int64]*userAccess` * updateUserAccess(): use tighter syntax as suggested by lafriks * even tighter * Avoid extra loop * Don't disclose limited orgs to unauthenticated users * Don't assume block only applies to orgs * Use an array of `VisibleType` for filtering * fix yet another thinko * Ok - no need for u * Revert "Ok - no need for u" This reverts commit 5c3e886aabd5acd997a3b35687d322439732c200. Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv>
5 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. "code.gitea.io/gitea/services/badge"
  8. "errors"
  9. "fmt"
  10. "path"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  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/org"
  17. )
  18. // GetUserByName get user by name
  19. func GetUserByName(ctx *context.Context, name string) *models.User {
  20. user, err := models.GetUserByName(name)
  21. if err != nil {
  22. if models.IsErrUserNotExist(err) {
  23. ctx.NotFound("GetUserByName", nil)
  24. } else {
  25. ctx.ServerError("GetUserByName", err)
  26. }
  27. return nil
  28. }
  29. return user
  30. }
  31. // GetUserByParams returns user whose name is presented in URL paramenter.
  32. func GetUserByParams(ctx *context.Context) *models.User {
  33. return GetUserByName(ctx, ctx.Params(":username"))
  34. }
  35. // Profile render user's profile page
  36. func Profile(ctx *context.Context) {
  37. uname := ctx.Params(":username")
  38. // Special handle for FireFox requests favicon.ico.
  39. if uname == "favicon.ico" {
  40. ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
  41. return
  42. } else if strings.HasSuffix(uname, ".png") {
  43. ctx.Error(404)
  44. return
  45. }
  46. isShowKeys := false
  47. if strings.HasSuffix(uname, ".keys") {
  48. isShowKeys = true
  49. uname = strings.TrimSuffix(uname, ".keys")
  50. }
  51. isShowGPG := false
  52. if strings.HasSuffix(uname, ".gpg") {
  53. isShowGPG = true
  54. uname = strings.TrimSuffix(uname, ".gpg")
  55. }
  56. ctxUser := GetUserByName(ctx, uname)
  57. if ctx.Written() {
  58. return
  59. }
  60. // Show SSH keys.
  61. if isShowKeys {
  62. ShowSSHKeys(ctx, ctxUser.ID)
  63. return
  64. }
  65. // Show GPG keys.
  66. if isShowGPG {
  67. ShowGPGKeys(ctx, ctxUser.ID)
  68. return
  69. }
  70. if ctxUser.IsOrganization() {
  71. org.Home(ctx)
  72. return
  73. }
  74. // Show OpenID URIs
  75. openIDs, err := models.GetUserOpenIDs(ctxUser.ID)
  76. if err != nil {
  77. ctx.ServerError("GetUserOpenIDs", err)
  78. return
  79. }
  80. // Show user badges
  81. badges, err := badge.GetUserBadges(ctxUser.ID, models.ListOptions{Page: 1, PageSize: 5})
  82. if err != nil {
  83. ctx.ServerError("GetUserBadges", err)
  84. return
  85. }
  86. // Count user badges
  87. cnt, err := badge.CountUserBadges(ctxUser.ID)
  88. if err != nil {
  89. ctx.ServerError("CountUserBadges", err)
  90. return
  91. }
  92. ctx.Data["Title"] = ctxUser.DisplayName()
  93. ctx.Data["PageIsUserProfile"] = true
  94. ctx.Data["Owner"] = ctxUser
  95. ctx.Data["OpenIDs"] = openIDs
  96. ctx.Data["RecentBadges"] = badges
  97. ctx.Data["TotalBadges"] = cnt
  98. ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap
  99. ctx.Data["HeatmapUser"] = ctxUser.Name
  100. showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
  101. orgs, err := models.GetOrgsByUserID(ctxUser.ID, showPrivate)
  102. if err != nil {
  103. ctx.ServerError("GetOrgsByUserIDDesc", err)
  104. return
  105. }
  106. for _, org := range orgs {
  107. _, repoCount, err := models.SearchRepository(&models.SearchRepoOptions{
  108. OwnerID: org.ID,
  109. Private: ctx.IsSigned,
  110. Actor: ctx.User,
  111. })
  112. if err != nil {
  113. ctx.ServerError("SearchRepository", err)
  114. return
  115. }
  116. var opts = models.FindOrgMembersOpts{
  117. OrgID: org.ID,
  118. PublicOnly: true,
  119. }
  120. if ctx.User != nil {
  121. isMember, err := org.IsOrgMember(ctx.User.ID)
  122. if err != nil {
  123. ctx.Error(500, "IsOrgMember")
  124. return
  125. }
  126. opts.PublicOnly = !isMember && !ctx.User.IsAdmin
  127. }
  128. membersCount, err := models.CountOrgMembers(opts)
  129. if err != nil {
  130. ctx.ServerError("CountOrgMembers", err)
  131. return
  132. }
  133. org.NumMembers = int(membersCount)
  134. org.NumRepos = int(repoCount)
  135. }
  136. ctx.Data["Orgs"] = orgs
  137. ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User)
  138. tab := ctx.Query("tab")
  139. if tab == "" {
  140. tab = "activity"
  141. }
  142. ctx.Data["TabName"] = tab
  143. page := ctx.QueryInt("page")
  144. if page <= 0 {
  145. page = 1
  146. }
  147. topicOnly := ctx.QueryBool("topic")
  148. var (
  149. repos []*models.Repository
  150. count int64
  151. total int
  152. orderBy models.SearchOrderBy
  153. )
  154. ctx.Data["SortType"] = ctx.Query("sort")
  155. switch ctx.Query("sort") {
  156. case "newest":
  157. orderBy = models.SearchOrderByNewest
  158. case "oldest":
  159. orderBy = models.SearchOrderByOldest
  160. case "recentupdate":
  161. orderBy = models.SearchOrderByRecentUpdated
  162. case "leastupdate":
  163. orderBy = models.SearchOrderByLeastUpdated
  164. case "reversealphabetically":
  165. orderBy = models.SearchOrderByAlphabeticallyReverse
  166. case "alphabetically":
  167. orderBy = models.SearchOrderByAlphabetically
  168. case "downloadtimes":
  169. orderBy = models.SearchOrderByDownloadTimes
  170. case "moststars":
  171. orderBy = models.SearchOrderByStarsReverse
  172. case "feweststars":
  173. orderBy = models.SearchOrderByStars
  174. case "mostforks":
  175. orderBy = models.SearchOrderByForksReverse
  176. case "fewestforks":
  177. orderBy = models.SearchOrderByForks
  178. default:
  179. ctx.Data["SortType"] = "recentupdate"
  180. orderBy = models.SearchOrderByRecentUpdated
  181. }
  182. keyword := strings.Trim(ctx.Query("q"), " ")
  183. ctx.Data["Keyword"] = keyword
  184. switch tab {
  185. case "followers":
  186. items, err := ctxUser.GetFollowers(models.ListOptions{
  187. PageSize: setting.UI.User.RepoPagingNum,
  188. Page: page,
  189. })
  190. if err != nil {
  191. ctx.ServerError("GetFollowers", err)
  192. return
  193. }
  194. ctx.Data["Cards"] = items
  195. total = ctxUser.NumFollowers
  196. case "following":
  197. items, err := ctxUser.GetFollowing(models.ListOptions{
  198. PageSize: setting.UI.User.RepoPagingNum,
  199. Page: page,
  200. })
  201. if err != nil {
  202. ctx.ServerError("GetFollowing", err)
  203. return
  204. }
  205. ctx.Data["Cards"] = items
  206. total = ctxUser.NumFollowing
  207. case "activity":
  208. retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
  209. Actor: ctx.User,
  210. IncludePrivate: showPrivate,
  211. OnlyPerformedBy: true,
  212. IncludeDeleted: false,
  213. })
  214. if ctx.Written() {
  215. return
  216. }
  217. case "stars":
  218. ctx.Data["PageIsProfileStarList"] = true
  219. repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
  220. ListOptions: models.ListOptions{
  221. PageSize: setting.UI.User.RepoPagingNum,
  222. Page: page,
  223. },
  224. Actor: ctx.User,
  225. Keyword: keyword,
  226. OrderBy: orderBy,
  227. Private: ctx.IsSigned,
  228. StarredByID: ctxUser.ID,
  229. Collaborate: util.OptionalBoolFalse,
  230. TopicOnly: topicOnly,
  231. IncludeDescription: setting.UI.SearchRepoDescription,
  232. })
  233. if err != nil {
  234. ctx.ServerError("SearchRepository", err)
  235. return
  236. }
  237. total = int(count)
  238. case "datasets":
  239. var isOwner = false
  240. if ctx.User != nil && ctx.User.ID == ctxUser.ID {
  241. isOwner = true
  242. }
  243. datasetSearchOptions := &models.SearchDatasetOptions{
  244. Keyword: keyword,
  245. OwnerID: ctxUser.ID,
  246. SearchOrderBy: orderBy,
  247. IsOwner: isOwner,
  248. ListOptions: models.ListOptions{
  249. Page: page,
  250. PageSize: setting.UI.User.RepoPagingNum,
  251. },
  252. CloudBrainType: -1,
  253. }
  254. if len(datasetSearchOptions.SearchOrderBy) == 0 {
  255. datasetSearchOptions.SearchOrderBy = models.SearchOrderByAlphabetically
  256. }
  257. datasets, count, err := models.SearchDataset(datasetSearchOptions)
  258. if err != nil {
  259. ctx.ServerError("SearchDatasets", err)
  260. }
  261. total = int(count)
  262. ctx.Data["Datasets"] = datasets
  263. case "repository":
  264. repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
  265. ListOptions: models.ListOptions{
  266. PageSize: setting.UI.User.RepoPagingNum,
  267. Page: page,
  268. },
  269. Actor: ctx.User,
  270. Keyword: keyword,
  271. OwnerID: ctxUser.ID,
  272. OrderBy: orderBy,
  273. Private: ctx.IsSigned,
  274. Collaborate: util.OptionalBoolFalse,
  275. TopicOnly: topicOnly,
  276. IncludeDescription: setting.UI.SearchRepoDescription,
  277. })
  278. if err != nil {
  279. ctx.ServerError("SearchRepository", err)
  280. return
  281. }
  282. total = int(count)
  283. case "badge":
  284. allBadges, err := badge.GetUserAllBadges(ctxUser.ID)
  285. if err != nil {
  286. ctx.ServerError("GetUserAllBadges", err)
  287. return
  288. }
  289. ctx.Data["AllBadges"] = allBadges
  290. default:
  291. ctx.ServerError("tab error", errors.New("tab error"))
  292. return
  293. }
  294. ctx.Data["Repos"] = repos
  295. ctx.Data["Total"] = total
  296. pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5)
  297. pager.SetDefaultParams(ctx)
  298. ctx.Data["Page"] = pager
  299. ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.User.ID)
  300. ctx.HTML(200, tplProfile)
  301. }
  302. // Action response for follow/unfollow user request
  303. func Action(ctx *context.Context) {
  304. u := GetUserByParams(ctx)
  305. if ctx.Written() {
  306. return
  307. }
  308. var err error
  309. switch ctx.Params(":action") {
  310. case "follow":
  311. err = models.FollowUser(ctx.User.ID, u.ID)
  312. case "unfollow":
  313. err = models.UnfollowUser(ctx.User.ID, u.ID)
  314. }
  315. if err != nil {
  316. ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.Params(":action")), err)
  317. return
  318. }
  319. ctx.RedirectToFirst(ctx.Query("redirect_to"), u.HomeLink())
  320. }