Refactor routers directory (#15800)
* refactor routers directory * move func used for web and api to common * make corsHandler a function to prohibit side efects * rm unused func Co-authored-by: 6543 <6543@obermui.de>tokarchuk/v1.17
parent
e03a91a48e
commit
1bfb0a24d8
@ -0,0 +1,39 @@ |
|||||||
|
// 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 common |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
"time" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/models/migrations" |
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
) |
||||||
|
|
||||||
|
// InitDBEngine In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology
|
||||||
|
func InitDBEngine(ctx context.Context) (err error) { |
||||||
|
log.Info("Beginning ORM engine initialization.") |
||||||
|
for i := 0; i < setting.Database.DBConnectRetries; i++ { |
||||||
|
select { |
||||||
|
case <-ctx.Done(): |
||||||
|
return fmt.Errorf("Aborted due to shutdown:\nin retry ORM engine initialization") |
||||||
|
default: |
||||||
|
} |
||||||
|
log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries) |
||||||
|
if err = models.NewEngine(ctx, migrations.Migrate); err == nil { |
||||||
|
break |
||||||
|
} else if i == setting.Database.DBConnectRetries-1 { |
||||||
|
return err |
||||||
|
} |
||||||
|
log.Error("ORM engine initialization attempt #%d/%d failed. Error: %v", i+1, setting.Database.DBConnectRetries, err) |
||||||
|
log.Info("Backing off for %d seconds", int64(setting.Database.DBConnectBackoff/time.Second)) |
||||||
|
time.Sleep(setting.Database.DBConnectBackoff) |
||||||
|
} |
||||||
|
models.HasEngine = true |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
// 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 common |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"time" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
) |
||||||
|
|
||||||
|
// LoggerHandler is a handler that will log the routing to the default gitea log
|
||||||
|
func LoggerHandler(level log.Level) func(next http.Handler) http.Handler { |
||||||
|
return func(next http.Handler) http.Handler { |
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { |
||||||
|
start := time.Now() |
||||||
|
|
||||||
|
_ = log.GetLogger("router").Log(0, level, "Started %s %s for %s", log.ColoredMethod(req.Method), req.URL.RequestURI(), req.RemoteAddr) |
||||||
|
|
||||||
|
next.ServeHTTP(w, req) |
||||||
|
|
||||||
|
var status int |
||||||
|
if v, ok := w.(context.ResponseWriter); ok { |
||||||
|
status = v.Status() |
||||||
|
} |
||||||
|
|
||||||
|
_ = log.GetLogger("router").Log(0, level, "Completed %s %s %v %s in %v", log.ColoredMethod(req.Method), req.URL.RequestURI(), log.ColoredStatus(status), log.ColoredStatus(status, http.StatusText(status)), log.ColoredTime(time.Since(start))) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
// 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 common |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
|
||||||
|
"github.com/chi-middleware/proxy" |
||||||
|
"github.com/go-chi/chi/middleware" |
||||||
|
) |
||||||
|
|
||||||
|
// Middlewares returns common middlewares
|
||||||
|
func Middlewares() []func(http.Handler) http.Handler { |
||||||
|
var handlers = []func(http.Handler) http.Handler{ |
||||||
|
func(next http.Handler) http.Handler { |
||||||
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||||
|
next.ServeHTTP(context.NewResponse(resp), req) |
||||||
|
}) |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
if setting.ReverseProxyLimit > 0 { |
||||||
|
opt := proxy.NewForwardedHeadersOptions(). |
||||||
|
WithForwardLimit(setting.ReverseProxyLimit). |
||||||
|
ClearTrustedProxies() |
||||||
|
for _, n := range setting.ReverseProxyTrustedProxies { |
||||||
|
if !strings.Contains(n, "/") { |
||||||
|
opt.AddTrustedProxy(n) |
||||||
|
} else { |
||||||
|
opt.AddTrustedNetwork(n) |
||||||
|
} |
||||||
|
} |
||||||
|
handlers = append(handlers, proxy.ForwardedHeaders(opt)) |
||||||
|
} |
||||||
|
|
||||||
|
handlers = append(handlers, middleware.StripSlashes) |
||||||
|
|
||||||
|
if !setting.DisableRouterLog && setting.RouterLogLevel != log.NONE { |
||||||
|
if log.GetLogger("router").GetLevel() <= setting.RouterLogLevel { |
||||||
|
handlers = append(handlers, LoggerHandler(setting.RouterLogLevel)) |
||||||
|
} |
||||||
|
} |
||||||
|
if setting.EnableAccessLog { |
||||||
|
handlers = append(handlers, context.AccessLogger()) |
||||||
|
} |
||||||
|
|
||||||
|
handlers = append(handlers, func(next http.Handler) http.Handler { |
||||||
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||||
|
// Why we need this? The Recovery() will try to render a beautiful
|
||||||
|
// error page for user, but the process can still panic again, and other
|
||||||
|
// middleware like session also may panic then we have to recover twice
|
||||||
|
// and send a simple error page that should not panic any more.
|
||||||
|
defer func() { |
||||||
|
if err := recover(); err != nil { |
||||||
|
combinedErr := fmt.Sprintf("PANIC: %v\n%s", err, string(log.Stack(2))) |
||||||
|
log.Error("%v", combinedErr) |
||||||
|
if setting.IsProd() { |
||||||
|
http.Error(resp, http.StatusText(500), 500) |
||||||
|
} else { |
||||||
|
http.Error(resp, combinedErr, 500) |
||||||
|
} |
||||||
|
} |
||||||
|
}() |
||||||
|
next.ServeHTTP(resp, req) |
||||||
|
}) |
||||||
|
}) |
||||||
|
return handlers |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
// 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 common |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"net/http" |
||||||
|
"path" |
||||||
|
"path/filepath" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/charset" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/git" |
||||||
|
"code.gitea.io/gitea/modules/httpcache" |
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/typesniffer" |
||||||
|
"code.gitea.io/gitea/services/archiver" |
||||||
|
) |
||||||
|
|
||||||
|
// ServeBlob download a git.Blob
|
||||||
|
func ServeBlob(ctx *context.Context, blob *git.Blob) error { |
||||||
|
if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
dataRc, err := blob.DataAsync() |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
defer func() { |
||||||
|
if err = dataRc.Close(); err != nil { |
||||||
|
log.Error("ServeBlob: Close: %v", err) |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
return ServeData(ctx, ctx.Repo.TreePath, blob.Size(), dataRc) |
||||||
|
} |
||||||
|
|
||||||
|
// Download an archive of a repository
|
||||||
|
func Download(ctx *context.Context) { |
||||||
|
uri := ctx.Params("*") |
||||||
|
aReq := archiver.DeriveRequestFrom(ctx, uri) |
||||||
|
|
||||||
|
if aReq == nil { |
||||||
|
ctx.Error(http.StatusNotFound) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
downloadName := ctx.Repo.Repository.Name + "-" + aReq.GetArchiveName() |
||||||
|
complete := aReq.IsComplete() |
||||||
|
if !complete { |
||||||
|
aReq = archiver.ArchiveRepository(aReq) |
||||||
|
complete = aReq.WaitForCompletion(ctx) |
||||||
|
} |
||||||
|
|
||||||
|
if complete { |
||||||
|
ctx.ServeFile(aReq.GetArchivePath(), downloadName) |
||||||
|
} else { |
||||||
|
ctx.Error(http.StatusNotFound) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ServeData download file from io.Reader
|
||||||
|
func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) error { |
||||||
|
buf := make([]byte, 1024) |
||||||
|
n, err := reader.Read(buf) |
||||||
|
if err != nil && err != io.EOF { |
||||||
|
return err |
||||||
|
} |
||||||
|
if n >= 0 { |
||||||
|
buf = buf[:n] |
||||||
|
} |
||||||
|
|
||||||
|
ctx.Resp.Header().Set("Cache-Control", "public,max-age=86400") |
||||||
|
|
||||||
|
if size >= 0 { |
||||||
|
ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", size)) |
||||||
|
} else { |
||||||
|
log.Error("ServeData called to serve data: %s with size < 0: %d", name, size) |
||||||
|
} |
||||||
|
name = path.Base(name) |
||||||
|
|
||||||
|
// Google Chrome dislike commas in filenames, so let's change it to a space
|
||||||
|
name = strings.ReplaceAll(name, ",", " ") |
||||||
|
|
||||||
|
st := typesniffer.DetectContentType(buf) |
||||||
|
|
||||||
|
if st.IsText() || ctx.QueryBool("render") { |
||||||
|
cs, err := charset.DetectEncoding(buf) |
||||||
|
if err != nil { |
||||||
|
log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err) |
||||||
|
cs = "utf-8" |
||||||
|
} |
||||||
|
ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs)) |
||||||
|
} else { |
||||||
|
ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") |
||||||
|
|
||||||
|
if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) { |
||||||
|
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) |
||||||
|
if st.IsSvgImage() { |
||||||
|
ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox") |
||||||
|
ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") |
||||||
|
ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType) |
||||||
|
} |
||||||
|
} else { |
||||||
|
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) |
||||||
|
if setting.MimeTypeMap.Enabled { |
||||||
|
fileExtension := strings.ToLower(filepath.Ext(name)) |
||||||
|
if mimetype, ok := setting.MimeTypeMap.Map[fileExtension]; ok { |
||||||
|
ctx.Resp.Header().Set("Content-Type", mimetype) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_, err = ctx.Resp.Write(buf) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
_, err = io.Copy(ctx.Resp, reader) |
||||||
|
return err |
||||||
|
} |
@ -1,413 +0,0 @@ |
|||||||
// 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" |
|
||||||
"net/http" |
|
||||||
"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/modules/web/middleware" |
|
||||||
"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(http.StatusOK, 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(http.StatusOK, "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" |
|
||||||
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) |
|
||||||
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(http.StatusOK, 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(http.StatusOK, opts.TplName) |
|
||||||
} |
|
||||||
|
|
||||||
// ExploreRepos render explore repositories page
|
|
||||||
func ExploreRepos(ctx *context.Context) { |
|
||||||
ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
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["UsersTwoFaStatus"] = models.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) |
|
||||||
ctx.Data["Page"] = pager |
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplName) |
|
||||||
} |
|
||||||
|
|
||||||
// ExploreUsers render explore users page
|
|
||||||
func ExploreUsers(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, &models.SearchUserOptions{ |
|
||||||
Actor: ctx.User, |
|
||||||
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["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
|
||||||
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{ |
|
||||||
Actor: ctx.User, |
|
||||||
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["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
queryType := strings.TrimSpace(ctx.Query("t")) |
|
||||||
isMatch := queryType == "match" |
|
||||||
|
|
||||||
var ( |
|
||||||
repoIDs []int64 |
|
||||||
err error |
|
||||||
isAdmin bool |
|
||||||
) |
|
||||||
if ctx.User != nil { |
|
||||||
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(ctx.User, 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, isMatch) |
|
||||||
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, isMatch) |
|
||||||
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["queryType"] = queryType |
|
||||||
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(http.StatusOK, tplExploreCode) |
|
||||||
} |
|
||||||
|
|
||||||
// NotFound render 404 page
|
|
||||||
func NotFound(ctx *context.Context) { |
|
||||||
ctx.Data["Title"] = "Page Not Found" |
|
||||||
ctx.NotFound("home.NotFound", nil) |
|
||||||
} |
|
@ -0,0 +1,49 @@ |
|||||||
|
// 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 install |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/svg" |
||||||
|
"code.gitea.io/gitea/modules/translation" |
||||||
|
"code.gitea.io/gitea/routers/common" |
||||||
|
) |
||||||
|
|
||||||
|
// PreloadSettings preloads the configuration to check if we need to run install
|
||||||
|
func PreloadSettings(ctx context.Context) bool { |
||||||
|
setting.NewContext() |
||||||
|
if !setting.InstallLock { |
||||||
|
log.Trace("AppPath: %s", setting.AppPath) |
||||||
|
log.Trace("AppWorkPath: %s", setting.AppWorkPath) |
||||||
|
log.Trace("Custom path: %s", setting.CustomPath) |
||||||
|
log.Trace("Log path: %s", setting.LogRootPath) |
||||||
|
log.Trace("Preparing to run install page") |
||||||
|
translation.InitLocales() |
||||||
|
if setting.EnableSQLite3 { |
||||||
|
log.Info("SQLite3 Supported") |
||||||
|
} |
||||||
|
setting.InitDBConfig() |
||||||
|
svg.Init() |
||||||
|
} |
||||||
|
|
||||||
|
return !setting.InstallLock |
||||||
|
} |
||||||
|
|
||||||
|
// ReloadSettings rereads the settings and starts up the database
|
||||||
|
func ReloadSettings(ctx context.Context) { |
||||||
|
setting.NewContext() |
||||||
|
setting.InitDBConfig() |
||||||
|
if setting.InstallLock { |
||||||
|
if err := common.InitDBEngine(ctx); err == nil { |
||||||
|
log.Info("ORM engine initialization successful!") |
||||||
|
} else { |
||||||
|
log.Fatal("ORM engine initialization failed: %v", err) |
||||||
|
} |
||||||
|
svg.Init() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
// 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 ( |
||||||
|
"net/http" |
||||||
|
"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/setting" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// tplExploreCode explore code page template
|
||||||
|
tplExploreCode base.TplName = "explore/code" |
||||||
|
) |
||||||
|
|
||||||
|
// Code render explore code page
|
||||||
|
func Code(ctx *context.Context) { |
||||||
|
if !setting.Indexer.RepoIndexerEnabled { |
||||||
|
ctx.Redirect(setting.AppSubURL+"/explore", 302) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
queryType := strings.TrimSpace(ctx.Query("t")) |
||||||
|
isMatch := queryType == "match" |
||||||
|
|
||||||
|
var ( |
||||||
|
repoIDs []int64 |
||||||
|
err error |
||||||
|
isAdmin bool |
||||||
|
) |
||||||
|
if ctx.User != nil { |
||||||
|
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(ctx.User, 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, isMatch) |
||||||
|
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, isMatch) |
||||||
|
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["queryType"] = queryType |
||||||
|
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(http.StatusOK, tplExploreCode) |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
// 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 ( |
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/structs" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// tplExploreOrganizations explore organizations page template
|
||||||
|
tplExploreOrganizations base.TplName = "explore/organizations" |
||||||
|
) |
||||||
|
|
||||||
|
// Organizations render explore organizations page
|
||||||
|
func Organizations(ctx *context.Context) { |
||||||
|
ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
||||||
|
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{ |
||||||
|
Actor: ctx.User, |
||||||
|
Type: models.UserTypeOrganization, |
||||||
|
ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum}, |
||||||
|
Visible: visibleTypes, |
||||||
|
}, tplExploreOrganizations) |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
// 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 ( |
||||||
|
"net/http" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// tplExploreRepos explore repositories page template
|
||||||
|
tplExploreRepos base.TplName = "explore/repos" |
||||||
|
) |
||||||
|
|
||||||
|
// RepoSearchOptions when calling search repositories
|
||||||
|
type RepoSearchOptions struct { |
||||||
|
OwnerID int64 |
||||||
|
Private bool |
||||||
|
Restricted bool |
||||||
|
PageSize int |
||||||
|
TplName base.TplName |
||||||
|
} |
||||||
|
|
||||||
|
// 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(http.StatusOK, opts.TplName) |
||||||
|
} |
||||||
|
|
||||||
|
// Repos render explore repositories page
|
||||||
|
func Repos(ctx *context.Context) { |
||||||
|
ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage |
||||||
|
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, |
||||||
|
}) |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
// 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" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/structs" |
||||||
|
"code.gitea.io/gitea/modules/util" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// tplExploreUsers explore users page template
|
||||||
|
tplExploreUsers base.TplName = "explore/users" |
||||||
|
) |
||||||
|
|
||||||
|
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 *models.SearchUserOptions, tplName base.TplName) { |
||||||
|
opts.Page = ctx.QueryInt("page") |
||||||
|
if opts.Page <= 1 { |
||||||
|
opts.Page = 1 |
||||||
|
} |
||||||
|
|
||||||
|
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["UsersTwoFaStatus"] = models.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) |
||||||
|
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, &models.SearchUserOptions{ |
||||||
|
Actor: ctx.User, |
||||||
|
Type: models.UserTypeIndividual, |
||||||
|
ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum}, |
||||||
|
IsActive: util.OptionalBoolTrue, |
||||||
|
Visible: []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate}, |
||||||
|
}, tplExploreUsers) |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
// 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 web |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"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/web/middleware" |
||||||
|
"code.gitea.io/gitea/routers/web/user" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
// tplHome home page template
|
||||||
|
tplHome base.TplName = "home" |
||||||
|
) |
||||||
|
|
||||||
|
// 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(http.StatusOK, 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(http.StatusOK, "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" |
||||||
|
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) |
||||||
|
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(http.StatusOK, tplHome) |
||||||
|
} |
||||||
|
|
||||||
|
// NotFound render 404 page
|
||||||
|
func NotFound(ctx *context.Context) { |
||||||
|
ctx.Data["Title"] = "Page Not Found" |
||||||
|
ctx.NotFound("home.NotFound", nil) |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue