code.gitea.io/gitea@v1.21.7/routers/web/explore/user.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package explore
     5  
     6  import (
     7  	"bytes"
     8  	"net/http"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	user_model "code.gitea.io/gitea/models/user"
    12  	"code.gitea.io/gitea/modules/base"
    13  	"code.gitea.io/gitea/modules/context"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/setting"
    16  	"code.gitea.io/gitea/modules/sitemap"
    17  	"code.gitea.io/gitea/modules/structs"
    18  	"code.gitea.io/gitea/modules/util"
    19  )
    20  
    21  const (
    22  	// tplExploreUsers explore users page template
    23  	tplExploreUsers base.TplName = "explore/users"
    24  )
    25  
    26  // UserSearchDefaultSortType is the default sort type for user search
    27  const (
    28  	UserSearchDefaultSortType  = "recentupdate"
    29  	UserSearchDefaultAdminSort = "alphabetically"
    30  )
    31  
    32  var nullByte = []byte{0x00}
    33  
    34  func isKeywordValid(keyword string) bool {
    35  	return !bytes.Contains([]byte(keyword), nullByte)
    36  }
    37  
    38  // RenderUserSearch render user search page
    39  func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, tplName base.TplName) {
    40  	// Sitemap index for sitemap paths
    41  	opts.Page = int(ctx.ParamsInt64("idx"))
    42  	isSitemap := ctx.Params("idx") != ""
    43  	if opts.Page <= 1 {
    44  		opts.Page = ctx.FormInt("page")
    45  	}
    46  	if opts.Page <= 1 {
    47  		opts.Page = 1
    48  	}
    49  
    50  	if isSitemap {
    51  		opts.PageSize = setting.UI.SitemapPagingNum
    52  	}
    53  
    54  	var (
    55  		users   []*user_model.User
    56  		count   int64
    57  		err     error
    58  		orderBy db.SearchOrderBy
    59  	)
    60  
    61  	// 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
    62  
    63  	ctx.Data["SortType"] = ctx.FormString("sort")
    64  	switch ctx.FormString("sort") {
    65  	case "newest":
    66  		orderBy = "`user`.id DESC"
    67  	case "oldest":
    68  		orderBy = "`user`.id ASC"
    69  	case "leastupdate":
    70  		orderBy = "`user`.updated_unix ASC"
    71  	case "reversealphabetically":
    72  		orderBy = "`user`.name DESC"
    73  	case "lastlogin":
    74  		orderBy = "`user`.last_login_unix ASC"
    75  	case "reverselastlogin":
    76  		orderBy = "`user`.last_login_unix DESC"
    77  	case "alphabetically":
    78  		orderBy = "`user`.name ASC"
    79  	case "recentupdate":
    80  		fallthrough
    81  	default:
    82  		// in case the sortType is not valid, we set it to recentupdate
    83  		ctx.Data["SortType"] = "recentupdate"
    84  		orderBy = "`user`.updated_unix DESC"
    85  	}
    86  
    87  	opts.Keyword = ctx.FormTrim("q")
    88  	opts.OrderBy = orderBy
    89  	if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
    90  		users, count, err = user_model.SearchUsers(ctx, opts)
    91  		if err != nil {
    92  			ctx.ServerError("SearchUsers", err)
    93  			return
    94  		}
    95  	}
    96  	if isSitemap {
    97  		m := sitemap.NewSitemap()
    98  		for _, item := range users {
    99  			m.Add(sitemap.URL{URL: item.HTMLURL(), LastMod: item.UpdatedUnix.AsTimePtr()})
   100  		}
   101  		ctx.Resp.Header().Set("Content-Type", "text/xml")
   102  		if _, err := m.WriteTo(ctx.Resp); err != nil {
   103  			log.Error("Failed writing sitemap: %v", err)
   104  		}
   105  		return
   106  	}
   107  
   108  	ctx.Data["Keyword"] = opts.Keyword
   109  	ctx.Data["Total"] = count
   110  	ctx.Data["Users"] = users
   111  	ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus(ctx)
   112  	ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
   113  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   114  
   115  	pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
   116  	pager.SetDefaultParams(ctx)
   117  	for paramKey, paramVal := range opts.ExtraParamStrings {
   118  		pager.AddParamString(paramKey, paramVal)
   119  	}
   120  	ctx.Data["Page"] = pager
   121  
   122  	ctx.HTML(http.StatusOK, tplName)
   123  }
   124  
   125  // Users render explore users page
   126  func Users(ctx *context.Context) {
   127  	if setting.Service.Explore.DisableUsersPage {
   128  		ctx.Redirect(setting.AppSubURL + "/explore/repos")
   129  		return
   130  	}
   131  	ctx.Data["Title"] = ctx.Tr("explore")
   132  	ctx.Data["PageIsExplore"] = true
   133  	ctx.Data["PageIsExploreUsers"] = true
   134  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   135  
   136  	if ctx.FormString("sort") == "" {
   137  		ctx.SetFormString("sort", UserSearchDefaultSortType)
   138  	}
   139  
   140  	RenderUserSearch(ctx, &user_model.SearchUserOptions{
   141  		Actor:       ctx.Doer,
   142  		Type:        user_model.UserTypeIndividual,
   143  		ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
   144  		IsActive:    util.OptionalBoolTrue,
   145  		Visible:     []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate},
   146  	}, tplExploreUsers)
   147  }