code.gitea.io/gitea@v1.22.3/routers/web/explore/repo.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package explore
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	repo_model "code.gitea.io/gitea/models/repo"
    12  	"code.gitea.io/gitea/modules/base"
    13  	"code.gitea.io/gitea/modules/log"
    14  	"code.gitea.io/gitea/modules/setting"
    15  	"code.gitea.io/gitea/modules/sitemap"
    16  	"code.gitea.io/gitea/services/context"
    17  )
    18  
    19  const (
    20  	// tplExploreRepos explore repositories page template
    21  	tplExploreRepos        base.TplName = "explore/repos"
    22  	relevantReposOnlyParam string       = "only_show_relevant"
    23  )
    24  
    25  // RepoSearchOptions when calling search repositories
    26  type RepoSearchOptions struct {
    27  	OwnerID          int64
    28  	Private          bool
    29  	Restricted       bool
    30  	PageSize         int
    31  	OnlyShowRelevant bool
    32  	TplName          base.TplName
    33  }
    34  
    35  // RenderRepoSearch render repositories search page
    36  // This function is also used to render the Admin Repository Management page.
    37  func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
    38  	// Sitemap index for sitemap paths
    39  	page := int(ctx.ParamsInt64("idx"))
    40  	isSitemap := ctx.Params("idx") != ""
    41  	if page <= 1 {
    42  		page = ctx.FormInt("page")
    43  	}
    44  
    45  	if page <= 0 {
    46  		page = 1
    47  	}
    48  
    49  	if isSitemap {
    50  		opts.PageSize = setting.UI.SitemapPagingNum
    51  	}
    52  
    53  	var (
    54  		repos   []*repo_model.Repository
    55  		count   int64
    56  		err     error
    57  		orderBy db.SearchOrderBy
    58  	)
    59  
    60  	sortOrder := ctx.FormString("sort")
    61  	if sortOrder == "" {
    62  		sortOrder = setting.UI.ExploreDefaultSort
    63  	}
    64  	ctx.Data["SortType"] = sortOrder
    65  
    66  	switch sortOrder {
    67  	case "newest":
    68  		orderBy = db.SearchOrderByNewest
    69  	case "oldest":
    70  		orderBy = db.SearchOrderByOldest
    71  	case "leastupdate":
    72  		orderBy = db.SearchOrderByLeastUpdated
    73  	case "reversealphabetically":
    74  		orderBy = "owner_name DESC, name DESC"
    75  	case "alphabetically":
    76  		orderBy = "owner_name ASC, name ASC"
    77  	case "reversesize":
    78  		orderBy = db.SearchOrderBySizeReverse
    79  	case "size":
    80  		orderBy = db.SearchOrderBySize
    81  	case "reversegitsize":
    82  		orderBy = db.SearchOrderByGitSizeReverse
    83  	case "gitsize":
    84  		orderBy = db.SearchOrderByGitSize
    85  	case "reverselfssize":
    86  		orderBy = db.SearchOrderByLFSSizeReverse
    87  	case "lfssize":
    88  		orderBy = db.SearchOrderByLFSSize
    89  	case "moststars":
    90  		orderBy = db.SearchOrderByStarsReverse
    91  	case "feweststars":
    92  		orderBy = db.SearchOrderByStars
    93  	case "mostforks":
    94  		orderBy = db.SearchOrderByForksReverse
    95  	case "fewestforks":
    96  		orderBy = db.SearchOrderByForks
    97  	default:
    98  		ctx.Data["SortType"] = "recentupdate"
    99  		orderBy = db.SearchOrderByRecentUpdated
   100  	}
   101  
   102  	keyword := ctx.FormTrim("q")
   103  
   104  	ctx.Data["OnlyShowRelevant"] = opts.OnlyShowRelevant
   105  
   106  	topicOnly := ctx.FormBool("topic")
   107  	ctx.Data["TopicOnly"] = topicOnly
   108  
   109  	language := ctx.FormTrim("language")
   110  	ctx.Data["Language"] = language
   111  
   112  	archived := ctx.FormOptionalBool("archived")
   113  	ctx.Data["IsArchived"] = archived
   114  
   115  	fork := ctx.FormOptionalBool("fork")
   116  	ctx.Data["IsFork"] = fork
   117  
   118  	mirror := ctx.FormOptionalBool("mirror")
   119  	ctx.Data["IsMirror"] = mirror
   120  
   121  	template := ctx.FormOptionalBool("template")
   122  	ctx.Data["IsTemplate"] = template
   123  
   124  	private := ctx.FormOptionalBool("private")
   125  	ctx.Data["IsPrivate"] = private
   126  
   127  	repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{
   128  		ListOptions: db.ListOptions{
   129  			Page:     page,
   130  			PageSize: opts.PageSize,
   131  		},
   132  		Actor:              ctx.Doer,
   133  		OrderBy:            orderBy,
   134  		Private:            opts.Private,
   135  		Keyword:            keyword,
   136  		OwnerID:            opts.OwnerID,
   137  		AllPublic:          true,
   138  		AllLimited:         true,
   139  		TopicOnly:          topicOnly,
   140  		Language:           language,
   141  		IncludeDescription: setting.UI.SearchRepoDescription,
   142  		OnlyShowRelevant:   opts.OnlyShowRelevant,
   143  		Archived:           archived,
   144  		Fork:               fork,
   145  		Mirror:             mirror,
   146  		Template:           template,
   147  		IsPrivate:          private,
   148  	})
   149  	if err != nil {
   150  		ctx.ServerError("SearchRepository", err)
   151  		return
   152  	}
   153  	if isSitemap {
   154  		m := sitemap.NewSitemap()
   155  		for _, item := range repos {
   156  			m.Add(sitemap.URL{URL: item.HTMLURL(), LastMod: item.UpdatedUnix.AsTimePtr()})
   157  		}
   158  		ctx.Resp.Header().Set("Content-Type", "text/xml")
   159  		if _, err := m.WriteTo(ctx.Resp); err != nil {
   160  			log.Error("Failed writing sitemap: %v", err)
   161  		}
   162  		return
   163  	}
   164  
   165  	ctx.Data["Keyword"] = keyword
   166  	ctx.Data["Total"] = count
   167  	ctx.Data["Repos"] = repos
   168  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   169  
   170  	pager := context.NewPagination(int(count), opts.PageSize, page, 5)
   171  	pager.SetDefaultParams(ctx)
   172  	pager.AddParamString("topic", fmt.Sprint(topicOnly))
   173  	pager.AddParamString("language", language)
   174  	pager.AddParamString(relevantReposOnlyParam, fmt.Sprint(opts.OnlyShowRelevant))
   175  	if archived.Has() {
   176  		pager.AddParamString("archived", fmt.Sprint(archived.Value()))
   177  	}
   178  	if fork.Has() {
   179  		pager.AddParamString("fork", fmt.Sprint(fork.Value()))
   180  	}
   181  	if mirror.Has() {
   182  		pager.AddParamString("mirror", fmt.Sprint(mirror.Value()))
   183  	}
   184  	if template.Has() {
   185  		pager.AddParamString("template", fmt.Sprint(template.Value()))
   186  	}
   187  	if private.Has() {
   188  		pager.AddParamString("private", fmt.Sprint(private.Value()))
   189  	}
   190  	ctx.Data["Page"] = pager
   191  
   192  	ctx.HTML(http.StatusOK, opts.TplName)
   193  }
   194  
   195  // Repos render explore repositories page
   196  func Repos(ctx *context.Context) {
   197  	ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage
   198  	ctx.Data["Title"] = ctx.Tr("explore")
   199  	ctx.Data["PageIsExplore"] = true
   200  	ctx.Data["PageIsExploreRepositories"] = true
   201  	ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
   202  
   203  	var ownerID int64
   204  	if ctx.Doer != nil && !ctx.Doer.IsAdmin {
   205  		ownerID = ctx.Doer.ID
   206  	}
   207  
   208  	onlyShowRelevant := setting.UI.OnlyShowRelevantRepos
   209  
   210  	_ = ctx.Req.ParseForm() // parse the form first, to prepare the ctx.Req.Form field
   211  	if len(ctx.Req.Form[relevantReposOnlyParam]) != 0 {
   212  		onlyShowRelevant = ctx.FormBool(relevantReposOnlyParam)
   213  	}
   214  
   215  	RenderRepoSearch(ctx, &RepoSearchOptions{
   216  		PageSize:         setting.UI.ExplorePagingNum,
   217  		OwnerID:          ownerID,
   218  		Private:          ctx.Doer != nil,
   219  		TplName:          tplExploreRepos,
   220  		OnlyShowRelevant: onlyShowRelevant,
   221  	})
   222  }