gitea源码

header.go 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user
  4. import (
  5. "net/url"
  6. "code.gitea.io/gitea/models/db"
  7. "code.gitea.io/gitea/models/organization"
  8. access_model "code.gitea.io/gitea/models/perm/access"
  9. project_model "code.gitea.io/gitea/models/project"
  10. repo_model "code.gitea.io/gitea/models/repo"
  11. "code.gitea.io/gitea/models/unit"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/git"
  14. "code.gitea.io/gitea/modules/gitrepo"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/markup"
  17. "code.gitea.io/gitea/modules/markup/markdown"
  18. "code.gitea.io/gitea/modules/optional"
  19. "code.gitea.io/gitea/modules/setting"
  20. "code.gitea.io/gitea/modules/util"
  21. "code.gitea.io/gitea/services/context"
  22. )
  23. // prepareContextForProfileBigAvatar set the context for big avatar view on the profile page
  24. func prepareContextForProfileBigAvatar(ctx *context.Context) {
  25. ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
  26. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
  27. if setting.Service.UserLocationMapURL != "" {
  28. ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location)
  29. }
  30. // Show OpenID URIs
  31. openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID)
  32. if err != nil {
  33. ctx.ServerError("GetUserOpenIDs", err)
  34. return
  35. }
  36. ctx.Data["OpenIDs"] = openIDs
  37. if len(ctx.ContextUser.Description) != 0 {
  38. content, err := markdown.RenderString(markup.NewRenderContext(ctx).WithMetas(markup.ComposeSimpleDocumentMetas()), ctx.ContextUser.Description)
  39. if err != nil {
  40. ctx.ServerError("RenderString", err)
  41. return
  42. }
  43. ctx.Data["RenderedDescription"] = content
  44. }
  45. orgs, err := db.Find[organization.Organization](ctx, organization.FindOrgOptions{
  46. UserID: ctx.ContextUser.ID,
  47. IncludeVisibility: organization.DoerViewOtherVisibility(ctx.Doer, ctx.ContextUser),
  48. ListOptions: db.ListOptions{
  49. Page: 1,
  50. // query one more result (without a separate counting) to see whether we need to add the "show more orgs" link
  51. PageSize: setting.UI.User.OrgPagingNum + 1,
  52. },
  53. })
  54. if err != nil {
  55. ctx.ServerError("FindOrgs", err)
  56. return
  57. }
  58. if len(orgs) > setting.UI.User.OrgPagingNum {
  59. orgs = orgs[:setting.UI.User.OrgPagingNum]
  60. ctx.Data["ShowMoreOrgs"] = true
  61. }
  62. ctx.Data["Orgs"] = orgs
  63. ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(ctx, orgs, ctx.Doer)
  64. badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser)
  65. if err != nil {
  66. ctx.ServerError("GetUserBadges", err)
  67. return
  68. }
  69. ctx.Data["Badges"] = badges
  70. // in case the numbers are already provided by other functions, no need to query again (which is slow)
  71. if _, ok := ctx.Data["NumFollowers"]; !ok {
  72. _, ctx.Data["NumFollowers"], _ = user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1})
  73. }
  74. if _, ok := ctx.Data["NumFollowing"]; !ok {
  75. _, ctx.Data["NumFollowing"], _ = user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1})
  76. }
  77. if ctx.Doer != nil {
  78. if block, err := user_model.GetBlocking(ctx, ctx.Doer.ID, ctx.ContextUser.ID); err != nil {
  79. ctx.ServerError("GetBlocking", err)
  80. } else {
  81. ctx.Data["UserBlocking"] = block
  82. }
  83. }
  84. }
  85. func FindOwnerProfileReadme(ctx *context.Context, doer *user_model.User, optProfileRepoName ...string) (profileDbRepo *repo_model.Repository, profileReadmeBlob *git.Blob) {
  86. profileRepoName := util.OptionalArg(optProfileRepoName, RepoNameProfile)
  87. profileDbRepo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, profileRepoName)
  88. if err != nil {
  89. if !repo_model.IsErrRepoNotExist(err) {
  90. log.Error("FindOwnerProfileReadme failed to GetRepositoryByName: %v", err)
  91. }
  92. return nil, nil
  93. }
  94. perm, err := access_model.GetUserRepoPermission(ctx, profileDbRepo, doer)
  95. if err != nil {
  96. log.Error("FindOwnerProfileReadme failed to GetRepositoryByName: %v", err)
  97. return nil, nil
  98. }
  99. if profileDbRepo.IsEmpty || !perm.CanRead(unit.TypeCode) {
  100. return nil, nil
  101. }
  102. profileGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, profileDbRepo)
  103. if err != nil {
  104. log.Error("FindOwnerProfileReadme failed to OpenRepository: %v", err)
  105. return nil, nil
  106. }
  107. commit, err := profileGitRepo.GetBranchCommit(profileDbRepo.DefaultBranch)
  108. if err != nil {
  109. log.Error("FindOwnerProfileReadme failed to GetBranchCommit: %v", err)
  110. return nil, nil
  111. }
  112. profileReadmeBlob, _ = commit.GetBlobByPath("README.md") // no need to handle this error
  113. return profileDbRepo, profileReadmeBlob
  114. }
  115. type PrepareOwnerHeaderResult struct {
  116. ProfilePublicRepo *repo_model.Repository
  117. ProfilePublicReadmeBlob *git.Blob
  118. ProfilePrivateRepo *repo_model.Repository
  119. ProfilePrivateReadmeBlob *git.Blob
  120. HasOrgProfileReadme bool
  121. }
  122. const (
  123. RepoNameProfilePrivate = ".profile-private"
  124. RepoNameProfile = ".profile"
  125. )
  126. func RenderUserOrgHeader(ctx *context.Context) (result *PrepareOwnerHeaderResult, err error) {
  127. ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
  128. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  129. ctx.Data["EnableFeed"] = setting.Other.EnableFeed
  130. ctx.Data["FeedURL"] = ctx.ContextUser.HomeLink()
  131. if err := loadHeaderCount(ctx); err != nil {
  132. return nil, err
  133. }
  134. result = &PrepareOwnerHeaderResult{}
  135. if ctx.ContextUser.IsOrganization() {
  136. result.ProfilePublicRepo, result.ProfilePublicReadmeBlob = FindOwnerProfileReadme(ctx, ctx.Doer)
  137. result.ProfilePrivateRepo, result.ProfilePrivateReadmeBlob = FindOwnerProfileReadme(ctx, ctx.Doer, RepoNameProfilePrivate)
  138. result.HasOrgProfileReadme = result.ProfilePublicReadmeBlob != nil || result.ProfilePrivateReadmeBlob != nil
  139. ctx.Data["HasOrgProfileReadme"] = result.HasOrgProfileReadme // many pages need it to show the "overview" tab
  140. } else {
  141. _, profileReadmeBlob := FindOwnerProfileReadme(ctx, ctx.Doer)
  142. ctx.Data["HasUserProfileReadme"] = profileReadmeBlob != nil
  143. prepareContextForProfileBigAvatar(ctx)
  144. }
  145. return result, nil
  146. }
  147. func loadHeaderCount(ctx *context.Context) error {
  148. repoCount, err := repo_model.CountRepository(ctx, repo_model.SearchRepoOptions{
  149. Actor: ctx.Doer,
  150. OwnerID: ctx.ContextUser.ID,
  151. Private: ctx.IsSigned,
  152. Collaborate: optional.Some(false),
  153. IncludeDescription: setting.UI.SearchRepoDescription,
  154. })
  155. if err != nil {
  156. return err
  157. }
  158. ctx.Data["RepoCount"] = repoCount
  159. var projectType project_model.Type
  160. if ctx.ContextUser.IsOrganization() {
  161. projectType = project_model.TypeOrganization
  162. } else {
  163. projectType = project_model.TypeIndividual
  164. }
  165. projectCount, err := db.Count[project_model.Project](ctx, project_model.SearchOptions{
  166. OwnerID: ctx.ContextUser.ID,
  167. IsClosed: optional.Some(false),
  168. Type: projectType,
  169. })
  170. if err != nil {
  171. return err
  172. }
  173. ctx.Data["ProjectCount"] = projectCount
  174. return nil
  175. }