Browse Source

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>
tags/v1.15.0-rc1
Lunny Xiao 2 years ago
parent
commit
1bfb0a24d8
No account linked to committer's email address
100 changed files with 912 additions and 696 deletions
  1. 1
    3
      .golangci.yml
  2. 4
    4
      cmd/web.go
  3. 1
    2
      contrib/pr/checkout.go
  4. 3
    3
      integrations/create_no_session_test.go
  5. 1
    2
      integrations/integration_test.go
  6. 4
    4
      integrations/lfs_getobject_test.go
  7. 3
    3
      routers/api/v1/repo/file.go
  8. 39
    0
      routers/common/db.go
  9. 33
    0
      routers/common/logger.go
  10. 76
    0
      routers/common/middleware.go
  11. 127
    0
      routers/common/repo.go
  12. 0
    413
      routers/home.go
  13. 19
    61
      routers/init.go
  14. 7
    6
      routers/install/install.go
  15. 21
    17
      routers/install/routes.go
  16. 49
    0
      routers/install/setting.go
  17. 0
    0
      routers/web/admin/admin.go
  18. 0
    0
      routers/web/admin/admin_test.go
  19. 0
    0
      routers/web/admin/auths.go
  20. 0
    0
      routers/web/admin/emails.go
  21. 0
    0
      routers/web/admin/hooks.go
  22. 1
    1
      routers/web/admin/main_test.go
  23. 0
    0
      routers/web/admin/notice.go
  24. 2
    2
      routers/web/admin/orgs.go
  25. 2
    2
      routers/web/admin/repos.go
  26. 3
    3
      routers/web/admin/users.go
  27. 0
    0
      routers/web/admin/users_test.go
  28. 15
    40
      routers/web/base.go
  29. 0
    0
      routers/web/dev/template.go
  30. 1
    1
      routers/web/events/events.go
  31. 139
    0
      routers/web/explore/code.go
  32. 39
    0
      routers/web/explore/org.go
  33. 131
    0
      routers/web/explore/repo.go
  34. 107
    0
      routers/web/explore/user.go
  35. 1
    1
      routers/web/goget.go
  36. 65
    0
      routers/web/home.go
  37. 1
    1
      routers/web/metrics.go
  38. 0
    0
      routers/web/org/home.go
  39. 0
    0
      routers/web/org/members.go
  40. 0
    0
      routers/web/org/org.go
  41. 0
    0
      routers/web/org/org_labels.go
  42. 1
    1
      routers/web/org/setting.go
  43. 0
    0
      routers/web/org/teams.go
  44. 0
    0
      routers/web/repo/activity.go
  45. 2
    1
      routers/web/repo/attachment.go
  46. 0
    0
      routers/web/repo/blame.go
  47. 0
    0
      routers/web/repo/branch.go
  48. 0
    0
      routers/web/repo/commit.go
  49. 0
    0
      routers/web/repo/compare.go
  50. 6
    94
      routers/web/repo/download.go
  51. 0
    0
      routers/web/repo/editor.go
  52. 0
    0
      routers/web/repo/editor_test.go
  53. 0
    0
      routers/web/repo/http.go
  54. 0
    0
      routers/web/repo/issue.go
  55. 0
    0
      routers/web/repo/issue_dependency.go
  56. 0
    0
      routers/web/repo/issue_label.go
  57. 0
    0
      routers/web/repo/issue_label_test.go
  58. 0
    0
      routers/web/repo/issue_lock.go
  59. 0
    0
      routers/web/repo/issue_stopwatch.go
  60. 0
    0
      routers/web/repo/issue_test.go
  61. 0
    0
      routers/web/repo/issue_timetrack.go
  62. 0
    0
      routers/web/repo/issue_watch.go
  63. 0
    0
      routers/web/repo/lfs.go
  64. 1
    1
      routers/web/repo/main_test.go
  65. 0
    0
      routers/web/repo/middlewares.go
  66. 0
    0
      routers/web/repo/migrate.go
  67. 0
    0
      routers/web/repo/milestone.go
  68. 0
    0
      routers/web/repo/projects.go
  69. 0
    0
      routers/web/repo/projects_test.go
  70. 0
    0
      routers/web/repo/pull.go
  71. 0
    0
      routers/web/repo/pull_review.go
  72. 0
    0
      routers/web/repo/release.go
  73. 0
    0
      routers/web/repo/release_test.go
  74. 0
    24
      routers/web/repo/repo.go
  75. 0
    0
      routers/web/repo/search.go
  76. 0
    0
      routers/web/repo/setting.go
  77. 0
    0
      routers/web/repo/setting_protected_branch.go
  78. 0
    0
      routers/web/repo/settings_test.go
  79. 0
    0
      routers/web/repo/topic.go
  80. 0
    0
      routers/web/repo/view.go
  81. 0
    0
      routers/web/repo/webhook.go
  82. 2
    1
      routers/web/repo/wiki.go
  83. 0
    0
      routers/web/repo/wiki_test.go
  84. 1
    1
      routers/web/swagger_json.go
  85. 0
    0
      routers/web/user/auth.go
  86. 0
    0
      routers/web/user/auth_openid.go
  87. 0
    0
      routers/web/user/avatar.go
  88. 0
    0
      routers/web/user/home.go
  89. 0
    0
      routers/web/user/home_test.go
  90. 1
    1
      routers/web/user/main_test.go
  91. 0
    0
      routers/web/user/notification.go
  92. 0
    0
      routers/web/user/oauth.go
  93. 1
    1
      routers/web/user/profile.go
  94. 0
    0
      routers/web/user/setting/account.go
  95. 0
    0
      routers/web/user/setting/account_test.go
  96. 0
    0
      routers/web/user/setting/adopt.go
  97. 0
    0
      routers/web/user/setting/applications.go
  98. 0
    0
      routers/web/user/setting/keys.go
  99. 2
    2
      routers/web/user/setting/main_test.go
  100. 0
    0
      routers/web/user/setting/oauth2.go

+ 1
- 3
.golangci.yml View File

@@ -70,9 +70,6 @@ issues:
- path: modules/log/
linters:
- errcheck
- path: routers/routes/web.go
linters:
- dupl
- path: routers/api/v1/repo/issue_subscription.go
linters:
- dupl
@@ -114,3 +111,4 @@ issues:
linters:
- staticcheck
text: "svc.IsAnInteractiveSession is deprecated: Use IsWindowsService instead."


+ 4
- 4
cmd/web.go View File

@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"
"code.gitea.io/gitea/routers/install"

context2 "github.com/gorilla/context"
"github.com/urfave/cli"
@@ -88,7 +88,7 @@ func runWeb(ctx *cli.Context) error {
}

// Perform pre-initialization
needsInstall := routers.PreInstallInit(graceful.GetManager().HammerContext())
needsInstall := install.PreloadSettings(graceful.GetManager().HammerContext())
if needsInstall {
// Flag for port number in case first time run conflict
if ctx.IsSet("port") {
@@ -101,7 +101,7 @@ func runWeb(ctx *cli.Context) error {
return err
}
}
c := routes.InstallRoutes()
c := install.Routes()
err := listen(c, false)
select {
case <-graceful.GetManager().IsShutdown():
@@ -134,7 +134,7 @@ func runWeb(ctx *cli.Context) error {
}

// Set up Chi routes
c := routes.NormalRoutes()
c := routers.NormalRoutes()
err := listen(c, true)
<-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid())

+ 1
- 2
contrib/pr/checkout.go View File

@@ -31,7 +31,6 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
@@ -116,7 +115,7 @@ func runPR() {
//routers.GlobalInit()
external.RegisterRenderers()
markup.Init()
c := routes.NormalRoutes()
c := routers.NormalRoutes()

log.Printf("[PR] Ready for testing !\n")
log.Printf("[PR] Login with user1, user2, user3, ... with pass: password\n")

+ 3
- 3
integrations/create_no_session_test.go View File

@@ -14,7 +14,7 @@ import (

"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/routes"
"code.gitea.io/gitea/routers"

"gitea.com/go-chi/session"
jsoniter "github.com/json-iterator/go"
@@ -58,7 +58,7 @@ func TestSessionFileCreation(t *testing.T) {
oldSessionConfig := setting.SessionConfig.ProviderConfig
defer func() {
setting.SessionConfig.ProviderConfig = oldSessionConfig
c = routes.NormalRoutes()
c = routers.NormalRoutes()
}()

var config session.Options
@@ -84,7 +84,7 @@ func TestSessionFileCreation(t *testing.T) {

setting.SessionConfig.ProviderConfig = string(newConfigBytes)

c = routes.NormalRoutes()
c = routers.NormalRoutes()

t.Run("NoSessionOnViewIssue", func(t *testing.T) {
defer PrintCurrentTest(t)()

+ 1
- 2
integrations/integration_test.go View File

@@ -34,7 +34,6 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes"

"github.com/PuerkitoBio/goquery"
jsoniter "github.com/json-iterator/go"
@@ -88,7 +87,7 @@ func TestMain(m *testing.M) {
defer cancel()

initIntegrationTest()
c = routes.NormalRoutes()
c = routers.NormalRoutes()

// integration test settings...
if setting.Cfg != nil {

+ 4
- 4
integrations/lfs_getobject_test.go View File

@@ -15,7 +15,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/routes"
"code.gitea.io/gitea/routers/web"

jsoniter "github.com/json-iterator/go"
gzipp "github.com/klauspost/compress/gzip"
@@ -99,7 +99,7 @@ func TestGetLFSLarge(t *testing.T) {
t.Skip()
return
}
content := make([]byte, routes.GzipMinSize*10)
content := make([]byte, web.GzipMinSize*10)
for i := range content {
content[i] = byte(i % 256)
}
@@ -115,7 +115,7 @@ func TestGetLFSGzip(t *testing.T) {
t.Skip()
return
}
b := make([]byte, routes.GzipMinSize*10)
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
}
@@ -136,7 +136,7 @@ func TestGetLFSZip(t *testing.T) {
t.Skip()
return
}
b := make([]byte, routes.GzipMinSize*10)
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
}

+ 3
- 3
routers/api/v1/repo/file.go View File

@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/repofiles"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/repo"
"code.gitea.io/gitea/routers/common"
)

// GetRawFile get a file by path on a repository
@@ -83,7 +83,7 @@ func GetRawFile(ctx *context.APIContext) {
}
return
}
if err = repo.ServeBlob(ctx.Context, blob); err != nil {
if err = common.ServeBlob(ctx.Context, blob); err != nil {
ctx.Error(http.StatusInternalServerError, "ServeBlob", err)
}
}
@@ -126,7 +126,7 @@ func GetArchive(ctx *context.APIContext) {
ctx.Repo.GitRepo = gitRepo
defer gitRepo.Close()

repo.Download(ctx.Context)
common.Download(ctx.Context)
}

// GetEditorconfig get editor config of a repository

+ 39
- 0
routers/common/db.go View File

@@ -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
}

+ 33
- 0
routers/common/logger.go View File

@@ -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)))
})
}
}

+ 76
- 0
routers/common/middleware.go View File

@@ -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
}

+ 127
- 0
routers/common/repo.go View File

@@ -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
}

+ 0
- 413
routers/home.go View File

@@ -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)
}

+ 19
- 61
routers/init.go View File

@@ -6,12 +6,9 @@ package routers

import (
"context"
"fmt"
"strings"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/auth/sso"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/cron"
@@ -32,6 +29,11 @@ import (
"code.gitea.io/gitea/modules/svg"
"code.gitea.io/gitea/modules/task"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/web"
apiv1 "code.gitea.io/gitea/routers/api/v1"
"code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/routers/private"
web_routers "code.gitea.io/gitea/routers/web"
"code.gitea.io/gitea/services/mailer"
mirror_service "code.gitea.io/gitea/services/mirror"
pull_service "code.gitea.io/gitea/services/pull"
@@ -63,63 +65,6 @@ func NewServices() {
notification.NewContext()
}

// 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
}

// PreInstallInit preloads the configuration to check if we need to run install
func PreInstallInit(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
}

// PostInstallInit rereads the settings and starts up the database
func PostInstallInit(ctx context.Context) {
setting.NewContext()
setting.InitDBConfig()
if setting.InstallLock {
if err := initDBEngine(ctx); err == nil {
log.Info("ORM engine initialization successful!")
} else {
log.Fatal("ORM engine initialization failed: %v", err)
}
svg.Init()
}
}

// GlobalInit is for global configuration reload-able.
func GlobalInit(ctx context.Context) {
setting.NewContext()
@@ -151,7 +96,7 @@ func GlobalInit(ctx context.Context) {
} else if setting.Database.UseSQLite3 {
log.Fatal("SQLite3 is set in settings but NOT Supported")
}
if err := initDBEngine(ctx); err == nil {
if err := common.InitDBEngine(ctx); err == nil {
log.Info("ORM engine initialization successful!")
} else {
log.Fatal("ORM engine initialization failed: %v", err)
@@ -193,3 +138,16 @@ func GlobalInit(ctx context.Context) {

svg.Init()
}

// NormalRoutes represents non install routes
func NormalRoutes() *web.Route {
r := web.NewRoute()
for _, middle := range common.Middlewares() {
r.Use(middle)
}

r.Mount("/", web_routers.Routes())
r.Mount("/api/v1", apiv1.Routes())
r.Mount("/api/internal", private.Routes())
return r
}

routers/install.go → routers/install/install.go View File

@@ -1,8 +1,9 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// 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 routers
package install

import (
"fmt"
@@ -38,8 +39,8 @@ const (
tplPostInstall base.TplName = "post-install"
)

// InstallInit prepare for rendering installation page
func InstallInit(next http.Handler) http.Handler {
// Init prepare for rendering installation page
func Init(next http.Handler) http.Handler {
var rnd = templates.HTMLRenderer()

return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
@@ -158,8 +159,8 @@ func Install(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplInstall)
}

// InstallPost response for submit install items
func InstallPost(ctx *context.Context) {
// SubmitInstall response for submit install items
func SubmitInstall(ctx *context.Context) {
form := *web.GetForm(ctx).(*forms.InstallForm)
var err error
ctx.Data["CurDbOption"] = form.DbType
@@ -409,7 +410,7 @@ func InstallPost(ctx *context.Context) {
}

// Re-read settings
PostInstallInit(ctx)
ReloadSettings(ctx)

// Create admin account
if len(form.AdminName) > 0 {

routers/routes/install.go → routers/install/routes.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package routes
package install

import (
"fmt"
@@ -15,12 +15,18 @@ import (
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/forms"

"gitea.com/go-chi/session"
)

type dataStore map[string]interface{}

func (d *dataStore) GetData() map[string]interface{} {
return *d
}

func installRecovery() func(next http.Handler) http.Handler {
var rnd = templates.HTMLRenderer()
return func(next http.Handler) http.Handler {
@@ -48,21 +54,19 @@ func installRecovery() func(next http.Handler) http.Handler {

lc := middleware.Locale(w, req)
var store = dataStore{
Data: templates.Vars{
"Language": lc.Language(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
"i18n": lc,
"SignedUserID": int64(0),
"SignedUserName": "",
},
"Language": lc.Language(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
"i18n": lc,
"SignedUserID": int64(0),
"SignedUserName": "",
}

w.Header().Set(`X-Frame-Options`, `SAMEORIGIN`)

if !setting.IsProd() {
store.Data["ErrorMsg"] = combinedErr
store["ErrorMsg"] = combinedErr
}
err = rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store.Data))
err = rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store))
if err != nil {
log.Error("%v", err)
}
@@ -74,10 +78,10 @@ func installRecovery() func(next http.Handler) http.Handler {
}
}

// InstallRoutes registers the install routes
func InstallRoutes() *web.Route {
// Routes registers the install routes
func Routes() *web.Route {
r := web.NewRoute()
for _, middle := range commonMiddlewares() {
for _, middle := range common.Middlewares() {
r.Use(middle)
}

@@ -99,9 +103,9 @@ func InstallRoutes() *web.Route {
}))

r.Use(installRecovery())
r.Use(routers.InstallInit)
r.Get("/", routers.Install)
r.Post("/", web.Bind(forms.InstallForm{}), routers.InstallPost)
r.Use(Init)
r.Get("/", Install)
r.Post("/", web.Bind(forms.InstallForm{}), SubmitInstall)
r.NotFound(func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, setting.AppURL, http.StatusFound)
})

+ 49
- 0
routers/install/setting.go View File

@@ -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()
}
}

routers/admin/admin.go → routers/web/admin/admin.go View File


routers/admin/admin_test.go → routers/web/admin/admin_test.go View File


routers/admin/auths.go → routers/web/admin/auths.go View File


routers/admin/emails.go → routers/web/admin/emails.go View File


routers/admin/hooks.go → routers/web/admin/hooks.go View File


routers/user/setting/main_test.go → routers/web/admin/main_test.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package setting
package admin

import (
"path/filepath"

routers/admin/notice.go → routers/web/admin/notice.go View File


routers/admin/orgs.go → routers/web/admin/orgs.go View File

@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/web/explore"
)

const (
@@ -24,7 +24,7 @@ func Organizations(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminOrganizations"] = true

routers.RenderUserSearch(ctx, &models.SearchUserOptions{
explore.RenderUserSearch(ctx, &models.SearchUserOptions{
Type: models.UserTypeOrganization,
ListOptions: models.ListOptions{
PageSize: setting.UI.Admin.OrgPagingNum,

routers/admin/repos.go → routers/web/admin/repos.go View File

@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/web/explore"
repo_service "code.gitea.io/gitea/services/repository"
)

@@ -32,7 +32,7 @@ func Repos(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminRepositories"] = true

routers.RenderRepoSearch(ctx, &routers.RepoSearchOptions{
explore.RenderRepoSearch(ctx, &explore.RepoSearchOptions{
Private: true,
PageSize: setting.UI.Admin.RepoPagingNum,
TplName: tplRepos,

routers/admin/users.go → routers/web/admin/users.go View File

@@ -18,8 +18,8 @@ import (
"code.gitea.io/gitea/modules/password"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers"
router_user_setting "code.gitea.io/gitea/routers/user/setting"
"code.gitea.io/gitea/routers/web/explore"
router_user_setting "code.gitea.io/gitea/routers/web/user/setting"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/mailer"
)
@@ -36,7 +36,7 @@ func Users(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminUsers"] = true

routers.RenderUserSearch(ctx, &models.SearchUserOptions{
explore.RenderUserSearch(ctx, &models.SearchUserOptions{
Type: models.UserTypeIndividual,
ListOptions: models.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum,

routers/admin/users_test.go → routers/web/admin/users_test.go View File


routers/routes/base.go → routers/web/base.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package routes
package web

import (
"errors"
@@ -13,7 +13,6 @@ import (
"path"
"path/filepath"
"strings"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/sso"
@@ -28,26 +27,6 @@ import (
"gitea.com/go-chi/session"
)

// 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)))
})
}
}

func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if storageSetting.ServeDirect {
@@ -134,12 +113,10 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
}
}

type dataStore struct {
Data map[string]interface{}
}
type dataStore map[string]interface{}

func (d *dataStore) GetData() map[string]interface{} {
return d.Data
return *d
}

// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so.
@@ -165,11 +142,9 @@ func Recovery() func(next http.Handler) http.Handler {

var lc = middleware.Locale(w, req)
var store = dataStore{
Data: templates.Vars{
"Language": lc.Language(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
"i18n": lc,
},
"Language": lc.Language(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
"i18n": lc,
}

var user *models.User
@@ -186,22 +161,22 @@ func Recovery() func(next http.Handler) http.Handler {
user = sso.SessionUser(sessionStore)
}
if user != nil {
store.Data["IsSigned"] = true
store.Data["SignedUser"] = user
store.Data["SignedUserID"] = user.ID
store.Data["SignedUserName"] = user.Name
store.Data["IsAdmin"] = user.IsAdmin
store["IsSigned"] = true
store["SignedUser"] = user
store["SignedUserID"] = user.ID
store["SignedUserName"] = user.Name
store["IsAdmin"] = user.IsAdmin
} else {
store.Data["SignedUserID"] = int64(0)
store.Data["SignedUserName"] = ""
store["SignedUserID"] = int64(0)
store["SignedUserName"] = ""
}

w.Header().Set(`X-Frame-Options`, `SAMEORIGIN`)

if !setting.IsProd() {
store.Data["ErrorMsg"] = combinedErr
store["ErrorMsg"] = combinedErr
}
err = rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store.Data))
err = rnd.HTML(w, 500, "status/500", templates.BaseVars().Merge(store))
if err != nil {
log.Error("%v", err)
}

routers/dev/template.go → routers/web/dev/template.go View File


routers/events/events.go → routers/web/events/events.go View File

@@ -15,7 +15,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/user"
"code.gitea.io/gitea/routers/web/user"
jsoniter "github.com/json-iterator/go"
)


+ 139
- 0
routers/web/explore/code.go View File

@@ -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)
}

+ 39
- 0
routers/web/explore/org.go View File

@@ -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)
}

+ 131
- 0
routers/web/explore/repo.go View File

@@ -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,
})
}

+ 107
- 0
routers/web/explore/user.go View File

@@ -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)
}

routers/routes/goget.go → routers/web/goget.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package routes
package web

import (
"net/http"

+ 65
- 0
routers/web/home.go View File

@@ -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)
}

routers/metrics.go → routers/web/metrics.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package routers
package web

import (
"crypto/subtle"

routers/org/home.go → routers/web/org/home.go View File


routers/org/members.go → routers/web/org/members.go View File


routers/org/org.go → routers/web/org/org.go View File


routers/org/org_labels.go → routers/web/org/org_labels.go View File


routers/org/setting.go → routers/web/org/setting.go View File

@@ -15,7 +15,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
userSetting "code.gitea.io/gitea/routers/user/setting"
userSetting "code.gitea.io/gitea/routers/web/user/setting"
"code.gitea.io/gitea/services/forms"
)


routers/org/teams.go → routers/web/org/teams.go View File


routers/repo/activity.go → routers/web/repo/activity.go View File


routers/repo/attachment.go → routers/web/repo/attachment.go View File

@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/upload"
"code.gitea.io/gitea/routers/common"
)

// UploadIssueAttachment response for Issue/PR attachments
@@ -152,7 +153,7 @@ func GetAttachment(ctx *context.Context) {
}
defer fr.Close()

if err = ServeData(ctx, attach.Name, attach.Size, fr); err != nil {
if err = common.ServeData(ctx, attach.Name, attach.Size, fr); err != nil {
ctx.ServerError("ServeData", err)
return
}

routers/repo/blame.go → routers/web/repo/blame.go View File


routers/repo/branch.go → routers/web/repo/branch.go View File


routers/repo/commit.go → routers/web/repo/commit.go View File


routers/repo/compare.go → routers/web/repo/compare.go View File


routers/repo/download.go → routers/web/repo/download.go View File

@@ -6,102 +6,14 @@
package repo

import (
"fmt"
"io"
"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/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/routers/common"
)

// 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
}

// 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)
}

// ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`) {
@@ -130,7 +42,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
log.Error("ServeBlobOrLFS: Close: %v", err)
}
closed = true
return ServeBlob(ctx, blob)
return common.ServeBlob(ctx, blob)
}
if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) {
return nil
@@ -144,14 +56,14 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob) error {
log.Error("ServeBlobOrLFS: Close: %v", err)
}
}()
return ServeData(ctx, ctx.Repo.TreePath, meta.Size, lfsDataRc)
return common.ServeData(ctx, ctx.Repo.TreePath, meta.Size, lfsDataRc)
}
if err = dataRc.Close(); err != nil {
log.Error("ServeBlobOrLFS: Close: %v", err)
}
closed = true

return ServeBlob(ctx, blob)
return common.ServeBlob(ctx, blob)
}

// SingleDownload download a file by repos path
@@ -165,7 +77,7 @@ func SingleDownload(ctx *context.Context) {
}
return
}
if err = ServeBlob(ctx, blob); err != nil {
if err = common.ServeBlob(ctx, blob); err != nil {
ctx.ServerError("ServeBlob", err)
}
}
@@ -197,7 +109,7 @@ func DownloadByID(ctx *context.Context) {
}
return
}
if err = ServeBlob(ctx, blob); err != nil {
if err = common.ServeBlob(ctx, blob); err != nil {
ctx.ServerError("ServeBlob", err)
}
}

routers/repo/editor.go → routers/web/repo/editor.go View File


routers/repo/editor_test.go → routers/web/repo/editor_test.go View File


routers/repo/http.go → routers/web/repo/http.go View File


routers/repo/issue.go → routers/web/repo/issue.go View File


routers/repo/issue_dependency.go → routers/web/repo/issue_dependency.go View File


routers/repo/issue_label.go → routers/web/repo/issue_label.go View File


routers/repo/issue_label_test.go → routers/web/repo/issue_label_test.go View File


routers/repo/issue_lock.go → routers/web/repo/issue_lock.go View File


routers/repo/issue_stopwatch.go → routers/web/repo/issue_stopwatch.go View File


routers/repo/issue_test.go → routers/web/repo/issue_test.go View File


routers/repo/issue_timetrack.go → routers/web/repo/issue_timetrack.go View File


routers/repo/issue_watch.go → routers/web/repo/issue_watch.go View File


routers/repo/lfs.go → routers/web/repo/lfs.go View File


routers/repo/main_test.go → routers/web/repo/main_test.go View File

@@ -12,5 +12,5 @@ import (
)

func TestMain(m *testing.M) {
models.MainTest(m, filepath.Join("..", ".."))
models.MainTest(m, filepath.Join("..", "..", ".."))
}

routers/repo/middlewares.go → routers/web/repo/middlewares.go View File


routers/repo/migrate.go → routers/web/repo/migrate.go View File


routers/repo/milestone.go → routers/web/repo/milestone.go View File


routers/repo/projects.go → routers/web/repo/projects.go View File


routers/repo/projects_test.go → routers/web/repo/projects_test.go View File


routers/repo/pull.go → routers/web/repo/pull.go View File


routers/repo/pull_review.go → routers/web/repo/pull_review.go View File


routers/repo/release.go → routers/web/repo/release.go View File


routers/repo/release_test.go → routers/web/repo/release_test.go View File


routers/repo/repo.go → routers/web/repo/repo.go View File

@@ -364,30 +364,6 @@ func RedirectDownload(ctx *context.Context) {
ctx.Error(http.StatusNotFound)
}

// Download an archive of a repository
func Download(ctx *context.Context) {
uri := ctx.Params("*")
aReq := archiver_service.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_service.ArchiveRepository(aReq)
complete = aReq.WaitForCompletion(ctx)
}

if complete {
ctx.ServeFile(aReq.GetArchivePath(), downloadName)
} else {
ctx.Error(http.StatusNotFound)
}
}

// InitiateDownload will enqueue an archival request, as needed. It may submit
// a request that's already in-progress, but the archiver service will just
// kind of drop it on the floor if this is the case.

routers/repo/search.go → routers/web/repo/search.go View File


routers/repo/setting.go → routers/web/repo/setting.go View File


routers/repo/setting_protected_branch.go → routers/web/repo/setting_protected_branch.go View File


routers/repo/settings_test.go → routers/web/repo/settings_test.go View File


routers/repo/topic.go → routers/web/repo/topic.go View File


routers/repo/view.go → routers/web/repo/view.go View File


routers/repo/webhook.go → routers/web/repo/webhook.go View File


routers/repo/wiki.go → routers/web/repo/wiki.go View File

@@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/forms"
wiki_service "code.gitea.io/gitea/services/wiki"
)
@@ -558,7 +559,7 @@ func WikiRaw(ctx *context.Context) {
}

if entry != nil {
if err = ServeBlob(ctx, entry.Blob()); err != nil {
if err = common.ServeBlob(ctx, entry.Blob()); err != nil {
ctx.ServerError("ServeBlob", err)
}
return

routers/repo/wiki_test.go → routers/web/repo/wiki_test.go View File


routers/swagger_json.go → routers/web/swagger_json.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package routers
package web

import (
"net/http"

routers/user/auth.go → routers/web/user/auth.go View File


routers/user/auth_openid.go → routers/web/user/auth_openid.go View File


routers/user/avatar.go → routers/web/user/avatar.go View File


routers/user/home.go → routers/web/user/home.go View File


routers/user/home_test.go → routers/web/user/home_test.go View File


routers/user/main_test.go → routers/web/user/main_test.go View File

@@ -12,5 +12,5 @@ import (
)

func TestMain(m *testing.M) {
models.MainTest(m, filepath.Join("..", ".."))
models.MainTest(m, filepath.Join("..", "..", ".."))
}

routers/user/notification.go → routers/web/user/notification.go View File


routers/user/oauth.go → routers/web/user/oauth.go View File


routers/user/profile.go → routers/web/user/profile.go View File

@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/org"
"code.gitea.io/gitea/routers/web/org"
)

// GetUserByName get user by name

routers/user/setting/account.go → routers/web/user/setting/account.go View File


routers/user/setting/account_test.go → routers/web/user/setting/account_test.go View File


routers/user/setting/adopt.go → routers/web/user/setting/adopt.go View File


routers/user/setting/applications.go → routers/web/user/setting/applications.go View File


routers/user/setting/keys.go → routers/web/user/setting/keys.go View File


routers/admin/main_test.go → routers/web/user/setting/main_test.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package admin
package setting

import (
"path/filepath"
@@ -12,5 +12,5 @@ import (
)

func TestMain(m *testing.M) {
models.MainTest(m, filepath.Join("..", ".."))
models.MainTest(m, filepath.Join("..", "..", "..", ".."))
}

routers/user/setting/oauth2.go → routers/web/user/setting/oauth2.go View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save