code.gitea.io/gitea@v1.22.3/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/container"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/optional"
    16  	"code.gitea.io/gitea/modules/setting"
    17  	"code.gitea.io/gitea/modules/sitemap"
    18  	"code.gitea.io/gitea/modules/structs"
    19  	"code.gitea.io/gitea/services/context"
    20  )
    21  
    22  const (
    23  	// tplExploreUsers explore users page template
    24  	tplExploreUsers base.TplName = "explore/users"
    25  )
    26  
    27  var nullByte = []byte{0x00}
    28  
    29  func isKeywordValid(keyword string) bool {
    30  	return !bytes.Contains([]byte(keyword), nullByte)
    31  }
    32  
    33  // RenderUserSearch render user search page
    34  func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, tplName base.TplName) {
    35  	// Sitemap index for sitemap paths
    36  	opts.Page = int(ctx.ParamsInt64("idx"))
    37  	isSitemap := ctx.Params("idx") != ""
    38  	if opts.Page <= 1 {
    39  		opts.Page = ctx.FormInt("page")
    40  	}
    41  	if opts.Page <= 1 {
    42  		opts.Page = 1
    43  	}
    44  
    45  	if isSitemap {
    46  		opts.PageSize = setting.UI.SitemapPagingNum
    47  	}
    48  
    49  	var (
    50  		users   []*user_model.User
    51  		count   int64
    52  		err     error
    53  		orderBy db.SearchOrderBy
    54  	)
    55  
    56  	// 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
    57  
    58  	sortOrder := ctx.FormString("sort")
    59  	if sortOrder == "" {
    60  		sortOrder = setting.UI.ExploreDefaultSort
    61  	}
    62  	ctx.Data["SortType"] = sortOrder
    63  
    64  	switch sortOrder {
    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  		sortOrder = "recentupdate"
    84  		ctx.Data["SortType"] = "recentupdate"
    85  		orderBy = "`user`.updated_unix DESC"
    86  	}
    87  
    88  	if opts.SupportedSortOrders != nil && !opts.SupportedSortOrders.Contains(sortOrder) {
    89  		ctx.NotFound("unsupported sort order", nil)
    90  		return
    91  	}
    92  
    93  	opts.Keyword = ctx.FormTrim("q")
    94  	opts.OrderBy = orderBy
    95  	if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
    96  		users, count, err = user_model.SearchUsers(ctx, opts)
    97  		if err != nil {
    98  			ctx.ServerError("SearchUsers", err)
    99  			return
   100  		}
   101  	}
   102  	if isSitemap {
   103  		m := sitemap.NewSitemap()
   104  		for _, item := range users {
   105  			m.Add(sitemap.URL{URL: item.HTMLURL(), LastMod: item.UpdatedUnix.AsTimePtr()})
   106  		}
   107  		ctx.Resp.Header().Set("Content-Type", "text/xml")
   108  		if _, err := m.WriteTo(ctx.Resp); err != nil {
   109  			log.Error("Failed writing sitemap: %v", err)
   110  		}
   111  		return
   112  	}
   113  
   114  	ctx.Data["Keyword"] = opts.Keyword
   115  	ctx.Data["Total"] = count
   116  	ctx.Data["Users"] = users
   117  	ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus(ctx)
   118  	ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
   119  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   120  
   121  	pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
   122  	pager.SetDefaultParams(ctx)
   123  	for paramKey, paramVal := range opts.ExtraParamStrings {
   124  		pager.AddParamString(paramKey, paramVal)
   125  	}
   126  	ctx.Data["Page"] = pager
   127  
   128  	ctx.HTML(http.StatusOK, tplName)
   129  }
   130  
   131  // Users render explore users page
   132  func Users(ctx *context.Context) {
   133  	if setting.Service.Explore.DisableUsersPage {
   134  		ctx.Redirect(setting.AppSubURL + "/explore/repos")
   135  		return
   136  	}
   137  	ctx.Data["Title"] = ctx.Tr("explore")
   138  	ctx.Data["PageIsExplore"] = true
   139  	ctx.Data["PageIsExploreUsers"] = true
   140  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   141  
   142  	supportedSortOrders := container.SetOf(
   143  		"newest",
   144  		"oldest",
   145  		"alphabetically",
   146  		"reversealphabetically",
   147  	)
   148  	sortOrder := ctx.FormString("sort")
   149  	if sortOrder == "" {
   150  		sortOrder = "newest"
   151  		ctx.SetFormString("sort", sortOrder)
   152  	}
   153  
   154  	RenderUserSearch(ctx, &user_model.SearchUserOptions{
   155  		Actor:       ctx.Doer,
   156  		Type:        user_model.UserTypeIndividual,
   157  		ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum},
   158  		IsActive:    optional.Some(true),
   159  		Visible:     []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate},
   160  
   161  		SupportedSortOrders: supportedSortOrders,
   162  	}, tplExploreUsers)
   163  }