3c45cf8494
Move langauge detection to separate module to be more reusable Add option to disable vendored file exclusion from file search Allways show all language stats for search
400 lines
11 KiB
Go
400 lines
11 KiB
Go
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
// Copyright 2019 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 routers
|
|
|
|
import (
|
|
"bytes"
|
|
"strings"
|
|
|
|
"code.gitea.io/gitea/models"
|
|
"code.gitea.io/gitea/modules/base"
|
|
"code.gitea.io/gitea/modules/context"
|
|
code_indexer "code.gitea.io/gitea/modules/indexer/code"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/structs"
|
|
"code.gitea.io/gitea/modules/util"
|
|
"code.gitea.io/gitea/routers/user"
|
|
)
|
|
|
|
const (
|
|
// tplHome home page template
|
|
tplHome base.TplName = "home"
|
|
// tplExploreRepos explore repositories page template
|
|
tplExploreRepos base.TplName = "explore/repos"
|
|
// tplExploreUsers explore users page template
|
|
tplExploreUsers base.TplName = "explore/users"
|
|
// tplExploreOrganizations explore organizations page template
|
|
tplExploreOrganizations base.TplName = "explore/organizations"
|
|
// tplExploreCode explore code page template
|
|
tplExploreCode base.TplName = "explore/code"
|
|
)
|
|
|
|
// Home render home page
|
|
func Home(ctx *context.Context) {
|
|
if ctx.IsSigned {
|
|
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
|
|
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
|
ctx.HTML(200, user.TplActivate)
|
|
} else if !ctx.User.IsActive || ctx.User.ProhibitLogin {
|
|
log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
|
|
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
|
ctx.HTML(200, "user/auth/prohibit_login")
|
|
} else if ctx.User.MustChangePassword {
|
|
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
|
|
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
|
|
ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL)
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
|
|
} else {
|
|
user.Dashboard(ctx)
|
|
}
|
|
return
|
|
// Check non-logged users landing page.
|
|
} else if setting.LandingPageURL != setting.LandingPageHome {
|
|
ctx.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
|
|
return
|
|
}
|
|
|
|
// Check auto-login.
|
|
uname := ctx.GetCookie(setting.CookieUserName)
|
|
if len(uname) != 0 {
|
|
ctx.Redirect(setting.AppSubURL + "/user/login")
|
|
return
|
|
}
|
|
|
|
ctx.Data["PageIsHome"] = true
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
ctx.HTML(200, tplHome)
|
|
}
|
|
|
|
// RepoSearchOptions when calling search repositories
|
|
type RepoSearchOptions struct {
|
|
OwnerID int64
|
|
Private bool
|
|
Restricted bool
|
|
PageSize int
|
|
TplName base.TplName
|
|
}
|
|
|
|
var (
|
|
nullByte = []byte{0x00}
|
|
)
|
|
|
|
func isKeywordValid(keyword string) bool {
|
|
return !bytes.Contains([]byte(keyword), nullByte)
|
|
}
|
|
|
|
// RenderRepoSearch render repositories search page
|
|
func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
|
page := ctx.QueryInt("page")
|
|
if page <= 0 {
|
|
page = 1
|
|
}
|
|
|
|
var (
|
|
repos []*models.Repository
|
|
count int64
|
|
err error
|
|
orderBy models.SearchOrderBy
|
|
)
|
|
|
|
ctx.Data["SortType"] = ctx.Query("sort")
|
|
switch ctx.Query("sort") {
|
|
case "newest":
|
|
orderBy = models.SearchOrderByNewest
|
|
case "oldest":
|
|
orderBy = models.SearchOrderByOldest
|
|
case "recentupdate":
|
|
orderBy = models.SearchOrderByRecentUpdated
|
|
case "leastupdate":
|
|
orderBy = models.SearchOrderByLeastUpdated
|
|
case "reversealphabetically":
|
|
orderBy = models.SearchOrderByAlphabeticallyReverse
|
|
case "alphabetically":
|
|
orderBy = models.SearchOrderByAlphabetically
|
|
case "reversesize":
|
|
orderBy = models.SearchOrderBySizeReverse
|
|
case "size":
|
|
orderBy = models.SearchOrderBySize
|
|
case "moststars":
|
|
orderBy = models.SearchOrderByStarsReverse
|
|
case "feweststars":
|
|
orderBy = models.SearchOrderByStars
|
|
case "mostforks":
|
|
orderBy = models.SearchOrderByForksReverse
|
|
case "fewestforks":
|
|
orderBy = models.SearchOrderByForks
|
|
default:
|
|
ctx.Data["SortType"] = "recentupdate"
|
|
orderBy = models.SearchOrderByRecentUpdated
|
|
}
|
|
|
|
keyword := strings.Trim(ctx.Query("q"), " ")
|
|
topicOnly := ctx.QueryBool("topic")
|
|
ctx.Data["TopicOnly"] = topicOnly
|
|
|
|
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
|
|
ListOptions: models.ListOptions{
|
|
Page: page,
|
|
PageSize: opts.PageSize,
|
|
},
|
|
Actor: ctx.User,
|
|
OrderBy: orderBy,
|
|
Private: opts.Private,
|
|
Keyword: keyword,
|
|
OwnerID: opts.OwnerID,
|
|
AllPublic: true,
|
|
AllLimited: true,
|
|
TopicOnly: topicOnly,
|
|
IncludeDescription: setting.UI.SearchRepoDescription,
|
|
})
|
|
if err != nil {
|
|
ctx.ServerError("SearchRepository", err)
|
|
return
|
|
}
|
|
ctx.Data["Keyword"] = keyword
|
|
ctx.Data["Total"] = count
|
|
ctx.Data["Repos"] = repos
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
|
|
pager := context.NewPagination(int(count), opts.PageSize, page, 5)
|
|
pager.SetDefaultParams(ctx)
|
|
pager.AddParam(ctx, "topic", "TopicOnly")
|
|
ctx.Data["Page"] = pager
|
|
|
|
ctx.HTML(200, opts.TplName)
|
|
}
|
|
|
|
// ExploreRepos render explore repositories page
|
|
func ExploreRepos(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("explore")
|
|
ctx.Data["PageIsExplore"] = true
|
|
ctx.Data["PageIsExploreRepositories"] = true
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
|
|
var ownerID int64
|
|
if ctx.User != nil && !ctx.User.IsAdmin {
|
|
ownerID = ctx.User.ID
|
|
}
|
|
|
|
RenderRepoSearch(ctx, &RepoSearchOptions{
|
|
PageSize: setting.UI.ExplorePagingNum,
|
|
OwnerID: ownerID,
|
|
Private: ctx.User != nil,
|
|
TplName: tplExploreRepos,
|
|
})
|
|
}
|
|
|
|
// RenderUserSearch render user search page
|
|
func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplName base.TplName) {
|
|
opts.Page = ctx.QueryInt("page")
|
|
if opts.Page <= 1 {
|
|
opts.Page = 1
|
|
}
|
|
opts.Actor = ctx.User
|
|
|
|
var (
|
|
users []*models.User
|
|
count int64
|
|
err error
|
|
orderBy models.SearchOrderBy
|
|
)
|
|
|
|
ctx.Data["SortType"] = ctx.Query("sort")
|
|
switch ctx.Query("sort") {
|
|
case "newest":
|
|
orderBy = models.SearchOrderByIDReverse
|
|
case "oldest":
|
|
orderBy = models.SearchOrderByID
|
|
case "recentupdate":
|
|
orderBy = models.SearchOrderByRecentUpdated
|
|
case "leastupdate":
|
|
orderBy = models.SearchOrderByLeastUpdated
|
|
case "reversealphabetically":
|
|
orderBy = models.SearchOrderByAlphabeticallyReverse
|
|
case "alphabetically":
|
|
orderBy = models.SearchOrderByAlphabetically
|
|
default:
|
|
ctx.Data["SortType"] = "alphabetically"
|
|
orderBy = models.SearchOrderByAlphabetically
|
|
}
|
|
|
|
opts.Keyword = strings.Trim(ctx.Query("q"), " ")
|
|
opts.OrderBy = orderBy
|
|
if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
|
|
users, count, err = models.SearchUsers(opts)
|
|
if err != nil {
|
|
ctx.ServerError("SearchUsers", err)
|
|
return
|
|
}
|
|
}
|
|
ctx.Data["Keyword"] = opts.Keyword
|
|
ctx.Data["Total"] = count
|
|
ctx.Data["Users"] = users
|
|
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)
|
|
ctx.Data["Page"] = pager
|
|
|
|
ctx.HTML(200, tplName)
|
|
}
|
|
|
|
// ExploreUsers render explore users page
|
|
func ExploreUsers(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("explore")
|
|
ctx.Data["PageIsExplore"] = true
|
|
ctx.Data["PageIsExploreUsers"] = true
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
|
|
RenderUserSearch(ctx, &models.SearchUserOptions{
|
|
Type: models.UserTypeIndividual,
|
|
ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum},
|
|
IsActive: util.OptionalBoolTrue,
|
|
Visible: []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate},
|
|
}, tplExploreUsers)
|
|
}
|
|
|
|
// ExploreOrganizations render explore organizations page
|
|
func ExploreOrganizations(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("explore")
|
|
ctx.Data["PageIsExplore"] = true
|
|
ctx.Data["PageIsExploreOrganizations"] = true
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
|
|
visibleTypes := []structs.VisibleType{structs.VisibleTypePublic}
|
|
if ctx.User != nil {
|
|
visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate)
|
|
}
|
|
|
|
RenderUserSearch(ctx, &models.SearchUserOptions{
|
|
Type: models.UserTypeOrganization,
|
|
ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum},
|
|
Visible: visibleTypes,
|
|
}, tplExploreOrganizations)
|
|
}
|
|
|
|
// ExploreCode render explore code page
|
|
func ExploreCode(ctx *context.Context) {
|
|
if !setting.Indexer.RepoIndexerEnabled {
|
|
ctx.Redirect(setting.AppSubURL+"/explore", 302)
|
|
return
|
|
}
|
|
|
|
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
ctx.Data["Title"] = ctx.Tr("explore")
|
|
ctx.Data["PageIsExplore"] = true
|
|
ctx.Data["PageIsExploreCode"] = true
|
|
|
|
language := strings.TrimSpace(ctx.Query("l"))
|
|
keyword := strings.TrimSpace(ctx.Query("q"))
|
|
page := ctx.QueryInt("page")
|
|
if page <= 0 {
|
|
page = 1
|
|
}
|
|
|
|
var (
|
|
repoIDs []int64
|
|
err error
|
|
isAdmin bool
|
|
userID int64
|
|
)
|
|
if ctx.User != nil {
|
|
userID = ctx.User.ID
|
|
isAdmin = ctx.User.IsAdmin
|
|
}
|
|
|
|
// guest user or non-admin user
|
|
if ctx.User == nil || !isAdmin {
|
|
repoIDs, err = models.FindUserAccessibleRepoIDs(ctx.User)
|
|
if err != nil {
|
|
ctx.ServerError("SearchResults", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
var (
|
|
total int
|
|
searchResults []*code_indexer.Result
|
|
searchResultLanguages []*code_indexer.SearchResultLanguages
|
|
)
|
|
|
|
// if non-admin login user, we need check UnitTypeCode at first
|
|
if ctx.User != nil && len(repoIDs) > 0 {
|
|
repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
|
|
if err != nil {
|
|
ctx.ServerError("SearchResults", err)
|
|
return
|
|
}
|
|
|
|
var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
|
|
repoIDs = make([]int64, 0, len(repoMaps))
|
|
for id, repo := range repoMaps {
|
|
if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
|
|
rightRepoMap[id] = repo
|
|
repoIDs = append(repoIDs, id)
|
|
}
|
|
}
|
|
|
|
ctx.Data["RepoMaps"] = rightRepoMap
|
|
|
|
total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
|
|
if err != nil {
|
|
ctx.ServerError("SearchResults", err)
|
|
return
|
|
}
|
|
// if non-login user or isAdmin, no need to check UnitTypeCode
|
|
} else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
|
|
total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
|
|
if err != nil {
|
|
ctx.ServerError("SearchResults", err)
|
|
return
|
|
}
|
|
|
|
var loadRepoIDs = make([]int64, 0, len(searchResults))
|
|
for _, result := range searchResults {
|
|
var find bool
|
|
for _, id := range loadRepoIDs {
|
|
if id == result.RepoID {
|
|
find = true
|
|
break
|
|
}
|
|
}
|
|
if !find {
|
|
loadRepoIDs = append(loadRepoIDs, result.RepoID)
|
|
}
|
|
}
|
|
|
|
repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
|
|
if err != nil {
|
|
ctx.ServerError("SearchResults", err)
|
|
return
|
|
}
|
|
|
|
ctx.Data["RepoMaps"] = repoMaps
|
|
}
|
|
|
|
ctx.Data["Keyword"] = keyword
|
|
ctx.Data["Language"] = language
|
|
ctx.Data["SearchResults"] = searchResults
|
|
ctx.Data["SearchResultLanguages"] = searchResultLanguages
|
|
ctx.Data["RequireHighlightJS"] = true
|
|
ctx.Data["PageIsViewCode"] = true
|
|
|
|
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
|
|
pager.SetDefaultParams(ctx)
|
|
pager.AddParam(ctx, "l", "Language")
|
|
ctx.Data["Page"] = pager
|
|
|
|
ctx.HTML(200, tplExploreCode)
|
|
}
|
|
|
|
// NotFound render 404 page
|
|
func NotFound(ctx *context.Context) {
|
|
ctx.Data["Title"] = "Page Not Found"
|
|
ctx.NotFound("home.NotFound", nil)
|
|
}
|