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  }