code.gitea.io/gitea@v1.21.7/routers/web/shared/user/header.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package user 5 6 import ( 7 "code.gitea.io/gitea/models/db" 8 "code.gitea.io/gitea/models/organization" 9 project_model "code.gitea.io/gitea/models/project" 10 repo_model "code.gitea.io/gitea/models/repo" 11 user_model "code.gitea.io/gitea/models/user" 12 "code.gitea.io/gitea/modules/context" 13 "code.gitea.io/gitea/modules/git" 14 "code.gitea.io/gitea/modules/log" 15 "code.gitea.io/gitea/modules/markup" 16 "code.gitea.io/gitea/modules/markup/markdown" 17 "code.gitea.io/gitea/modules/setting" 18 "code.gitea.io/gitea/modules/util" 19 ) 20 21 // prepareContextForCommonProfile store some common data into context data for user's profile related pages (including the nav menu) 22 // It is designed to be fast and safe to be called multiple times in one request 23 func prepareContextForCommonProfile(ctx *context.Context) { 24 ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled 25 ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled 26 ctx.Data["EnableFeed"] = setting.Other.EnableFeed 27 ctx.Data["FeedURL"] = ctx.ContextUser.HomeLink() 28 } 29 30 // PrepareContextForProfileBigAvatar set the context for big avatar view on the profile page 31 func PrepareContextForProfileBigAvatar(ctx *context.Context) { 32 prepareContextForCommonProfile(ctx) 33 34 ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) 35 ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate 36 ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL 37 38 // Show OpenID URIs 39 openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID) 40 if err != nil { 41 ctx.ServerError("GetUserOpenIDs", err) 42 return 43 } 44 ctx.Data["OpenIDs"] = openIDs 45 46 if len(ctx.ContextUser.Description) != 0 { 47 content, err := markdown.RenderString(&markup.RenderContext{ 48 Metas: map[string]string{"mode": "document"}, 49 Ctx: ctx, 50 }, ctx.ContextUser.Description) 51 if err != nil { 52 ctx.ServerError("RenderString", err) 53 return 54 } 55 ctx.Data["RenderedDescription"] = content 56 } 57 58 showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) 59 orgs, err := organization.FindOrgs(organization.FindOrgOptions{ 60 UserID: ctx.ContextUser.ID, 61 IncludePrivate: showPrivate, 62 }) 63 if err != nil { 64 ctx.ServerError("FindOrgs", err) 65 return 66 } 67 ctx.Data["Orgs"] = orgs 68 ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer) 69 70 badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser) 71 if err != nil { 72 ctx.ServerError("GetUserBadges", err) 73 return 74 } 75 ctx.Data["Badges"] = badges 76 77 // in case the numbers are already provided by other functions, no need to query again (which is slow) 78 if _, ok := ctx.Data["NumFollowers"]; !ok { 79 _, ctx.Data["NumFollowers"], _ = user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1}) 80 } 81 if _, ok := ctx.Data["NumFollowing"]; !ok { 82 _, ctx.Data["NumFollowing"], _ = user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1}) 83 } 84 } 85 86 func FindUserProfileReadme(ctx *context.Context) (profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) { 87 profileDbRepo, err := repo_model.GetRepositoryByName(ctx.ContextUser.ID, ".profile") 88 if err == nil && !profileDbRepo.IsEmpty && !profileDbRepo.IsPrivate { 89 if profileGitRepo, err = git.OpenRepository(ctx, profileDbRepo.RepoPath()); err != nil { 90 log.Error("FindUserProfileReadme failed to OpenRepository: %v", err) 91 } else { 92 if commit, err := profileGitRepo.GetBranchCommit(profileDbRepo.DefaultBranch); err != nil { 93 log.Error("FindUserProfileReadme failed to GetBranchCommit: %v", err) 94 } else { 95 profileReadmeBlob, _ = commit.GetBlobByPath("README.md") 96 } 97 } 98 } 99 return profileDbRepo, profileGitRepo, profileReadmeBlob, func() { 100 if profileGitRepo != nil { 101 _ = profileGitRepo.Close() 102 } 103 } 104 } 105 106 func RenderUserHeader(ctx *context.Context) { 107 prepareContextForCommonProfile(ctx) 108 109 _, _, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx) 110 defer profileClose() 111 ctx.Data["HasProfileReadme"] = profileReadmeBlob != nil 112 } 113 114 func LoadHeaderCount(ctx *context.Context) error { 115 prepareContextForCommonProfile(ctx) 116 117 repoCount, err := repo_model.CountRepository(ctx, &repo_model.SearchRepoOptions{ 118 Actor: ctx.Doer, 119 OwnerID: ctx.ContextUser.ID, 120 Private: ctx.IsSigned, 121 Collaborate: util.OptionalBoolFalse, 122 IncludeDescription: setting.UI.SearchRepoDescription, 123 }) 124 if err != nil { 125 return err 126 } 127 ctx.Data["RepoCount"] = repoCount 128 129 var projectType project_model.Type 130 if ctx.ContextUser.IsOrganization() { 131 projectType = project_model.TypeOrganization 132 } else { 133 projectType = project_model.TypeIndividual 134 } 135 projectCount, err := project_model.CountProjects(ctx, project_model.SearchOptions{ 136 OwnerID: ctx.ContextUser.ID, 137 IsClosed: util.OptionalBoolOf(false), 138 Type: projectType, 139 }) 140 if err != nil { 141 return err 142 } 143 ctx.Data["ProjectCount"] = projectCount 144 145 return nil 146 }