forked from gitea/gitea
		
	
		
			
				
	
	
		
			135 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | |
| // Use of this source code is governed by a MIT-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package explore
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"code.gitea.io/gitea/models/db"
 | |
| 	user_model "code.gitea.io/gitea/models/user"
 | |
| 	"code.gitea.io/gitea/modules/base"
 | |
| 	"code.gitea.io/gitea/modules/context"
 | |
| 	"code.gitea.io/gitea/modules/log"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 	"code.gitea.io/gitea/modules/sitemap"
 | |
| 	"code.gitea.io/gitea/modules/structs"
 | |
| 	"code.gitea.io/gitea/modules/util"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// tplExploreUsers explore users page template
 | |
| 	tplExploreUsers base.TplName = "explore/users"
 | |
| )
 | |
| 
 | |
| // UserSearchDefaultSortType is the default sort type for user search
 | |
| const UserSearchDefaultSortType = "alphabetically"
 | |
| 
 | |
| var nullByte = []byte{0x00}
 | |
| 
 | |
| func isKeywordValid(keyword string) bool {
 | |
| 	return !bytes.Contains([]byte(keyword), nullByte)
 | |
| }
 | |
| 
 | |
| // RenderUserSearch render user search page
 | |
| func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, tplName base.TplName) {
 | |
| 	// Sitemap index for sitemap paths
 | |
| 	opts.Page = int(ctx.ParamsInt64("idx"))
 | |
| 	isSitemap := ctx.Params("idx") != ""
 | |
| 	if opts.Page <= 1 {
 | |
| 		opts.Page = ctx.FormInt("page")
 | |
| 	}
 | |
| 	if opts.Page <= 1 {
 | |
| 		opts.Page = 1
 | |
| 	}
 | |
| 
 | |
| 	if isSitemap {
 | |
| 		opts.PageSize = setting.UI.SitemapPagingNum
 | |
| 	}
 | |
| 
 | |
| 	var (
 | |
| 		users   []*user_model.User
 | |
| 		count   int64
 | |
| 		err     error
 | |
| 		orderBy db.SearchOrderBy
 | |
| 	)
 | |
| 
 | |
| 	// we can not set orderBy to `models.SearchOrderByXxx`, because there may be a JOIN in the statement, different tables may have the same name columns
 | |
| 	ctx.Data["SortType"] = ctx.FormString("sort")
 | |
| 	switch ctx.FormString("sort") {
 | |
| 	case "newest":
 | |
| 		orderBy = "`user`.id DESC"
 | |
| 	case "oldest":
 | |
| 		orderBy = "`user`.id ASC"
 | |
| 	case "recentupdate":
 | |
| 		orderBy = "`user`.updated_unix DESC"
 | |
| 	case "leastupdate":
 | |
| 		orderBy = "`user`.updated_unix ASC"
 | |
| 	case "reversealphabetically":
 | |
| 		orderBy = "`user`.name DESC"
 | |
| 	case UserSearchDefaultSortType: // "alphabetically"
 | |
| 	default:
 | |
| 		orderBy = "`user`.name ASC"
 | |
| 		ctx.Data["SortType"] = UserSearchDefaultSortType
 | |
| 	}
 | |
| 
 | |
| 	opts.Keyword = ctx.FormTrim("q")
 | |
| 	opts.OrderBy = orderBy
 | |
| 	if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
 | |
| 		users, count, err = user_model.SearchUsers(opts)
 | |
| 		if err != nil {
 | |
| 			ctx.ServerError("SearchUsers", err)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	if isSitemap {
 | |
| 		m := sitemap.NewSitemap()
 | |
| 		for _, item := range users {
 | |
| 			m.Add(sitemap.URL{URL: item.HTMLURL(), LastMod: item.UpdatedUnix.AsTimePtr()})
 | |
| 		}
 | |
| 		ctx.Resp.Header().Set("Content-Type", "text/xml")
 | |
| 		if _, err := m.WriteTo(ctx.Resp); err != nil {
 | |
| 			log.Error("Failed writing sitemap: %v", err)
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ctx.Data["Keyword"] = opts.Keyword
 | |
| 	ctx.Data["Total"] = count
 | |
| 	ctx.Data["Users"] = users
 | |
| 	ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus()
 | |
| 	ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
 | |
| 	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | |
| 
 | |
| 	pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
 | |
| 	pager.SetDefaultParams(ctx)
 | |
| 	for paramKey, paramVal := range opts.ExtraParamStrings {
 | |
| 		pager.AddParamString(paramKey, paramVal)
 | |
| 	}
 | |
| 	ctx.Data["Page"] = pager
 | |
| 
 | |
| 	ctx.HTML(http.StatusOK, tplName)
 | |
| }
 | |
| 
 | |
| // Users render explore users page
 | |
| func Users(ctx *context.Context) {
 | |
| 	if setting.Service.Explore.DisableUsersPage {
 | |
| 		ctx.Redirect(setting.AppSubURL + "/explore/repos")
 | |
| 		return
 | |
| 	}
 | |
| 	ctx.Data["Title"] = ctx.Tr("explore")
 | |
| 	ctx.Data["PageIsExplore"] = true
 | |
| 	ctx.Data["PageIsExploreUsers"] = true
 | |
| 	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
 | |
| 
 | |
| 	RenderUserSearch(ctx, &user_model.SearchUserOptions{
 | |
| 		Actor:       ctx.Doer,
 | |
| 		Type:        user_model.UserTypeIndividual,
 | |
| 		ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
 | |
| 		IsActive:    util.OptionalBoolTrue,
 | |
| 		Visible:     []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate},
 | |
| 	}, tplExploreUsers)
 | |
| }
 | 
