aboutsummaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
Diffstat (limited to 'routers')
-rw-r--r--routers/api/actions/artifacts_chunks.go4
-rw-r--r--routers/api/actions/artifactsv4.go6
-rw-r--r--routers/api/packages/api.go22
-rw-r--r--routers/api/packages/cargo/cargo.go2
-rw-r--r--routers/api/packages/chef/auth.go7
-rw-r--r--routers/api/packages/container/blob.go2
-rw-r--r--routers/api/packages/container/container.go4
-rw-r--r--routers/api/packages/container/manifest.go2
-rw-r--r--routers/api/packages/nuget/nuget.go2
-rw-r--r--routers/api/v1/activitypub/reqsignature.go3
-rw-r--r--routers/api/v1/admin/hooks.go5
-rw-r--r--routers/api/v1/admin/user.go2
-rw-r--r--routers/api/v1/api.go16
-rw-r--r--routers/api/v1/repo/action.go4
-rw-r--r--routers/api/v1/repo/actions_run.go64
-rw-r--r--routers/api/v1/repo/branch.go32
-rw-r--r--routers/api/v1/repo/commits.go11
-rw-r--r--routers/api/v1/repo/download.go3
-rw-r--r--routers/api/v1/repo/file.go2
-rw-r--r--routers/api/v1/repo/hook_test.go2
-rw-r--r--routers/api/v1/repo/issue.go8
-rw-r--r--routers/api/v1/repo/issue_label.go8
-rw-r--r--routers/api/v1/repo/issue_tracked_time.go7
-rw-r--r--routers/api/v1/repo/migrate.go4
-rw-r--r--routers/api/v1/repo/mirror.go3
-rw-r--r--routers/api/v1/repo/notes.go6
-rw-r--r--routers/api/v1/repo/pull.go4
-rw-r--r--routers/api/v1/repo/pull_review.go8
-rw-r--r--routers/api/v1/repo/release.go3
-rw-r--r--routers/api/v1/repo/repo.go11
-rw-r--r--routers/api/v1/repo/repo_test.go4
-rw-r--r--routers/api/v1/repo/transfer.go19
-rw-r--r--routers/api/v1/repo/wiki.go2
-rw-r--r--routers/api/v1/user/gpg_key.go12
-rw-r--r--routers/api/v1/user/key.go13
-rw-r--r--routers/api/v1/utils/git.go3
-rw-r--r--routers/api/v1/utils/hook.go3
-rw-r--r--routers/common/actions.go71
-rw-r--r--routers/common/blockexpensive.go90
-rw-r--r--routers/common/blockexpensive_test.go30
-rw-r--r--routers/common/db.go4
-rw-r--r--routers/common/markup.go2
-rw-r--r--routers/common/pagetmpl.go75
-rw-r--r--routers/install/install.go33
-rw-r--r--routers/install/routes.go2
-rw-r--r--routers/install/routes_test.go13
-rw-r--r--routers/private/hook_post_receive.go5
-rw-r--r--routers/private/hook_post_receive_test.go2
-rw-r--r--routers/private/hook_pre_receive.go11
-rw-r--r--routers/private/hook_verification.go3
-rw-r--r--routers/private/manager.go2
-rw-r--r--routers/private/serv.go2
-rw-r--r--routers/web/admin/admin_test.go4
-rw-r--r--routers/web/admin/applications.go5
-rw-r--r--routers/web/admin/users.go11
-rw-r--r--routers/web/auth/auth.go5
-rw-r--r--routers/web/auth/auth_test.go40
-rw-r--r--routers/web/auth/oauth.go11
-rw-r--r--routers/web/auth/oauth2_provider.go7
-rw-r--r--routers/web/auth/openid.go8
-rw-r--r--routers/web/auth/password.go5
-rw-r--r--routers/web/base.go4
-rw-r--r--routers/web/devtest/devtest.go201
-rw-r--r--routers/web/devtest/mock_actions.go6
-rw-r--r--routers/web/feed/branch.go3
-rw-r--r--routers/web/feed/file.go3
-rw-r--r--routers/web/githttp.go16
-rw-r--r--routers/web/goget.go2
-rw-r--r--routers/web/nodeinfo.go3
-rw-r--r--routers/web/org/projects.go4
-rw-r--r--routers/web/org/setting.go2
-rw-r--r--routers/web/org/worktime.go7
-rw-r--r--routers/web/repo/actions/actions.go7
-rw-r--r--routers/web/repo/actions/badge.go25
-rw-r--r--routers/web/repo/actions/view.go50
-rw-r--r--routers/web/repo/activity.go19
-rw-r--r--routers/web/repo/cherry_pick.go5
-rw-r--r--routers/web/repo/code_frequency.go2
-rw-r--r--routers/web/repo/commit.go4
-rw-r--r--routers/web/repo/compare.go28
-rw-r--r--routers/web/repo/editor.go9
-rw-r--r--routers/web/repo/editor_test.go2
-rw-r--r--routers/web/repo/githttp.go10
-rw-r--r--routers/web/repo/githttp_test.go2
-rw-r--r--routers/web/repo/issue_content_history.go7
-rw-r--r--routers/web/repo/issue_label_test.go14
-rw-r--r--routers/web/repo/issue_list.go23
-rw-r--r--routers/web/repo/issue_new.go4
-rw-r--r--routers/web/repo/issue_stopwatch.go38
-rw-r--r--routers/web/repo/patch.go5
-rw-r--r--routers/web/repo/projects.go4
-rw-r--r--routers/web/repo/pull.go15
-rw-r--r--routers/web/repo/pull_review.go7
-rw-r--r--routers/web/repo/recent_commits.go15
-rw-r--r--routers/web/repo/repo.go14
-rw-r--r--routers/web/repo/setting/protected_branch.go33
-rw-r--r--routers/web/repo/setting/public_access.go155
-rw-r--r--routers/web/repo/setting/setting.go1500
-rw-r--r--routers/web/repo/setting/settings_test.go22
-rw-r--r--routers/web/repo/view_home.go19
-rw-r--r--routers/web/repo/wiki.go7
-rw-r--r--routers/web/repo/wiki_test.go30
-rw-r--r--routers/web/shared/user/helper.go19
-rw-r--r--routers/web/user/home.go30
-rw-r--r--routers/web/user/home_test.go14
-rw-r--r--routers/web/user/notification.go32
-rw-r--r--routers/web/user/setting/account.go9
-rw-r--r--routers/web/user/setting/account_test.go2
-rw-r--r--routers/web/user/setting/applications.go2
-rw-r--r--routers/web/user/setting/keys.go14
-rw-r--r--routers/web/web.go35
-rw-r--r--routers/web/webfinger.go7
112 files changed, 1888 insertions, 1356 deletions
diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go
index 9d2b69820c..708931d1ac 100644
--- a/routers/api/actions/artifacts_chunks.go
+++ b/routers/api/actions/artifacts_chunks.go
@@ -51,7 +51,7 @@ func saveUploadChunkBase(st storage.ObjectStorage, ctx *ArtifactContext,
log.Info("[artifact] check chunk md5, sum: %s, header: %s", chunkMd5String, reqMd5String)
// if md5 not match, delete the chunk
if reqMd5String != chunkMd5String {
- checkErr = fmt.Errorf("md5 not match")
+ checkErr = errors.New("md5 not match")
}
}
if writtenSize != contentSize {
@@ -261,7 +261,7 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
return fmt.Errorf("save merged file error: %v", err)
}
if written != artifact.FileCompressedSize {
- return fmt.Errorf("merged file size is not equal to chunk length")
+ return errors.New("merged file size is not equal to chunk length")
}
defer func() {
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
index 665156d936..9fb0a31549 100644
--- a/routers/api/actions/artifactsv4.go
+++ b/routers/api/actions/artifactsv4.go
@@ -162,15 +162,15 @@ func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, tas
mac.Write([]byte(endp))
mac.Write([]byte(expires))
mac.Write([]byte(artifactName))
- mac.Write([]byte(fmt.Sprint(taskID)))
- mac.Write([]byte(fmt.Sprint(artifactID)))
+ fmt.Fprint(mac, taskID)
+ fmt.Fprint(mac, artifactID)
return mac.Sum(nil)
}
func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID, artifactID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(r.prefix, "/") +
- "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID, artifactID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) + "&artifactID=" + fmt.Sprint(artifactID)
+ "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID, artifactID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + strconv.FormatInt(taskID, 10) + "&artifactID=" + strconv.FormatInt(artifactID, 10)
return uploadURL
}
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index b64306037f..ae4ea7ea87 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -46,13 +46,14 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
if ok { // it's a personal access token but not oauth2 token
scopeMatched := false
var err error
- if accessMode == perm.AccessModeRead {
+ switch accessMode {
+ case perm.AccessModeRead:
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeReadPackage)
if err != nil {
ctx.HTTPError(http.StatusInternalServerError, "HasScope", err.Error())
return
}
- } else if accessMode == perm.AccessModeWrite {
+ case perm.AccessModeWrite:
scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeWritePackage)
if err != nil {
ctx.HTTPError(http.StatusInternalServerError, "HasScope", err.Error())
@@ -551,10 +552,10 @@ func CommonRoutes() *web.Router {
r.Methods("HEAD,GET,PUT,DELETE", "*", func(ctx *context.Context) {
path := ctx.PathParam("*")
- isHead := ctx.Req.Method == "HEAD"
- isGetHead := ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
- isPut := ctx.Req.Method == "PUT"
- isDelete := ctx.Req.Method == "DELETE"
+ isHead := ctx.Req.Method == http.MethodHead
+ isGetHead := ctx.Req.Method == http.MethodHead || ctx.Req.Method == http.MethodGet
+ isPut := ctx.Req.Method == http.MethodPut
+ isDelete := ctx.Req.Method == http.MethodDelete
m := repoPattern.FindStringSubmatch(path)
if len(m) == 2 && isGetHead {
@@ -703,13 +704,14 @@ func ContainerRoutes() *web.Router {
g.MatchPath("POST", "/<image:*>/blobs/uploads", reqPackageAccess(perm.AccessModeWrite), container.VerifyImageName, container.InitiateUploadBlob)
g.MatchPath("GET", "/<image:*>/tags/list", container.VerifyImageName, container.GetTagList)
g.MatchPath("GET,PATCH,PUT,DELETE", `/<image:*>/blobs/uploads/<uuid:[-.=\w]+>`, reqPackageAccess(perm.AccessModeWrite), container.VerifyImageName, func(ctx *context.Context) {
- if ctx.Req.Method == http.MethodGet {
+ switch ctx.Req.Method {
+ case http.MethodGet:
container.GetUploadBlob(ctx)
- } else if ctx.Req.Method == http.MethodPatch {
+ case http.MethodPatch:
container.UploadBlob(ctx)
- } else if ctx.Req.Method == http.MethodPut {
+ case http.MethodPut:
container.EndUploadBlob(ctx)
- } else /* DELETE */ {
+ default: /* DELETE */
container.CancelUploadBlob(ctx)
}
})
diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go
index 42ef13476c..710c614c6e 100644
--- a/routers/api/packages/cargo/cargo.go
+++ b/routers/api/packages/cargo/cargo.go
@@ -51,7 +51,7 @@ func apiError(ctx *context.Context, status int, obj any) {
// https://rust-lang.github.io/rfcs/2789-sparse-index.html
func RepositoryConfig(ctx *context.Context) {
- ctx.JSON(http.StatusOK, cargo_service.BuildConfig(ctx.Package.Owner, setting.Service.RequireSignInView || ctx.Package.Owner.Visibility != structs.VisibleTypePublic))
+ ctx.JSON(http.StatusOK, cargo_service.BuildConfig(ctx.Package.Owner, setting.Service.RequireSignInViewStrict || ctx.Package.Owner.Visibility != structs.VisibleTypePublic))
}
func EnumeratePackageVersions(ctx *context.Context) {
diff --git a/routers/api/packages/chef/auth.go b/routers/api/packages/chef/auth.go
index a790e9a363..c6808300a2 100644
--- a/routers/api/packages/chef/auth.go
+++ b/routers/api/packages/chef/auth.go
@@ -12,6 +12,7 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
+ "errors"
"fmt"
"hash"
"math/big"
@@ -121,7 +122,7 @@ func verifyTimestamp(req *http.Request) error {
}
if diff > maxTimeDifference {
- return fmt.Errorf("time difference")
+ return errors.New("time difference")
}
return nil
@@ -190,7 +191,7 @@ func getAuthorizationData(req *http.Request) ([]byte, error) {
tmp := make([]string, len(valueList))
for k, v := range valueList {
if k > len(tmp) {
- return nil, fmt.Errorf("invalid X-Ops-Authorization headers")
+ return nil, errors.New("invalid X-Ops-Authorization headers")
}
tmp[k-1] = v
}
@@ -267,7 +268,7 @@ func verifyDataOld(signature, data []byte, pub *rsa.PublicKey) error {
}
if !slices.Equal(out[skip:], data) {
- return fmt.Errorf("could not verify signature")
+ return errors.New("could not verify signature")
}
return nil
diff --git a/routers/api/packages/container/blob.go b/routers/api/packages/container/blob.go
index 671803788a..4a2320ab76 100644
--- a/routers/api/packages/container/blob.go
+++ b/routers/api/packages/container/blob.go
@@ -149,7 +149,7 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
}
func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, pb *packages_model.PackageBlob) error {
- filename := strings.ToLower(fmt.Sprintf("sha256_%s", pb.HashSHA256))
+ filename := strings.ToLower("sha256_" + pb.HashSHA256)
pf := &packages_model.PackageFile{
VersionID: pv.ID,
diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go
index bb14db9db7..6ef1655235 100644
--- a/routers/api/packages/container/container.go
+++ b/routers/api/packages/container/container.go
@@ -126,7 +126,7 @@ func apiUnauthorizedError(ctx *context.Context) {
// ReqContainerAccess is a middleware which checks the current user valid (real user or ghost if anonymous access is enabled)
func ReqContainerAccess(ctx *context.Context) {
- if ctx.Doer == nil || (setting.Service.RequireSignInView && ctx.Doer.IsGhost()) {
+ if ctx.Doer == nil || (setting.Service.RequireSignInViewStrict && ctx.Doer.IsGhost()) {
apiUnauthorizedError(ctx)
}
}
@@ -152,7 +152,7 @@ func Authenticate(ctx *context.Context) {
u := ctx.Doer
packageScope := auth_service.GetAccessScope(ctx.Data)
if u == nil {
- if setting.Service.RequireSignInView {
+ if setting.Service.RequireSignInViewStrict {
apiUnauthorizedError(ctx)
return
}
diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go
index ad035cf473..26faa7b024 100644
--- a/routers/api/packages/container/manifest.go
+++ b/routers/api/packages/container/manifest.go
@@ -406,7 +406,7 @@ func createFileFromBlobReference(ctx context.Context, pv, uploadVersion *package
}
if ref.Name == "" {
- ref.Name = strings.ToLower(fmt.Sprintf("sha256_%s", ref.File.Blob.HashSHA256))
+ ref.Name = strings.ToLower("sha256_" + ref.File.Blob.HashSHA256)
}
pf := &packages_model.PackageFile{
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index 07a8de0a68..fa5067a278 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -488,7 +488,7 @@ func UploadPackage(ctx *context.Context) {
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: strings.ToLower(fmt.Sprintf("%s.nuspec", np.ID)),
+ Filename: strings.ToLower(np.ID + ".nuspec"),
},
Data: nuspecBuf,
},
diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go
index 957d593d89..4eff51782f 100644
--- a/routers/api/v1/activitypub/reqsignature.go
+++ b/routers/api/v1/activitypub/reqsignature.go
@@ -7,6 +7,7 @@ import (
"crypto"
"crypto/x509"
"encoding/pem"
+ "errors"
"fmt"
"io"
"net/http"
@@ -34,7 +35,7 @@ func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err
pubKeyPem := pubKey.PublicKeyPem
block, _ := pem.Decode([]byte(pubKeyPem))
if block == nil || block.Type != "PUBLIC KEY" {
- return nil, fmt.Errorf("could not decode publicKeyPem to PUBLIC KEY pem block type")
+ return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type")
}
p, err = x509.ParsePKIXPublicKey(block.Bytes)
return p, err
diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go
index fb1ea4eab6..a687541be5 100644
--- a/routers/api/v1/admin/hooks.go
+++ b/routers/api/v1/admin/hooks.go
@@ -51,9 +51,10 @@ func ListHooks(ctx *context.APIContext) {
// for compatibility the default value is true
isSystemWebhook := optional.Some(true)
typeValue := ctx.FormString("type")
- if typeValue == "default" {
+ switch typeValue {
+ case "default":
isSystemWebhook = optional.Some(false)
- } else if typeValue == "all" {
+ case "all":
isSystemWebhook = optional.None[bool]()
}
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index c4bb85de55..3ba77604ec 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -296,7 +296,7 @@ func DeleteUser(ctx *context.APIContext) {
// admin should not delete themself
if ctx.ContextUser.ID == ctx.Doer.ID {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("you cannot delete yourself"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("you cannot delete yourself"))
return
}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index bc76b5285e..5cd08a3618 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -307,7 +307,7 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
// use the http method to determine the access level
requiredScopeLevel := auth_model.Read
- if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" {
+ if ctx.Req.Method == http.MethodPost || ctx.Req.Method == http.MethodPut || ctx.Req.Method == http.MethodPatch || ctx.Req.Method == http.MethodDelete {
requiredScopeLevel = auth_model.Write
}
@@ -355,7 +355,7 @@ func reqToken() func(ctx *context.APIContext) {
func reqExploreSignIn() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
- if (setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned {
+ if (setting.Service.RequireSignInViewStrict || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned {
ctx.APIError(http.StatusUnauthorized, "you must be signed in to search for users")
}
}
@@ -842,13 +842,13 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
func individualPermsChecker(ctx *context.APIContext) {
// org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
if ctx.ContextUser.IsIndividual() {
- switch {
- case ctx.ContextUser.Visibility == api.VisibleTypePrivate:
+ switch ctx.ContextUser.Visibility {
+ case api.VisibleTypePrivate:
if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
ctx.APIErrorNotFound("Visit Project", nil)
return
}
- case ctx.ContextUser.Visibility == api.VisibleTypeLimited:
+ case api.VisibleTypeLimited:
if ctx.Doer == nil {
ctx.APIErrorNotFound("Visit Project", nil)
return
@@ -886,7 +886,7 @@ func Routes() *web.Router {
m.Use(apiAuth(buildAuthGroup()))
m.Use(verifyAuthWithOptions(&common.VerifyOptions{
- SignInRequired: setting.Service.RequireSignInView,
+ SignInRequired: setting.Service.RequireSignInViewStrict,
}))
addActionsRoutes := func(
@@ -1168,6 +1168,10 @@ func Routes() *web.Router {
m.Post("/{workflow_id}/dispatches", reqRepoWriter(unit.TypeActions), bind(api.CreateActionWorkflowDispatch{}), repo.ActionsDispatchWorkflow)
}, context.ReferencesGitRepo(), reqToken(), reqRepoReader(unit.TypeActions))
+ m.Group("/actions/jobs", func() {
+ m.Get("/{job_id}/logs", repo.DownloadActionsRunJobLogs)
+ }, reqToken(), reqRepoReader(unit.TypeActions))
+
m.Group("/hooks/git", func() {
m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index 2ace9fa295..ed2017a372 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -1103,8 +1103,8 @@ func DeleteArtifact(ctx *context.APIContext) {
func buildSignature(endp string, expires, artifactID int64) []byte {
mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
mac.Write([]byte(endp))
- mac.Write([]byte(fmt.Sprint(expires)))
- mac.Write([]byte(fmt.Sprint(artifactID)))
+ fmt.Fprint(mac, expires)
+ fmt.Fprint(mac, artifactID)
return mac.Sum(nil)
}
diff --git a/routers/api/v1/repo/actions_run.go b/routers/api/v1/repo/actions_run.go
new file mode 100644
index 0000000000..c6d18af6aa
--- /dev/null
+++ b/routers/api/v1/repo/actions_run.go
@@ -0,0 +1,64 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "errors"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/routers/common"
+ "code.gitea.io/gitea/services/context"
+)
+
+func DownloadActionsRunJobLogs(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs repository downloadActionsRunJobLogs
+ // ---
+ // summary: Downloads the job logs for a workflow run
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: name of the owner
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repository
+ // type: string
+ // required: true
+ // - name: job_id
+ // in: path
+ // description: id of the job
+ // type: integer
+ // required: true
+ // responses:
+ // "200":
+ // description: output blob content
+ // "400":
+ // "$ref": "#/responses/error"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ jobID := ctx.PathParamInt64("job_id")
+ curJob, err := actions_model.GetRunJobByID(ctx, jobID)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
+ if err = curJob.LoadRepo(ctx); err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
+
+ err = common.DownloadActionsRunJobLogs(ctx.Base, ctx.Repo.Repository, curJob)
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.APIErrorNotFound(err)
+ } else {
+ ctx.APIErrorInternal(err)
+ }
+ }
+}
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index 9c6e572fb4..fe82550fdd 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -6,7 +6,6 @@ package repo
import (
"errors"
- "fmt"
"net/http"
"code.gitea.io/gitea/models/db"
@@ -60,17 +59,16 @@ func GetBranch(ctx *context.APIContext) {
branchName := ctx.PathParam("*")
- branch, err := ctx.Repo.GitRepo.GetBranch(branchName)
+ exist, err := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, branchName)
if err != nil {
- if git.IsErrBranchNotExist(err) {
- ctx.APIErrorNotFound(err)
- } else {
- ctx.APIErrorInternal(err)
- }
+ ctx.APIErrorInternal(err)
+ return
+ } else if !exist {
+ ctx.APIErrorNotFound(err)
return
}
- c, err := branch.GetCommit()
+ c, err := ctx.Repo.GitRepo.GetBranchCommit(branchName)
if err != nil {
ctx.APIErrorInternal(err)
return
@@ -82,7 +80,7 @@ func GetBranch(ctx *context.APIContext) {
return
}
- br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branch.Name, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
+ br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branchName, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil {
ctx.APIErrorInternal(err)
return
@@ -157,9 +155,9 @@ func DeleteBranch(ctx *context.APIContext) {
case git.IsErrBranchNotExist(err):
ctx.APIErrorNotFound(err)
case errors.Is(err, repo_service.ErrBranchIsDefault):
- ctx.APIError(http.StatusForbidden, fmt.Errorf("can not delete default branch"))
+ ctx.APIError(http.StatusForbidden, errors.New("can not delete default branch"))
case errors.Is(err, git_model.ErrBranchIsProtected):
- ctx.APIError(http.StatusForbidden, fmt.Errorf("branch protected"))
+ ctx.APIError(http.StatusForbidden, errors.New("branch protected"))
default:
ctx.APIErrorInternal(err)
}
@@ -261,25 +259,19 @@ func CreateBranch(ctx *context.APIContext) {
return
}
- branch, err := ctx.Repo.GitRepo.GetBranch(opt.BranchName)
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
-
- commit, err := branch.GetCommit()
+ commit, err := ctx.Repo.GitRepo.GetBranchCommit(opt.BranchName)
if err != nil {
ctx.APIErrorInternal(err)
return
}
- branchProtection, err := git_model.GetFirstMatchProtectedBranchRule(ctx, ctx.Repo.Repository.ID, branch.Name)
+ branchProtection, err := git_model.GetFirstMatchProtectedBranchRule(ctx, ctx.Repo.Repository.ID, opt.BranchName)
if err != nil {
ctx.APIErrorInternal(err)
return
}
- br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branch.Name, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
+ br, err := convert.ToBranch(ctx, ctx.Repo.Repository, opt.BranchName, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil {
ctx.APIErrorInternal(err)
return
diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go
index 03489d777b..34a81bd7f3 100644
--- a/routers/api/v1/repo/commits.go
+++ b/routers/api/v1/repo/commits.go
@@ -5,7 +5,6 @@
package repo
import (
- "fmt"
"math"
"net/http"
"strconv"
@@ -65,7 +64,7 @@ func GetSingleCommit(ctx *context.APIContext) {
sha := ctx.PathParam("sha")
if !git.IsValidRefPattern(sha) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("no valid ref or sha: %s", sha))
+ ctx.APIError(http.StatusUnprocessableEntity, "no valid ref or sha: "+sha)
return
}
@@ -180,13 +179,7 @@ func GetAllCommits(ctx *context.APIContext) {
var baseCommit *git.Commit
if len(sha) == 0 {
// no sha supplied - use default branch
- head, err := ctx.Repo.GitRepo.GetHEADBranch()
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
-
- baseCommit, err = ctx.Repo.GitRepo.GetBranchCommit(head.Name)
+ baseCommit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
if err != nil {
ctx.APIErrorInternal(err)
return
diff --git a/routers/api/v1/repo/download.go b/routers/api/v1/repo/download.go
index 20901badfb..acd93ecf2e 100644
--- a/routers/api/v1/repo/download.go
+++ b/routers/api/v1/repo/download.go
@@ -4,7 +4,6 @@
package repo
import (
- "fmt"
"net/http"
"code.gitea.io/gitea/modules/git"
@@ -23,7 +22,7 @@ func DownloadArchive(ctx *context.APIContext) {
case "bundle":
tp = git.ArchiveBundle
default:
- ctx.APIError(http.StatusBadRequest, fmt.Sprintf("Unknown archive type: %s", ballType))
+ ctx.APIError(http.StatusBadRequest, "Unknown archive type: "+ballType)
return
}
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 1ba71aa8a3..d8e9fde2c0 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -661,7 +661,7 @@ func UpdateFile(ctx *context.APIContext) {
// "$ref": "#/responses/repoArchivedError"
apiOpts := web.GetForm(ctx).(*api.UpdateFileOptions)
if ctx.Repo.Repository.IsEmpty {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("repo is empty"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("repo is empty"))
return
}
diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go
index 2d15c6e078..f8d61ccf00 100644
--- a/routers/api/v1/repo/hook_test.go
+++ b/routers/api/v1/repo/hook_test.go
@@ -23,7 +23,7 @@ func TestTestHook(t *testing.T) {
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
TestHook(ctx)
- assert.EqualValues(t, http.StatusNoContent, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusNoContent, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &webhook.HookTask{
HookID: 1,
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index c9575ff98a..e678db5262 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -290,10 +290,10 @@ func SearchIssues(ctx *context.APIContext) {
if ctx.IsSigned {
ctxUserID := ctx.Doer.ID
if ctx.FormBool("created") {
- searchOpt.PosterID = optional.Some(ctxUserID)
+ searchOpt.PosterID = strconv.FormatInt(ctxUserID, 10)
}
if ctx.FormBool("assigned") {
- searchOpt.AssigneeID = optional.Some(ctxUserID)
+ searchOpt.AssigneeID = strconv.FormatInt(ctxUserID, 10)
}
if ctx.FormBool("mentioned") {
searchOpt.MentionID = optional.Some(ctxUserID)
@@ -538,10 +538,10 @@ func ListIssues(ctx *context.APIContext) {
}
if createdByID > 0 {
- searchOpt.PosterID = optional.Some(createdByID)
+ searchOpt.PosterID = strconv.FormatInt(createdByID, 10)
}
if assignedByID > 0 {
- searchOpt.AssigneeID = optional.Some(assignedByID)
+ searchOpt.AssigneeID = strconv.FormatInt(assignedByID, 10)
}
if mentionedByID > 0 {
searchOpt.MentionID = optional.Some(mentionedByID)
diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go
index f8e14e0490..d5eee2d469 100644
--- a/routers/api/v1/repo/issue_label.go
+++ b/routers/api/v1/repo/issue_label.go
@@ -5,7 +5,7 @@
package repo
import (
- "fmt"
+ "errors"
"net/http"
"reflect"
@@ -321,7 +321,7 @@ func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption)
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
ctx.APIError(http.StatusForbidden, "write permission is required")
- return nil, nil, fmt.Errorf("permission denied")
+ return nil, nil, errors.New("permission denied")
}
var (
@@ -337,12 +337,12 @@ func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption)
labelNames = append(labelNames, rv.String())
default:
ctx.APIError(http.StatusBadRequest, "a label must be an integer or a string")
- return nil, nil, fmt.Errorf("invalid label")
+ return nil, nil, errors.New("invalid label")
}
}
if len(labelIDs) > 0 && len(labelNames) > 0 {
ctx.APIError(http.StatusBadRequest, "labels should be an array of strings or integers")
- return nil, nil, fmt.Errorf("invalid labels")
+ return nil, nil, errors.New("invalid labels")
}
if len(labelNames) > 0 {
repoLabelIDs, err := issues_model.GetLabelIDsInRepoByNames(ctx, ctx.Repo.Repository.ID, labelNames)
diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go
index dbb2afa920..49531f1824 100644
--- a/routers/api/v1/repo/issue_tracked_time.go
+++ b/routers/api/v1/repo/issue_tracked_time.go
@@ -4,6 +4,7 @@
package repo
import (
+ "errors"
"fmt"
"net/http"
"time"
@@ -116,7 +117,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
if opts.UserID == 0 {
opts.UserID = ctx.Doer.ID
} else {
- ctx.APIError(http.StatusForbidden, fmt.Errorf("query by user not allowed; not enough rights"))
+ ctx.APIError(http.StatusForbidden, errors.New("query by user not allowed; not enough rights"))
return
}
}
@@ -437,7 +438,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) {
}
if !ctx.IsUserRepoAdmin() && !ctx.Doer.IsAdmin && ctx.Doer.ID != user.ID {
- ctx.APIError(http.StatusForbidden, fmt.Errorf("query by user not allowed; not enough rights"))
+ ctx.APIError(http.StatusForbidden, errors.New("query by user not allowed; not enough rights"))
return
}
@@ -545,7 +546,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
if opts.UserID == 0 {
opts.UserID = ctx.Doer.ID
} else {
- ctx.APIError(http.StatusForbidden, fmt.Errorf("query by user not allowed; not enough rights"))
+ ctx.APIError(http.StatusForbidden, errors.New("query by user not allowed; not enough rights"))
return
}
}
diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go
index d7508684a1..87bb269031 100644
--- a/routers/api/v1/repo/migrate.go
+++ b/routers/api/v1/repo/migrate.go
@@ -115,12 +115,12 @@ func Migrate(ctx *context.APIContext) {
gitServiceType := convert.ToGitServiceType(form.Service)
if form.Mirror && setting.Mirror.DisableNewPull {
- ctx.APIError(http.StatusForbidden, fmt.Errorf("the site administrator has disabled the creation of new pull mirrors"))
+ ctx.APIError(http.StatusForbidden, errors.New("the site administrator has disabled the creation of new pull mirrors"))
return
}
if setting.Repository.DisableMigrations {
- ctx.APIError(http.StatusForbidden, fmt.Errorf("the site administrator has disabled migrations"))
+ ctx.APIError(http.StatusForbidden, errors.New("the site administrator has disabled migrations"))
return
}
diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go
index b5f4c12c50..f11a1603c4 100644
--- a/routers/api/v1/repo/mirror.go
+++ b/routers/api/v1/repo/mirror.go
@@ -5,7 +5,6 @@ package repo
import (
"errors"
- "fmt"
"net/http"
"time"
@@ -367,7 +366,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
pushMirror := &repo_model.PushMirror{
RepoID: repo.ID,
Repo: repo,
- RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix),
+ RemoteName: "remote_mirror_" + remoteSuffix,
Interval: interval,
SyncOnCommit: mirrorOption.SyncOnCommit,
RemoteAddress: remoteAddress,
diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go
index dcb512256c..eb048df6fe 100644
--- a/routers/api/v1/repo/notes.go
+++ b/routers/api/v1/repo/notes.go
@@ -4,7 +4,7 @@
package repo
import (
- "fmt"
+ "errors"
"net/http"
"code.gitea.io/gitea/modules/git"
@@ -54,7 +54,7 @@ func GetNote(ctx *context.APIContext) {
sha := ctx.PathParam("sha")
if !git.IsValidRefPattern(sha) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("no valid ref or sha: %s", sha))
+ ctx.APIError(http.StatusUnprocessableEntity, "no valid ref or sha: "+sha)
return
}
getNote(ctx, sha)
@@ -62,7 +62,7 @@ func GetNote(ctx *context.APIContext) {
func getNote(ctx *context.APIContext, identifier string) {
if ctx.Repo.GitRepo == nil {
- ctx.APIErrorInternal(fmt.Errorf("no open git repo"))
+ ctx.APIErrorInternal(errors.New("no open git repo"))
return
}
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index f5d0e37c65..c0b1810191 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -1054,9 +1054,9 @@ func MergePullRequest(ctx *context.APIContext) {
case git.IsErrBranchNotExist(err):
ctx.APIErrorNotFound(err)
case errors.Is(err, repo_service.ErrBranchIsDefault):
- ctx.APIError(http.StatusForbidden, fmt.Errorf("can not delete default branch"))
+ ctx.APIError(http.StatusForbidden, errors.New("can not delete default branch"))
case errors.Is(err, git_model.ErrBranchIsProtected):
- ctx.APIError(http.StatusForbidden, fmt.Errorf("branch protected"))
+ ctx.APIError(http.StatusForbidden, errors.New("branch protected"))
default:
ctx.APIErrorInternal(err)
}
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index fb35126a99..9421a052db 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -439,7 +439,7 @@ func SubmitPullReview(ctx *context.APIContext) {
}
if review.Type != issues_model.ReviewTypePending {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("only a pending review can be submitted"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("only a pending review can be submitted"))
return
}
@@ -451,7 +451,7 @@ func SubmitPullReview(ctx *context.APIContext) {
// if review stay pending return
if reviewType == issues_model.ReviewTypePending {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("review stay pending"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("review stay pending"))
return
}
@@ -496,7 +496,7 @@ func preparePullReviewType(ctx *context.APIContext, pr *issues_model.PullRequest
case api.ReviewStateApproved:
// can not approve your own PR
if pr.Issue.IsPoster(ctx.Doer.ID) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("approve your own pull is not allowed"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("approve your own pull is not allowed"))
return -1, true
}
reviewType = issues_model.ReviewTypeApprove
@@ -505,7 +505,7 @@ func preparePullReviewType(ctx *context.APIContext, pr *issues_model.PullRequest
case api.ReviewStateRequestChanges:
// can not reject your own PR
if pr.Issue.IsPoster(ctx.Doer.ID) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("reject your own pull is not allowed"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("reject your own pull is not allowed"))
return -1, true
}
reviewType = issues_model.ReviewTypeReject
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index 36fff126e1..b6f5a3ac9e 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -4,6 +4,7 @@
package repo
import (
+ "errors"
"fmt"
"net/http"
@@ -220,7 +221,7 @@ func CreateRelease(ctx *context.APIContext) {
form := web.GetForm(ctx).(*api.CreateReleaseOption)
if ctx.Repo.Repository.IsEmpty {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("repo is empty"))
+ ctx.APIError(http.StatusUnprocessableEntity, errors.New("repo is empty"))
return
}
rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName)
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 3d638cb05e..7caf004b4a 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -5,6 +5,7 @@
package repo
import (
+ "errors"
"fmt"
"net/http"
"slices"
@@ -711,7 +712,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
visibilityChanged = repo.IsPrivate != *opts.Private
// when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
if visibilityChanged && setting.Repository.ForcePrivate && !*opts.Private && !ctx.Doer.IsAdmin {
- err := fmt.Errorf("cannot change private repository to public")
+ err := errors.New("cannot change private repository to public")
ctx.APIError(http.StatusUnprocessableEntity, err)
return err
}
@@ -780,12 +781,12 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
if newHasIssues && opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
// Check that values are valid
if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
- err := fmt.Errorf("External tracker URL not valid")
+ err := errors.New("External tracker URL not valid")
ctx.APIError(http.StatusUnprocessableEntity, err)
return err
}
if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
- err := fmt.Errorf("External tracker URL format not valid")
+ err := errors.New("External tracker URL format not valid")
ctx.APIError(http.StatusUnprocessableEntity, err)
return err
}
@@ -847,7 +848,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
if newHasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
// Check that values are valid
if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
- err := fmt.Errorf("External wiki URL not valid")
+ err := errors.New("External wiki URL not valid")
ctx.APIError(http.StatusUnprocessableEntity, "Invalid external wiki URL")
return err
}
@@ -1038,7 +1039,7 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
// archive / un-archive
if opts.Archived != nil {
if repo.IsMirror {
- err := fmt.Errorf("repo is a mirror, cannot archive/un-archive")
+ err := errors.New("repo is a mirror, cannot archive/un-archive")
ctx.APIError(http.StatusUnprocessableEntity, err)
return err
}
diff --git a/routers/api/v1/repo/repo_test.go b/routers/api/v1/repo/repo_test.go
index 0a63b16a99..97233f85dc 100644
--- a/routers/api/v1/repo/repo_test.go
+++ b/routers/api/v1/repo/repo_test.go
@@ -58,7 +58,7 @@ func TestRepoEdit(t *testing.T) {
web.SetForm(ctx, &opts)
Edit(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{
ID: 1,
}, unittest.Cond("name = ? AND is_archived = 1", *opts.Name))
@@ -78,7 +78,7 @@ func TestRepoEditNameChange(t *testing.T) {
web.SetForm(ctx, &opts)
Edit(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{
ID: 1,
diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go
index 7b890c9e5c..cbf3d10c39 100644
--- a/routers/api/v1/repo/transfer.go
+++ b/routers/api/v1/repo/transfer.go
@@ -108,19 +108,16 @@ func Transfer(ctx *context.APIContext) {
oldFullname := ctx.Repo.Repository.FullName()
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil {
- if repo_model.IsErrRepoTransferInProgress(err) {
+ switch {
+ case repo_model.IsErrRepoTransferInProgress(err):
ctx.APIError(http.StatusConflict, err)
- return
- }
-
- if repo_model.IsErrRepoAlreadyExist(err) {
+ case repo_model.IsErrRepoAlreadyExist(err):
ctx.APIError(http.StatusUnprocessableEntity, err)
- return
- }
-
- if errors.Is(err, user_model.ErrBlockedUser) {
+ case repo_service.IsRepositoryLimitReached(err):
+ ctx.APIError(http.StatusForbidden, err)
+ case errors.Is(err, user_model.ErrBlockedUser):
ctx.APIError(http.StatusForbidden, err)
- } else {
+ default:
ctx.APIErrorInternal(err)
}
return
@@ -169,6 +166,8 @@ func AcceptTransfer(ctx *context.APIContext) {
ctx.APIError(http.StatusNotFound, err)
case errors.Is(err, util.ErrPermissionDenied):
ctx.APIError(http.StatusForbidden, err)
+ case repo_service.IsRepositoryLimitReached(err):
+ ctx.APIError(http.StatusForbidden, err)
default:
ctx.APIErrorInternal(err)
}
diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go
index 8d73383f76..67dd6c913d 100644
--- a/routers/api/v1/repo/wiki.go
+++ b/routers/api/v1/repo/wiki.go
@@ -476,7 +476,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
// findWikiRepoCommit opens the wiki repo and returns the latest commit, writing to context on error.
// The caller is responsible for closing the returned repo again
func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit) {
- wikiRepo, err := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ wikiRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository.WikiStorageRepo())
if err != nil {
if git.IsErrNotExist(err) || err.Error() == "no such file or directory" {
ctx.APIErrorNotFound(err)
diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go
index 504e74ae10..b76bd8a1ee 100644
--- a/routers/api/v1/user/gpg_key.go
+++ b/routers/api/v1/user/gpg_key.go
@@ -4,7 +4,7 @@
package user
import (
- "fmt"
+ "errors"
"net/http"
"strings"
@@ -135,7 +135,7 @@ func GetGPGKey(ctx *context.APIContext) {
// CreateUserGPGKey creates new GPG key to given user by ID.
func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.APIErrorNotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.APIErrorNotFound("Not Found", errors.New("gpg keys setting is not allowed to be visited"))
return
}
@@ -205,7 +205,7 @@ func VerifyUserGPGKey(ctx *context.APIContext) {
if err != nil {
if asymkey_model.IsErrGPGInvalidTokenSignature(err) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
+ ctx.APIError(http.StatusUnprocessableEntity, "The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: "+token)
return
}
ctx.APIErrorInternal(err)
@@ -276,7 +276,7 @@ func DeleteGPGKey(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.APIErrorNotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.APIErrorNotFound("Not Found", errors.New("gpg keys setting is not allowed to be visited"))
return
}
@@ -302,9 +302,9 @@ func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) {
case asymkey_model.IsErrGPGKeyParsing(err):
ctx.APIError(http.StatusUnprocessableEntity, err)
case asymkey_model.IsErrGPGNoEmailFound(err):
- ctx.APIError(http.StatusNotFound, fmt.Sprintf("None of the emails attached to the GPG key could be found. It may still be added if you provide a valid signature for the token: %s", token))
+ ctx.APIError(http.StatusNotFound, "None of the emails attached to the GPG key could be found. It may still be added if you provide a valid signature for the token: "+token)
case asymkey_model.IsErrGPGInvalidTokenSignature(err):
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
+ ctx.APIError(http.StatusUnprocessableEntity, "The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: "+token)
default:
ctx.APIErrorInternal(err)
}
diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go
index 6295f4753b..628f5d6cac 100644
--- a/routers/api/v1/user/key.go
+++ b/routers/api/v1/user/key.go
@@ -5,7 +5,7 @@ package user
import (
std_ctx "context"
- "fmt"
+ "errors"
"net/http"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -24,9 +24,10 @@ import (
// appendPrivateInformation appends the owner and key type information to api.PublicKey
func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) {
- if key.Type == asymkey_model.KeyTypeDeploy {
+ switch key.Type {
+ case asymkey_model.KeyTypeDeploy:
apiKey.KeyType = "deploy"
- } else if key.Type == asymkey_model.KeyTypeUser {
+ case asymkey_model.KeyTypeUser:
apiKey.KeyType = "user"
if defaultUser.ID == key.OwnerID {
@@ -38,7 +39,7 @@ func appendPrivateInformation(ctx std_ctx.Context, apiKey *api.PublicKey, key *a
}
apiKey.Owner = convert.ToUser(ctx, user, user)
}
- } else {
+ default:
apiKey.KeyType = "unknown"
}
apiKey.ReadOnly = key.Mode == perm.AccessModeRead
@@ -200,7 +201,7 @@ func GetPublicKey(ctx *context.APIContext) {
// CreateUserPublicKey creates new public key to given user by ID.
func CreateUserPublicKey(ctx *context.APIContext, form api.CreateKeyOption, uid int64) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.APIErrorNotFound("Not Found", fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.APIErrorNotFound("Not Found", errors.New("ssh keys setting is not allowed to be visited"))
return
}
@@ -270,7 +271,7 @@ func DeletePublicKey(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.APIErrorNotFound("Not Found", fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.APIErrorNotFound("Not Found", errors.New("ssh keys setting is not allowed to be visited"))
return
}
diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go
index af672ba147..7d276d9d98 100644
--- a/routers/api/v1/utils/git.go
+++ b/routers/api/v1/utils/git.go
@@ -5,6 +5,7 @@ package utils
import (
gocontext "context"
+ "errors"
"fmt"
"net/http"
@@ -50,7 +51,7 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string {
// GetGitRefs return git references based on filter
func GetGitRefs(ctx *context.APIContext, filter string) ([]*git.Reference, string, error) {
if ctx.Repo.GitRepo == nil {
- return nil, "", fmt.Errorf("no open git repo found in context")
+ return nil, "", errors.New("no open git repo found in context")
}
if len(filter) > 0 {
filter = "refs/" + filter
diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index ce0c1b5097..532d157e35 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -4,7 +4,6 @@
package utils
import (
- "fmt"
"net/http"
"strconv"
"strings"
@@ -80,7 +79,7 @@ func GetRepoHook(ctx *context.APIContext, repoID, hookID int64) (*webhook.Webhoo
// write the appropriate error to `ctx`. Return whether the form is valid
func checkCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) bool {
if !webhook_service.IsValidHookTaskType(form.Type) {
- ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid hook type: %s", form.Type))
+ ctx.APIError(http.StatusUnprocessableEntity, "Invalid hook type: "+form.Type)
return false
}
for _, name := range []string{"url", "content_type"} {
diff --git a/routers/common/actions.go b/routers/common/actions.go
new file mode 100644
index 0000000000..a4eabb6ba2
--- /dev/null
+++ b/routers/common/actions.go
@@ -0,0 +1,71 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ "fmt"
+ "strings"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/actions"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/services/context"
+)
+
+func DownloadActionsRunJobLogsWithIndex(ctx *context.Base, ctxRepo *repo_model.Repository, runID, jobIndex int64) error {
+ runJobs, err := actions_model.GetRunJobsByRunID(ctx, runID)
+ if err != nil {
+ return fmt.Errorf("GetRunJobsByRunID: %w", err)
+ }
+ if err = runJobs.LoadRepos(ctx); err != nil {
+ return fmt.Errorf("LoadRepos: %w", err)
+ }
+ if jobIndex < 0 || jobIndex >= int64(len(runJobs)) {
+ return util.NewNotExistErrorf("job index is out of range: %d", jobIndex)
+ }
+ return DownloadActionsRunJobLogs(ctx, ctxRepo, runJobs[jobIndex])
+}
+
+func DownloadActionsRunJobLogs(ctx *context.Base, ctxRepo *repo_model.Repository, curJob *actions_model.ActionRunJob) error {
+ if curJob.Repo.ID != ctxRepo.ID {
+ return util.NewNotExistErrorf("job not found")
+ }
+
+ if curJob.TaskID == 0 {
+ return util.NewNotExistErrorf("job not started")
+ }
+
+ if err := curJob.LoadRun(ctx); err != nil {
+ return fmt.Errorf("LoadRun: %w", err)
+ }
+
+ task, err := actions_model.GetTaskByID(ctx, curJob.TaskID)
+ if err != nil {
+ return fmt.Errorf("GetTaskByID: %w", err)
+ }
+
+ if task.LogExpired {
+ return util.NewNotExistErrorf("logs have been cleaned up")
+ }
+
+ reader, err := actions.OpenLogs(ctx, task.LogInStorage, task.LogFilename)
+ if err != nil {
+ return fmt.Errorf("OpenLogs: %w", err)
+ }
+ defer reader.Close()
+
+ workflowName := curJob.Run.WorkflowID
+ if p := strings.Index(workflowName, "."); p > 0 {
+ workflowName = workflowName[0:p]
+ }
+ ctx.ServeContent(reader, &context.ServeHeaderOptions{
+ Filename: fmt.Sprintf("%v-%v-%v.log", workflowName, curJob.Name, task.ID),
+ ContentLength: &task.LogSize,
+ ContentType: "text/plain",
+ ContentTypeCharset: "utf-8",
+ Disposition: "attachment",
+ })
+ return nil
+}
diff --git a/routers/common/blockexpensive.go b/routers/common/blockexpensive.go
new file mode 100644
index 0000000000..f52aa2b709
--- /dev/null
+++ b/routers/common/blockexpensive.go
@@ -0,0 +1,90 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ "net/http"
+ "strings"
+
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/reqctx"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/web/middleware"
+
+ "github.com/go-chi/chi/v5"
+)
+
+func BlockExpensive() func(next http.Handler) http.Handler {
+ if !setting.Service.BlockAnonymousAccessExpensive {
+ return nil
+ }
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ ret := determineRequestPriority(reqctx.FromContext(req.Context()))
+ if !ret.SignedIn {
+ if ret.Expensive || ret.LongPolling {
+ http.Redirect(w, req, setting.AppSubURL+"/user/login", http.StatusSeeOther)
+ return
+ }
+ }
+ next.ServeHTTP(w, req)
+ })
+ }
+}
+
+func isRoutePathExpensive(routePattern string) bool {
+ if strings.HasPrefix(routePattern, "/user/") || strings.HasPrefix(routePattern, "/login/") {
+ return false
+ }
+
+ expensivePaths := []string{
+ // code related
+ "/{username}/{reponame}/archive/",
+ "/{username}/{reponame}/blame/",
+ "/{username}/{reponame}/commit/",
+ "/{username}/{reponame}/commits/",
+ "/{username}/{reponame}/graph",
+ "/{username}/{reponame}/media/",
+ "/{username}/{reponame}/raw/",
+ "/{username}/{reponame}/src/",
+
+ // issue & PR related (no trailing slash)
+ "/{username}/{reponame}/issues",
+ "/{username}/{reponame}/{type:issues}",
+ "/{username}/{reponame}/pulls",
+ "/{username}/{reponame}/{type:pulls}",
+
+ // wiki
+ "/{username}/{reponame}/wiki/",
+
+ // activity
+ "/{username}/{reponame}/activity/",
+ }
+ for _, path := range expensivePaths {
+ if strings.HasPrefix(routePattern, path) {
+ return true
+ }
+ }
+ return false
+}
+
+func isRoutePathForLongPolling(routePattern string) bool {
+ return routePattern == "/user/events"
+}
+
+func determineRequestPriority(reqCtx reqctx.RequestContext) (ret struct {
+ SignedIn bool
+ Expensive bool
+ LongPolling bool
+},
+) {
+ chiRoutePath := chi.RouteContext(reqCtx).RoutePattern()
+ if _, ok := reqCtx.GetData()[middleware.ContextDataKeySignedUser].(*user_model.User); ok {
+ ret.SignedIn = true
+ } else {
+ ret.Expensive = isRoutePathExpensive(chiRoutePath)
+ ret.LongPolling = isRoutePathForLongPolling(chiRoutePath)
+ }
+ return ret
+}
diff --git a/routers/common/blockexpensive_test.go b/routers/common/blockexpensive_test.go
new file mode 100644
index 0000000000..db5c0db7dd
--- /dev/null
+++ b/routers/common/blockexpensive_test.go
@@ -0,0 +1,30 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBlockExpensive(t *testing.T) {
+ cases := []struct {
+ expensive bool
+ routePath string
+ }{
+ {false, "/user/xxx"},
+ {false, "/login/xxx"},
+ {true, "/{username}/{reponame}/archive/xxx"},
+ {true, "/{username}/{reponame}/graph"},
+ {true, "/{username}/{reponame}/src/xxx"},
+ {true, "/{username}/{reponame}/wiki/xxx"},
+ {true, "/{username}/{reponame}/activity/xxx"},
+ }
+ for _, c := range cases {
+ assert.Equal(t, c.expensive, isRoutePathExpensive(c.routePath), "routePath: %s", c.routePath)
+ }
+
+ assert.True(t, isRoutePathForLongPolling("/user/events"))
+}
diff --git a/routers/common/db.go b/routers/common/db.go
index cb163c867d..01c0261427 100644
--- a/routers/common/db.go
+++ b/routers/common/db.go
@@ -5,7 +5,7 @@ package common
import (
"context"
- "fmt"
+ "errors"
"time"
"code.gitea.io/gitea/models/db"
@@ -25,7 +25,7 @@ func InitDBEngine(ctx context.Context) (err error) {
for i := 0; i < setting.Database.DBConnectRetries; i++ {
select {
case <-ctx.Done():
- return fmt.Errorf("Aborted due to shutdown:\nin retry ORM engine initialization")
+ return errors.New("Aborted due to shutdown:\nin retry ORM engine initialization")
default:
}
log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries)
diff --git a/routers/common/markup.go b/routers/common/markup.go
index 60bf0dba54..4c77ff33ed 100644
--- a/routers/common/markup.go
+++ b/routers/common/markup.go
@@ -88,7 +88,7 @@ func RenderMarkup(ctx *context.Base, ctxRepo *context.Repository, mode, text, ur
})
rctx = rctx.WithMarkupType("").WithRelativePath(filePath) // render the repo file content by its extension
default:
- ctx.HTTPError(http.StatusUnprocessableEntity, fmt.Sprintf("Unknown mode: %s", mode))
+ ctx.HTTPError(http.StatusUnprocessableEntity, "Unknown mode: "+mode)
return
}
rctx = rctx.WithUseAbsoluteLink(true)
diff --git a/routers/common/pagetmpl.go b/routers/common/pagetmpl.go
new file mode 100644
index 0000000000..52c9fceba3
--- /dev/null
+++ b/routers/common/pagetmpl.go
@@ -0,0 +1,75 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ goctx "context"
+ "errors"
+
+ activities_model "code.gitea.io/gitea/models/activities"
+ "code.gitea.io/gitea/models/db"
+ issues_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/services/context"
+)
+
+// StopwatchTmplInfo is a view on a stopwatch specifically for template rendering
+type StopwatchTmplInfo struct {
+ IssueLink string
+ RepoSlug string
+ IssueIndex int64
+ Seconds int64
+}
+
+func getActiveStopwatch(goCtx goctx.Context) *StopwatchTmplInfo {
+ ctx := context.GetWebContext(goCtx)
+ if ctx.Doer == nil {
+ return nil
+ }
+
+ _, sw, issue, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
+ if err != nil {
+ if !errors.Is(err, goctx.Canceled) {
+ log.Error("Unable to HasUserStopwatch for user:%-v: %v", ctx.Doer, err)
+ }
+ return nil
+ }
+
+ if sw == nil || sw.ID == 0 {
+ return nil
+ }
+
+ return &StopwatchTmplInfo{
+ issue.Link(),
+ issue.Repo.FullName(),
+ issue.Index,
+ sw.Seconds() + 1, // ensure time is never zero in ui
+ }
+}
+
+func notificationUnreadCount(goCtx goctx.Context) int64 {
+ ctx := context.GetWebContext(goCtx)
+ if ctx.Doer == nil {
+ return 0
+ }
+ count, err := db.Count[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
+ UserID: ctx.Doer.ID,
+ Status: []activities_model.NotificationStatus{activities_model.NotificationStatusUnread},
+ })
+ if err != nil {
+ if !errors.Is(err, goctx.Canceled) {
+ log.Error("Unable to find notification for user:%-v: %v", ctx.Doer, err)
+ }
+ return 0
+ }
+ return count
+}
+
+func PageTmplFunctions(ctx *context.Context) {
+ if ctx.IsSigned {
+ // defer the function call to the last moment when the tmpl renders
+ ctx.Data["NotificationUnreadCount"] = notificationUnreadCount
+ ctx.Data["GetActiveStopwatch"] = getActiveStopwatch
+ }
+}
diff --git a/routers/install/install.go b/routers/install/install.go
index b81a5680d3..2962f3948f 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -5,7 +5,6 @@
package install
import (
- "fmt"
"net/http"
"net/mail"
"os"
@@ -151,7 +150,7 @@ func Install(ctx *context.Context) {
form.DisableRegistration = setting.Service.DisableRegistration
form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration
form.EnableCaptcha = setting.Service.EnableCaptcha
- form.RequireSignInView = setting.Service.RequireSignInView
+ form.RequireSignInView = setting.Service.RequireSignInViewStrict
form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
form.DefaultAllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking
@@ -398,7 +397,7 @@ func SubmitInstall(ctx *context.Context) {
cfg.Section("server").Key("DISABLE_SSH").SetValue("true")
} else {
cfg.Section("server").Key("DISABLE_SSH").SetValue("false")
- cfg.Section("server").Key("SSH_PORT").SetValue(fmt.Sprint(form.SSHPort))
+ cfg.Section("server").Key("SSH_PORT").SetValue(strconv.Itoa(form.SSHPort))
}
if form.LFSRootPath != "" {
@@ -429,10 +428,10 @@ func SubmitInstall(ctx *context.Context) {
} else {
cfg.Section("mailer").Key("ENABLED").SetValue("false")
}
- cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(fmt.Sprint(form.RegisterConfirm))
- cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(fmt.Sprint(form.MailNotify))
+ cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(strconv.FormatBool(form.RegisterConfirm))
+ cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(strconv.FormatBool(form.MailNotify))
- cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode))
+ cfg.Section("server").Key("OFFLINE_MODE").SetValue(strconv.FormatBool(form.OfflineMode))
if err := system_model.SetSettings(ctx, map[string]string{
setting.Config().Picture.DisableGravatar.DynKey(): strconv.FormatBool(form.DisableGravatar),
setting.Config().Picture.EnableFederatedAvatar.DynKey(): strconv.FormatBool(form.EnableFederatedAvatar),
@@ -441,17 +440,17 @@ func SubmitInstall(ctx *context.Context) {
return
}
- cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(fmt.Sprint(form.EnableOpenIDSignIn))
- cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(fmt.Sprint(form.EnableOpenIDSignUp))
- cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(fmt.Sprint(form.DisableRegistration))
- cfg.Section("service").Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").SetValue(fmt.Sprint(form.AllowOnlyExternalRegistration))
- cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(fmt.Sprint(form.EnableCaptcha))
- cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(fmt.Sprint(form.RequireSignInView))
- cfg.Section("service").Key("DEFAULT_KEEP_EMAIL_PRIVATE").SetValue(fmt.Sprint(form.DefaultKeepEmailPrivate))
- cfg.Section("service").Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").SetValue(fmt.Sprint(form.DefaultAllowCreateOrganization))
- cfg.Section("service").Key("DEFAULT_ENABLE_TIMETRACKING").SetValue(fmt.Sprint(form.DefaultEnableTimetracking))
- cfg.Section("service").Key("NO_REPLY_ADDRESS").SetValue(fmt.Sprint(form.NoReplyAddress))
- cfg.Section("cron.update_checker").Key("ENABLED").SetValue(fmt.Sprint(form.EnableUpdateChecker))
+ cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(strconv.FormatBool(form.EnableOpenIDSignIn))
+ cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(strconv.FormatBool(form.EnableOpenIDSignUp))
+ cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(strconv.FormatBool(form.DisableRegistration))
+ cfg.Section("service").Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").SetValue(strconv.FormatBool(form.AllowOnlyExternalRegistration))
+ cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(strconv.FormatBool(form.EnableCaptcha))
+ cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(strconv.FormatBool(form.RequireSignInView))
+ cfg.Section("service").Key("DEFAULT_KEEP_EMAIL_PRIVATE").SetValue(strconv.FormatBool(form.DefaultKeepEmailPrivate))
+ cfg.Section("service").Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").SetValue(strconv.FormatBool(form.DefaultAllowCreateOrganization))
+ cfg.Section("service").Key("DEFAULT_ENABLE_TIMETRACKING").SetValue(strconv.FormatBool(form.DefaultEnableTimetracking))
+ cfg.Section("service").Key("NO_REPLY_ADDRESS").SetValue(form.NoReplyAddress)
+ cfg.Section("cron.update_checker").Key("ENABLED").SetValue(strconv.FormatBool(form.EnableUpdateChecker))
cfg.Section("session").Key("PROVIDER").SetValue("file")
diff --git a/routers/install/routes.go b/routers/install/routes.go
index 7309a405d4..bc7a0eb48c 100644
--- a/routers/install/routes.go
+++ b/routers/install/routes.go
@@ -36,7 +36,7 @@ func Routes() *web.Router {
func installNotFound(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Content-Type", "text/html; charset=utf-8")
- w.Header().Add("Refresh", fmt.Sprintf("1; url=%s", setting.AppSubURL+"/"))
+ w.Header().Add("Refresh", "1; url="+setting.AppSubURL+"/")
// do not use 30x status, because the "post-install" page needs to use 404/200 to detect if Gitea has been installed.
// the fetch API could follow 30x requests to the page with 200 status.
w.WriteHeader(http.StatusNotFound)
diff --git a/routers/install/routes_test.go b/routers/install/routes_test.go
index 2aa7f5d7b7..e8902ba3f1 100644
--- a/routers/install/routes_test.go
+++ b/routers/install/routes_test.go
@@ -4,6 +4,7 @@
package install
import (
+ "net/http"
"net/http/httptest"
"testing"
@@ -17,20 +18,20 @@ func TestRoutes(t *testing.T) {
assert.NotNil(t, r)
w := httptest.NewRecorder()
- req := httptest.NewRequest("GET", "/", nil)
+ req := httptest.NewRequest(http.MethodGet, "/", nil)
r.ServeHTTP(w, req)
- assert.EqualValues(t, 200, w.Code)
+ assert.Equal(t, 200, w.Code)
assert.Contains(t, w.Body.String(), `class="page-content install"`)
w = httptest.NewRecorder()
- req = httptest.NewRequest("GET", "/no-such", nil)
+ req = httptest.NewRequest(http.MethodGet, "/no-such", nil)
r.ServeHTTP(w, req)
- assert.EqualValues(t, 404, w.Code)
+ assert.Equal(t, 404, w.Code)
w = httptest.NewRecorder()
- req = httptest.NewRequest("GET", "/assets/img/gitea.svg", nil)
+ req = httptest.NewRequest(http.MethodGet, "/assets/img/gitea.svg", nil)
r.ServeHTTP(w, req)
- assert.EqualValues(t, 200, w.Code)
+ assert.Equal(t, 200, w.Code)
}
func TestMain(m *testing.M) {
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index dba6aef9a3..442d0a76c9 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -303,14 +303,11 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
if pr == nil {
- if repo.IsFork {
- branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
- }
results = append(results, private.HookPostReceiveBranchResult{
Message: setting.Git.PullRequestPushMessage && baseRepo.AllowsPulls(ctx),
Create: true,
Branch: branch,
- URL: fmt.Sprintf("%s/compare/%s...%s", baseRepo.HTMLURL(), util.PathEscapeSegments(baseRepo.DefaultBranch), util.PathEscapeSegments(branch)),
+ URL: fmt.Sprintf("%s/pulls/new/%s", repo.HTMLURL(), util.PathEscapeSegments(branch)),
})
} else {
results = append(results, private.HookPostReceiveBranchResult{
diff --git a/routers/private/hook_post_receive_test.go b/routers/private/hook_post_receive_test.go
index 34722f910d..ca721b16d1 100644
--- a/routers/private/hook_post_receive_test.go
+++ b/routers/private/hook_post_receive_test.go
@@ -43,7 +43,7 @@ func TestHandlePullRequestMerging(t *testing.T) {
pr, err = issues_model.GetPullRequestByID(db.DefaultContext, pr.ID)
assert.NoError(t, err)
assert.True(t, pr.HasMerged)
- assert.EqualValues(t, "01234567", pr.MergedCommitID)
+ assert.Equal(t, "01234567", pr.MergedCommitID)
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{ID: autoMerge.ID})
}
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index ae23abc542..be9923c98f 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -311,13 +311,13 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
if isForcePush {
log.Warn("Forbidden: User %d is not allowed to force-push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- UserMsg: fmt.Sprintf("Not allowed to force-push to protected branch %s", branchName),
+ UserMsg: "Not allowed to force-push to protected branch " + branchName,
})
return
}
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", ctx.opts.UserID, branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
- UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
+ UserMsg: "Not allowed to push to protected branch " + branchName,
})
return
}
@@ -353,7 +353,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
if !allowedMerge {
log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v and is not allowed to merge pr #%d", ctx.opts.UserID, branchName, repo, pr.Index)
ctx.JSON(http.StatusForbidden, private.Response{
- UserMsg: fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
+ UserMsg: "Not allowed to push to protected branch " + branchName,
})
return
}
@@ -447,10 +447,7 @@ func preReceiveFor(ctx *preReceiveContext, refFullName git.RefName) {
baseBranchName := refFullName.ForBranchName()
- baseBranchExist := false
- if gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, baseBranchName) {
- baseBranchExist = true
- }
+ baseBranchExist := gitrepo.IsBranchExist(ctx, ctx.Repo.Repository, baseBranchName)
if !baseBranchExist {
for p, v := range baseBranchName {
diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go
index 7c06cf8557..57d0964ead 100644
--- a/routers/private/hook_verification.go
+++ b/routers/private/hook_verification.go
@@ -6,7 +6,6 @@ package private
import (
"bufio"
"context"
- "fmt"
"io"
"os"
@@ -113,7 +112,7 @@ type errUnverifiedCommit struct {
}
func (e *errUnverifiedCommit) Error() string {
- return fmt.Sprintf("Unverified commit: %s", e.sha)
+ return "Unverified commit: " + e.sha
}
func isErrUnverifiedCommit(err error) bool {
diff --git a/routers/private/manager.go b/routers/private/manager.go
index c712bbcf21..00e52d6511 100644
--- a/routers/private/manager.go
+++ b/routers/private/manager.go
@@ -180,7 +180,7 @@ func AddLogger(ctx *context.PrivateContext) {
writerOption.Addr, _ = opts.Config["address"].(string)
writerMode.WriterOption = writerOption
default:
- panic(fmt.Sprintf("invalid log writer mode: %s", writerType))
+ panic("invalid log writer mode: " + writerType)
}
writer, err := log.NewEventWriter(opts.Writer, writerType, writerMode)
if err != nil {
diff --git a/routers/private/serv.go b/routers/private/serv.go
index ecff3b7a53..37fbc0730c 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -286,7 +286,7 @@ func ServCommand(ctx *context.PrivateContext) {
repo.IsPrivate ||
owner.Visibility.IsPrivate() ||
(user != nil && user.IsRestricted) || // user will be nil if the key is a deploykey
- setting.Service.RequireSignInView) {
+ setting.Service.RequireSignInViewStrict) {
if key.Type == asymkey_model.KeyTypeDeploy {
if deployKey.Mode < mode {
ctx.JSON(http.StatusUnauthorized, private.Response{
diff --git a/routers/web/admin/admin_test.go b/routers/web/admin/admin_test.go
index 6c38f0b509..a568c7c5c8 100644
--- a/routers/web/admin/admin_test.go
+++ b/routers/web/admin/admin_test.go
@@ -69,7 +69,7 @@ func TestShadowPassword(t *testing.T) {
}
for _, k := range kases {
- assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem))
+ assert.Equal(t, k.Result, shadowPassword(k.Provider, k.CfgItem))
}
}
@@ -79,7 +79,7 @@ func TestSelfCheckPost(t *testing.T) {
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
SelfCheckPost(ctx)
- assert.EqualValues(t, http.StatusOK, resp.Code)
+ assert.Equal(t, http.StatusOK, resp.Code)
data := struct {
Problems []string `json:"problems"`
diff --git a/routers/web/admin/applications.go b/routers/web/admin/applications.go
index aec6349f21..79c3a08808 100644
--- a/routers/web/admin/applications.go
+++ b/routers/web/admin/applications.go
@@ -4,7 +4,6 @@
package admin
import (
- "fmt"
"net/http"
"code.gitea.io/gitea/models/auth"
@@ -23,8 +22,8 @@ var (
func newOAuth2CommonHandlers() *user_setting.OAuth2CommonHandlers {
return &user_setting.OAuth2CommonHandlers{
OwnerID: 0,
- BasePathList: fmt.Sprintf("%s/-/admin/applications", setting.AppSubURL),
- BasePathEditPrefix: fmt.Sprintf("%s/-/admin/applications/oauth2", setting.AppSubURL),
+ BasePathList: setting.AppSubURL + "/-/admin/applications",
+ BasePathEditPrefix: setting.AppSubURL + "/-/admin/applications/oauth2",
TplAppEdit: tplSettingsOauth2ApplicationEdit,
}
}
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index f6a3af1c86..e42cbb316c 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/explore"
user_setting "code.gitea.io/gitea/routers/web/user/setting"
@@ -72,11 +71,11 @@ func Users(ctx *context.Context) {
PageSize: setting.UI.Admin.UserPagingNum,
},
SearchByEmail: true,
- IsActive: util.OptionalBoolParse(statusFilterMap["is_active"]),
- IsAdmin: util.OptionalBoolParse(statusFilterMap["is_admin"]),
- IsRestricted: util.OptionalBoolParse(statusFilterMap["is_restricted"]),
- IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]),
- IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]),
+ IsActive: optional.ParseBool(statusFilterMap["is_active"]),
+ IsAdmin: optional.ParseBool(statusFilterMap["is_admin"]),
+ IsRestricted: optional.ParseBool(statusFilterMap["is_restricted"]),
+ IsTwoFactorEnabled: optional.ParseBool(statusFilterMap["is_2fa_enabled"]),
+ IsProhibitLogin: optional.ParseBool(statusFilterMap["is_prohibit_login"]),
IncludeReserved: true, // administrator needs to list all accounts include reserved, bot, remote ones
}, tplUsers)
}
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index f07ef98931..1de8d7e8a3 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -534,7 +534,8 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any,
}
if err := user_model.CreateUser(ctx, u, meta, overwrites); err != nil {
if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
- if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
+ switch setting.OAuth2Client.AccountLinking {
+ case setting.OAuth2AccountLinkingAuto:
var user *user_model.User
user = &user_model.User{Name: u.Name}
hasUser, err := user_model.GetUser(ctx, user)
@@ -550,7 +551,7 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any,
// TODO: probably we should respect 'remember' user's choice...
linkAccount(ctx, user, *gothUser, true)
return false // user is already created here, all redirects are handled
- } else if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingLogin {
+ case setting.OAuth2AccountLinkingLogin:
showLinkingLogin(ctx, *gothUser)
return false // user will be created only after linking login
}
diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go
index cbcb2a5222..e238125407 100644
--- a/routers/web/auth/auth_test.go
+++ b/routers/web/auth/auth_test.go
@@ -61,23 +61,35 @@ func TestUserLogin(t *testing.T) {
assert.Equal(t, "/", test.RedirectURL(resp))
}
-func TestSignUpOAuth2ButMissingFields(t *testing.T) {
+func TestSignUpOAuth2Login(t *testing.T) {
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
- defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
- return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
- })()
addOAuth2Source(t, "dummy-auth-source", oauth2.Source{})
- mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
- ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
- ctx.SetPathParam("provider", "dummy-auth-source")
- SignInOAuthCallback(ctx)
- assert.Equal(t, http.StatusSeeOther, resp.Code)
- assert.Equal(t, "/user/link_account", test.RedirectURL(resp))
+ t.Run("OAuth2MissingField", func(t *testing.T) {
+ defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
+ return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
+ })()
+ mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
+ ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
+ ctx.SetPathParam("provider", "dummy-auth-source")
+ SignInOAuthCallback(ctx)
+ assert.Equal(t, http.StatusSeeOther, resp.Code)
+ assert.Equal(t, "/user/link_account", test.RedirectURL(resp))
+
+ // then the user will be redirected to the link account page, and see a message about the missing fields
+ ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt)
+ LinkAccount(ctx)
+ assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"])
+ })
- // then the user will be redirected to the link account page, and see a message about the missing fields
- ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt)
- LinkAccount(ctx)
- assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"])
+ t.Run("OAuth2CallbackError", func(t *testing.T) {
+ mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
+ ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback", mockOpt)
+ ctx.SetPathParam("provider", "dummy-auth-source")
+ SignInOAuthCallback(ctx)
+ assert.Equal(t, http.StatusSeeOther, resp.Code)
+ assert.Equal(t, "/user/login", test.RedirectURL(resp))
+ assert.Contains(t, ctx.Flash.ErrorMsg, "auth.oauth.signin.error.general")
+ })
}
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index 7a9721cf56..94a8bec565 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -115,7 +115,7 @@ func SignInOAuthCallback(ctx *context.Context) {
case "temporarily_unavailable":
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.temporarily_unavailable"))
default:
- ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error"))
+ ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.general", callbackErr.Description))
}
ctx.Redirect(setting.AppSubURL + "/user/login")
return
@@ -155,9 +155,10 @@ func SignInOAuthCallback(ctx *context.Context) {
return
}
if uname == "" {
- if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname {
+ switch setting.OAuth2Client.Username {
+ case setting.OAuth2UsernameNickname:
missingFields = append(missingFields, "nickname")
- } else if setting.OAuth2Client.Username == setting.OAuth2UsernamePreferredUsername {
+ case setting.OAuth2UsernamePreferredUsername:
missingFields = append(missingFields, "preferred_username")
} // else: "UserID" and "Email" have been handled above separately
}
@@ -431,8 +432,10 @@ func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, requ
gothUser, err := oauth2Source.Callback(request, response)
if err != nil {
if err.Error() == "securecookie: the value is too long" || strings.Contains(err.Error(), "Data too long") {
- log.Error("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
err = fmt.Errorf("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
+ log.Error("oauth2Source.Callback failed: %v", err)
+ } else {
+ err = errCallback{Code: "internal", Description: err.Error()}
}
return nil, goth.User{}, err
}
diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go
index 00b5b2db52..1804b5b193 100644
--- a/routers/web/auth/oauth2_provider.go
+++ b/routers/web/auth/oauth2_provider.go
@@ -10,6 +10,7 @@ import (
"html/template"
"net/http"
"net/url"
+ "strconv"
"strings"
"code.gitea.io/gitea/models/auth"
@@ -98,7 +99,7 @@ func InfoOAuth(ctx *context.Context) {
}
response := &userInfoResponse{
- Sub: fmt.Sprint(ctx.Doer.ID),
+ Sub: strconv.FormatInt(ctx.Doer.ID, 10),
Name: ctx.Doer.DisplayName(),
PreferredUsername: ctx.Doer.Name,
Email: ctx.Doer.Email,
@@ -171,7 +172,7 @@ func IntrospectOAuth(ctx *context.Context) {
response.Scope = grant.Scope
response.Issuer = setting.AppURL
response.Audience = []string{app.ClientID}
- response.Subject = fmt.Sprint(grant.UserID)
+ response.Subject = strconv.FormatInt(grant.UserID, 10)
}
if user, err := user_model.GetUserByID(ctx, grant.UserID); err == nil {
response.Username = user.Name
@@ -249,7 +250,7 @@ func AuthorizeOAuth(ctx *context.Context) {
}, form.RedirectURI)
return
}
- if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallenge); err != nil {
+ if err := ctx.Session.Set("CodeChallenge", form.CodeChallenge); err != nil {
handleAuthorizeError(ctx, AuthorizeError{
ErrorCode: ErrorCodeServerError,
ErrorDescription: "cannot set code challenge",
diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go
index c3415cccac..8c2d3276a8 100644
--- a/routers/web/auth/openid.go
+++ b/routers/web/auth/openid.go
@@ -4,7 +4,7 @@
package auth
import (
- "fmt"
+ "errors"
"net/http"
"net/url"
@@ -55,13 +55,13 @@ func allowedOpenIDURI(uri string) (err error) {
}
}
// must match one of this or be refused
- return fmt.Errorf("URI not allowed by whitelist")
+ return errors.New("URI not allowed by whitelist")
}
// A blacklist match expliclty forbids
for _, pat := range setting.Service.OpenIDBlacklist {
if pat.MatchString(uri) {
- return fmt.Errorf("URI forbidden by blacklist")
+ return errors.New("URI forbidden by blacklist")
}
}
@@ -99,7 +99,7 @@ func SignInOpenIDPost(ctx *context.Context) {
url, err := openid.RedirectURL(id, redirectTo, setting.AppURL)
if err != nil {
log.Error("Error in OpenID redirect URL: %s, %v", redirectTo, err.Error())
- ctx.RenderWithErr(fmt.Sprintf("Unable to find OpenID provider in %s", redirectTo), tplSignInOpenID, &form)
+ ctx.RenderWithErr("Unable to find OpenID provider in "+redirectTo, tplSignInOpenID, &form)
return
}
diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go
index 8dbde85fe6..537ad4b994 100644
--- a/routers/web/auth/password.go
+++ b/routers/web/auth/password.go
@@ -5,7 +5,6 @@ package auth
import (
"errors"
- "fmt"
"net/http"
"code.gitea.io/gitea/models/auth"
@@ -108,14 +107,14 @@ func commonResetPassword(ctx *context.Context) (*user_model.User, *auth.TwoFacto
}
if len(code) == 0 {
- ctx.Flash.Error(ctx.Tr("auth.invalid_code_forgot_password", fmt.Sprintf("%s/user/forgot_password", setting.AppSubURL)), true)
+ ctx.Flash.Error(ctx.Tr("auth.invalid_code_forgot_password", setting.AppSubURL+"/user/forgot_password"), true)
return nil, nil
}
// Fail early, don't frustrate the user
u := user_model.VerifyUserTimeLimitCode(ctx, &user_model.TimeLimitCodeOptions{Purpose: user_model.TimeLimitCodeResetPassword}, code)
if u == nil {
- ctx.Flash.Error(ctx.Tr("auth.invalid_code_forgot_password", fmt.Sprintf("%s/user/forgot_password", setting.AppSubURL)), true)
+ ctx.Flash.Error(ctx.Tr("auth.invalid_code_forgot_password", setting.AppSubURL+"/user/forgot_password"), true)
return nil, nil
}
diff --git a/routers/web/base.go b/routers/web/base.go
index a284dd0288..e43f36a97b 100644
--- a/routers/web/base.go
+++ b/routers/web/base.go
@@ -25,7 +25,7 @@ func avatarStorageHandler(storageSetting *setting.Storage, prefix string, objSto
if storageSetting.ServeDirect() {
return func(w http.ResponseWriter, req *http.Request) {
- if req.Method != "GET" && req.Method != "HEAD" {
+ if req.Method != http.MethodGet && req.Method != http.MethodHead {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
@@ -56,7 +56,7 @@ func avatarStorageHandler(storageSetting *setting.Storage, prefix string, objSto
}
return func(w http.ResponseWriter, req *http.Request) {
- if req.Method != "GET" && req.Method != "HEAD" {
+ if req.Method != http.MethodGet && req.Method != http.MethodHead {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
diff --git a/routers/web/devtest/devtest.go b/routers/web/devtest/devtest.go
index 1ea1398173..765931a730 100644
--- a/routers/web/devtest/devtest.go
+++ b/routers/web/devtest/devtest.go
@@ -4,16 +4,22 @@
package devtest
import (
+ "fmt"
+ "html/template"
"net/http"
"path"
+ "strconv"
"strings"
"time"
+ "unicode"
"code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/badge"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
@@ -45,86 +51,135 @@ func FetchActionTest(ctx *context.Context) {
ctx.JSONRedirect("")
}
-func prepareMockData(ctx *context.Context) {
- if ctx.Req.URL.Path == "/devtest/gitea-ui" {
- now := time.Now()
- ctx.Data["TimeNow"] = now
- ctx.Data["TimePast5s"] = now.Add(-5 * time.Second)
- ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second)
- ctx.Data["TimePast2m"] = now.Add(-2 * time.Minute)
- ctx.Data["TimeFuture2m"] = now.Add(2 * time.Minute)
- ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
- ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
+func prepareMockDataGiteaUI(ctx *context.Context) {
+ now := time.Now()
+ ctx.Data["TimeNow"] = now
+ ctx.Data["TimePast5s"] = now.Add(-5 * time.Second)
+ ctx.Data["TimeFuture5s"] = now.Add(5 * time.Second)
+ ctx.Data["TimePast2m"] = now.Add(-2 * time.Minute)
+ ctx.Data["TimeFuture2m"] = now.Add(2 * time.Minute)
+ ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
+ ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
+}
+
+func prepareMockDataBadgeCommitSign(ctx *context.Context) {
+ var commits []*asymkey.SignCommit
+ mockUsers, _ := db.Find[user_model.User](ctx, user_model.SearchUserOptions{ListOptions: db.ListOptions{PageSize: 1}})
+ mockUser := mockUsers[0]
+ commits = append(commits, &asymkey.SignCommit{
+ Verification: &asymkey.CommitVerification{},
+ UserCommit: &user_model.UserCommit{
+ Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
+ },
+ })
+ commits = append(commits, &asymkey.SignCommit{
+ Verification: &asymkey.CommitVerification{
+ Verified: true,
+ Reason: "name / key-id",
+ SigningUser: mockUser,
+ SigningKey: &asymkey.GPGKey{KeyID: "12345678"},
+ TrustStatus: "trusted",
+ },
+ UserCommit: &user_model.UserCommit{
+ User: mockUser,
+ Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
+ },
+ })
+ commits = append(commits, &asymkey.SignCommit{
+ Verification: &asymkey.CommitVerification{
+ Verified: true,
+ Reason: "name / key-id",
+ SigningUser: mockUser,
+ SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
+ TrustStatus: "untrusted",
+ },
+ UserCommit: &user_model.UserCommit{
+ User: mockUser,
+ Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
+ },
+ })
+ commits = append(commits, &asymkey.SignCommit{
+ Verification: &asymkey.CommitVerification{
+ Verified: true,
+ Reason: "name / key-id",
+ SigningUser: mockUser,
+ SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
+ TrustStatus: "other(unmatch)",
+ },
+ UserCommit: &user_model.UserCommit{
+ User: mockUser,
+ Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
+ },
+ })
+ commits = append(commits, &asymkey.SignCommit{
+ Verification: &asymkey.CommitVerification{
+ Warning: true,
+ Reason: "gpg.error",
+ SigningEmail: "test@example.com",
+ },
+ UserCommit: &user_model.UserCommit{
+ User: mockUser,
+ Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
+ },
+ })
+
+ ctx.Data["MockCommits"] = commits
+}
+
+func prepareMockDataBadgeActionsSvg(ctx *context.Context) {
+ fontFamilyNames := strings.Split(badge.DefaultFontFamily, ",")
+ selectedFontFamilyName := ctx.FormString("font", fontFamilyNames[0])
+ selectedStyle := ctx.FormString("style", badge.DefaultStyle)
+ var badges []badge.Badge
+ badges = append(badges, badge.GenerateBadge("啊啊啊啊啊啊啊啊啊啊啊啊", "🌞🌞🌞🌞🌞", "green"))
+ for r := rune(0); r < 256; r++ {
+ if unicode.IsPrint(r) {
+ s := strings.Repeat(string(r), 15)
+ badges = append(badges, badge.GenerateBadge(s, util.TruncateRunes(s, 7), "green"))
+ }
}
- if ctx.Req.URL.Path == "/devtest/commit-sign-badge" {
- var commits []*asymkey.SignCommit
- mockUsers, _ := db.Find[user_model.User](ctx, user_model.SearchUserOptions{ListOptions: db.ListOptions{PageSize: 1}})
- mockUser := mockUsers[0]
- commits = append(commits, &asymkey.SignCommit{
- Verification: &asymkey.CommitVerification{},
- UserCommit: &user_model.UserCommit{
- Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
- },
- })
- commits = append(commits, &asymkey.SignCommit{
- Verification: &asymkey.CommitVerification{
- Verified: true,
- Reason: "name / key-id",
- SigningUser: mockUser,
- SigningKey: &asymkey.GPGKey{KeyID: "12345678"},
- TrustStatus: "trusted",
- },
- UserCommit: &user_model.UserCommit{
- User: mockUser,
- Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
- },
- })
- commits = append(commits, &asymkey.SignCommit{
- Verification: &asymkey.CommitVerification{
- Verified: true,
- Reason: "name / key-id",
- SigningUser: mockUser,
- SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
- TrustStatus: "untrusted",
- },
- UserCommit: &user_model.UserCommit{
- User: mockUser,
- Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
- },
- })
- commits = append(commits, &asymkey.SignCommit{
- Verification: &asymkey.CommitVerification{
- Verified: true,
- Reason: "name / key-id",
- SigningUser: mockUser,
- SigningSSHKey: &asymkey.PublicKey{Fingerprint: "aa:bb:cc:dd:ee"},
- TrustStatus: "other(unmatch)",
- },
- UserCommit: &user_model.UserCommit{
- User: mockUser,
- Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
- },
- })
- commits = append(commits, &asymkey.SignCommit{
- Verification: &asymkey.CommitVerification{
- Warning: true,
- Reason: "gpg.error",
- SigningEmail: "test@example.com",
- },
- UserCommit: &user_model.UserCommit{
- User: mockUser,
- Commit: &git.Commit{ID: git.Sha1ObjectFormat.EmptyObjectID()},
- },
- })
+ var badgeSVGs []template.HTML
+ for i, b := range badges {
+ b.IDPrefix = "devtest-" + strconv.FormatInt(int64(i), 10) + "-"
+ b.FontFamily = selectedFontFamilyName
+ var h template.HTML
+ var err error
+ switch selectedStyle {
+ case badge.StyleFlat:
+ h, err = ctx.RenderToHTML("shared/actions/runner_badge_flat", map[string]any{"Badge": b})
+ case badge.StyleFlatSquare:
+ h, err = ctx.RenderToHTML("shared/actions/runner_badge_flat-square", map[string]any{"Badge": b})
+ default:
+ err = fmt.Errorf("unknown badge style: %s", selectedStyle)
+ }
+ if err != nil {
+ ctx.ServerError("RenderToHTML", err)
+ return
+ }
+ badgeSVGs = append(badgeSVGs, h)
+ }
+ ctx.Data["BadgeSVGs"] = badgeSVGs
+ ctx.Data["BadgeFontFamilyNames"] = fontFamilyNames
+ ctx.Data["SelectedFontFamilyName"] = selectedFontFamilyName
+ ctx.Data["BadgeStyles"] = badge.GlobalVars().AllStyles
+ ctx.Data["SelectedStyle"] = selectedStyle
+}
- ctx.Data["MockCommits"] = commits
+func prepareMockData(ctx *context.Context) {
+ switch ctx.Req.URL.Path {
+ case "/devtest/gitea-ui":
+ prepareMockDataGiteaUI(ctx)
+ case "/devtest/badge-commit-sign":
+ prepareMockDataBadgeCommitSign(ctx)
+ case "/devtest/badge-actions-svg":
+ prepareMockDataBadgeActionsSvg(ctx)
}
}
-func Tmpl(ctx *context.Context) {
+func TmplCommon(ctx *context.Context) {
prepareMockData(ctx)
- if ctx.Req.Method == "POST" {
+ if ctx.Req.Method == http.MethodPost {
_ = ctx.Req.ParseForm()
ctx.Flash.Info("form: "+ctx.Req.Method+" "+ctx.Req.RequestURI+"<br>"+
"Form: "+ctx.Req.Form.Encode()+"<br>"+
diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go
index 3ce75dfad2..023909aceb 100644
--- a/routers/web/devtest/mock_actions.go
+++ b/routers/web/devtest/mock_actions.go
@@ -4,9 +4,9 @@
package devtest
import (
- "fmt"
mathRand "math/rand/v2"
"net/http"
+ "strconv"
"strings"
"time"
@@ -38,8 +38,8 @@ func generateMockStepsLog(logCur actions.LogCursor) (stepsLog []*actions.ViewSte
for i := 0; i < mockCount; i++ {
logStr := mockedLogs[int(cur)%len(mockedLogs)]
cur++
- logStr = strings.ReplaceAll(logStr, "{step}", fmt.Sprintf("%d", logCur.Step))
- logStr = strings.ReplaceAll(logStr, "{cursor}", fmt.Sprintf("%d", cur))
+ logStr = strings.ReplaceAll(logStr, "{step}", strconv.Itoa(logCur.Step))
+ logStr = strings.ReplaceAll(logStr, "{cursor}", strconv.FormatInt(cur, 10))
stepsLog = append(stepsLog, &actions.ViewStepLog{
Step: logCur.Step,
Cursor: cur,
diff --git a/routers/web/feed/branch.go b/routers/web/feed/branch.go
index d3dae9503e..4a6fe9603d 100644
--- a/routers/web/feed/branch.go
+++ b/routers/web/feed/branch.go
@@ -4,7 +4,6 @@
package feed
import (
- "fmt"
"strings"
"time"
@@ -22,7 +21,7 @@ func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType stri
return
}
- title := fmt.Sprintf("Latest commits for branch %s", ctx.Repo.BranchName)
+ title := "Latest commits for branch " + ctx.Repo.BranchName
link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.RefTypeNameSubURL()}
feed := &feeds.Feed{
diff --git a/routers/web/feed/file.go b/routers/web/feed/file.go
index 407e4fa2d5..026c15c43a 100644
--- a/routers/web/feed/file.go
+++ b/routers/web/feed/file.go
@@ -4,7 +4,6 @@
package feed
import (
- "fmt"
"strings"
"time"
@@ -33,7 +32,7 @@ func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string
return
}
- title := fmt.Sprintf("Latest commits for file %s", ctx.Repo.TreePath)
+ title := "Latest commits for file " + ctx.Repo.TreePath
link := &feeds.Link{Href: repo.HTMLURL() + "/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)}
diff --git a/routers/web/githttp.go b/routers/web/githttp.go
index 8597ffe795..06de811f16 100644
--- a/routers/web/githttp.go
+++ b/routers/web/githttp.go
@@ -4,26 +4,12 @@
package web
import (
- "net/http"
-
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/context"
)
func addOwnerRepoGitHTTPRouters(m *web.Router) {
- reqGitSignIn := func(ctx *context.Context) {
- if !setting.Service.RequireSignInView {
- return
- }
- // rely on the results of Contexter
- if !ctx.IsSigned {
- // TODO: support digit auth - which would be Authorization header with digit
- ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea"`)
- ctx.HTTPError(http.StatusUnauthorized)
- }
- }
m.Group("/{username}/{reponame}", func() {
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
@@ -36,5 +22,5 @@ func addOwnerRepoGitHTTPRouters(m *web.Router) {
m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject)
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile)
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile)
- }, optSignInIgnoreCsrf, reqGitSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context.UserAssignmentWeb())
+ }, optSignInIgnoreCsrf, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context.UserAssignmentWeb())
}
diff --git a/routers/web/goget.go b/routers/web/goget.go
index 79d5c2b207..67e0bee866 100644
--- a/routers/web/goget.go
+++ b/routers/web/goget.go
@@ -18,7 +18,7 @@ import (
)
func goGet(ctx *context.Context) {
- if ctx.Req.Method != "GET" || len(ctx.Req.URL.RawQuery) < 8 || ctx.FormString("go-get") != "1" {
+ if ctx.Req.Method != http.MethodGet || len(ctx.Req.URL.RawQuery) < 8 || ctx.FormString("go-get") != "1" {
return
}
diff --git a/routers/web/nodeinfo.go b/routers/web/nodeinfo.go
index f1cc7bf530..47856bf98b 100644
--- a/routers/web/nodeinfo.go
+++ b/routers/web/nodeinfo.go
@@ -4,7 +4,6 @@
package web
import (
- "fmt"
"net/http"
"code.gitea.io/gitea/modules/setting"
@@ -24,7 +23,7 @@ type nodeInfoLink struct {
func NodeInfoLinks(ctx *context.Context) {
nodeinfolinks := &nodeInfoLinks{
Links: []nodeInfoLink{{
- fmt.Sprintf("%sapi/v1/nodeinfo", setting.AppURL),
+ setting.AppURL + "api/v1/nodeinfo",
"http://nodeinfo.diaspora.software/ns/schema/2.1",
}},
}
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 985fd2ca45..49f4792772 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -347,11 +347,11 @@ func ViewProject(ctx *context.Context) {
if ctx.Written() {
return
}
- assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
+ assigneeID := ctx.FormString("assignee")
opts := issues_model.IssuesOptions{
LabelIDs: labelIDs,
- AssigneeID: optional.Some(assigneeID),
+ AssigneeID: assigneeID,
Owner: project.Owner,
Doer: ctx.Doer,
}
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index cb1c4213c9..a8a81e0ade 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -170,7 +170,7 @@ func SettingsDelete(ctx *context.Context) {
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsSettingsDelete"] = true
- if ctx.Req.Method == "POST" {
+ if ctx.Req.Method == http.MethodPost {
if ctx.Org.Organization.Name != ctx.FormString("org_name") {
ctx.Data["Err_OrgName"] = true
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_org_name"), tplSettingsDelete, nil)
diff --git a/routers/web/org/worktime.go b/routers/web/org/worktime.go
index 2336984825..a576dd9a11 100644
--- a/routers/web/org/worktime.go
+++ b/routers/web/org/worktime.go
@@ -55,13 +55,14 @@ func Worktime(ctx *context.Context) {
var worktimeSumResult any
var err error
- if worktimeBy == "milestones" {
+ switch worktimeBy {
+ case "milestones":
worktimeSumResult, err = organization.GetWorktimeByMilestones(ctx.Org.Organization, unixFrom, unixTo)
ctx.Data["WorktimeByMilestones"] = true
- } else if worktimeBy == "members" {
+ case "members":
worktimeSumResult, err = organization.GetWorktimeByMembers(ctx.Org.Organization, unixFrom, unixTo)
ctx.Data["WorktimeByMembers"] = true
- } else /* by repos */ {
+ default: /* by repos */
worktimeSumResult, err = organization.GetWorktimeByRepos(ctx.Org.Organization, unixFrom, unixTo)
ctx.Data["WorktimeByRepos"] = true
}
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index d07d195713..5014ff52e3 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -6,6 +6,7 @@ package actions
import (
"bytes"
stdCtx "context"
+ "errors"
"net/http"
"slices"
"strings"
@@ -67,7 +68,11 @@ func List(ctx *context.Context) {
ctx.Data["PageIsActions"] = true
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
- if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.Data["NotFoundPrompt"] = ctx.Tr("repo.branch.default_branch_not_exist", ctx.Repo.Repository.DefaultBranch)
+ ctx.NotFound(nil)
+ return
+ } else if err != nil {
ctx.ServerError("GetBranchCommit", err)
return
}
diff --git a/routers/web/repo/actions/badge.go b/routers/web/repo/actions/badge.go
index e920ecaf58..d268a8df8a 100644
--- a/routers/web/repo/actions/badge.go
+++ b/routers/web/repo/actions/badge.go
@@ -5,35 +5,38 @@ package actions
import (
"errors"
- "fmt"
"net/http"
"path/filepath"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/modules/badge"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
func GetWorkflowBadge(ctx *context.Context) {
workflowFile := ctx.PathParam("workflow_name")
- branch := ctx.Req.URL.Query().Get("branch")
- if branch == "" {
- branch = ctx.Repo.Repository.DefaultBranch
- }
- branchRef := fmt.Sprintf("refs/heads/%s", branch)
- event := ctx.Req.URL.Query().Get("event")
+ branch := ctx.FormString("branch", ctx.Repo.Repository.DefaultBranch)
+ event := ctx.FormString("event")
+ style := ctx.FormString("style")
- badge, err := getWorkflowBadge(ctx, workflowFile, branchRef, event)
+ branchRef := git.RefNameFromBranch(branch)
+ b, err := getWorkflowBadge(ctx, workflowFile, branchRef.String(), event)
if err != nil {
ctx.ServerError("GetWorkflowBadge", err)
return
}
- ctx.Data["Badge"] = badge
+ ctx.Data["Badge"] = b
ctx.RespHeader().Set("Content-Type", "image/svg+xml")
- ctx.HTML(http.StatusOK, "shared/actions/runner_badge")
+ switch style {
+ case badge.StyleFlatSquare:
+ ctx.HTML(http.StatusOK, "shared/actions/runner_badge_flat-square")
+ default: // defaults to badge.StyleFlat
+ ctx.HTML(http.StatusOK, "shared/actions/runner_badge_flat")
+ }
}
func getWorkflowBadge(ctx *context.Context, workflowFile, branchName, event string) (badge.Badge, error) {
@@ -48,7 +51,7 @@ func getWorkflowBadge(ctx *context.Context, workflowFile, branchName, event stri
return badge.Badge{}, err
}
- color, ok := badge.StatusColorMap[run.Status]
+ color, ok := badge.GlobalVars().StatusColorMap[run.Status]
if !ok {
return badge.GenerateBadge(workflowName, "unknown status", badge.DefaultColor), nil
}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 41f0d2d0ec..ec06c9233a 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -14,7 +14,6 @@ import (
"net/http"
"net/url"
"strconv"
- "strings"
"time"
actions_model "code.gitea.io/gitea/models/actions"
@@ -31,6 +30,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"
actions_service "code.gitea.io/gitea/services/actions"
context_module "code.gitea.io/gitea/services/context"
notify_service "code.gitea.io/gitea/services/notify"
@@ -469,49 +469,19 @@ func Logs(ctx *context_module.Context) {
runIndex := getRunIndex(ctx)
jobIndex := ctx.PathParamInt64("job")
- job, _ := getRunJobs(ctx, runIndex, jobIndex)
- if ctx.Written() {
- return
- }
- if job.TaskID == 0 {
- ctx.HTTPError(http.StatusNotFound, "job is not started")
- return
- }
-
- err := job.LoadRun(ctx)
- if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, err.Error())
- return
- }
-
- task, err := actions_model.GetTaskByID(ctx, job.TaskID)
- if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, err.Error())
- return
- }
- if task.LogExpired {
- ctx.HTTPError(http.StatusNotFound, "logs have been cleaned up")
- return
- }
-
- reader, err := actions.OpenLogs(ctx, task.LogInStorage, task.LogFilename)
+ run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, err.Error())
+ ctx.NotFoundOrServerError("GetRunByIndex", func(err error) bool {
+ return errors.Is(err, util.ErrNotExist)
+ }, err)
return
}
- defer reader.Close()
- workflowName := job.Run.WorkflowID
- if p := strings.Index(workflowName, "."); p > 0 {
- workflowName = workflowName[0:p]
+ if err = common.DownloadActionsRunJobLogsWithIndex(ctx.Base, ctx.Repo.Repository, run.ID, jobIndex); err != nil {
+ ctx.NotFoundOrServerError("DownloadActionsRunJobLogsWithIndex", func(err error) bool {
+ return errors.Is(err, util.ErrNotExist)
+ }, err)
}
- ctx.ServeContent(reader, &context_module.ServeHeaderOptions{
- Filename: fmt.Sprintf("%v-%v-%v.log", workflowName, job.Name, task.ID),
- ContentLength: &task.LogSize,
- ContentType: "text/plain",
- ContentTypeCharset: "utf-8",
- Disposition: "attachment",
- })
}
func Cancel(ctx *context_module.Context) {
@@ -538,7 +508,7 @@ func Cancel(ctx *context_module.Context) {
return err
}
if n == 0 {
- return fmt.Errorf("job has changed, try again")
+ return errors.New("job has changed, try again")
}
if n > 0 {
updatedjobs = append(updatedjobs, job)
diff --git a/routers/web/repo/activity.go b/routers/web/repo/activity.go
index 1d809ad8e9..8232f0cc04 100644
--- a/routers/web/repo/activity.go
+++ b/routers/web/repo/activity.go
@@ -8,6 +8,7 @@ import (
"time"
activities_model "code.gitea.io/gitea/models/activities"
+ "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
@@ -52,12 +53,26 @@ func Activity(ctx *context.Context) {
ctx.Data["DateUntil"] = timeUntil
ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + ctx.Data["Period"].(string))
+ canReadCode := ctx.Repo.CanRead(unit.TypeCode)
+ if canReadCode {
+ // GetActivityStats needs to read the default branch to get some information
+ branchExist, _ := git.IsBranchExist(ctx, ctx.Repo.Repository.ID, ctx.Repo.Repository.DefaultBranch)
+ if !branchExist {
+ ctx.Data["NotFoundPrompt"] = ctx.Tr("repo.branch.default_branch_not_exist", ctx.Repo.Repository.DefaultBranch)
+ ctx.NotFound(nil)
+ return
+ }
+ }
+
var err error
- if ctx.Data["Activity"], err = activities_model.GetActivityStats(ctx, ctx.Repo.Repository, timeFrom,
+ // TODO: refactor these arguments to a struct
+ ctx.Data["Activity"], err = activities_model.GetActivityStats(ctx, ctx.Repo.Repository, timeFrom,
ctx.Repo.CanRead(unit.TypeReleases),
ctx.Repo.CanRead(unit.TypeIssues),
ctx.Repo.CanRead(unit.TypePullRequests),
- ctx.Repo.CanRead(unit.TypeCode)); err != nil {
+ canReadCode,
+ )
+ if err != nil {
ctx.ServerError("GetActivityStats", err)
return
}
diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go
index ec50e1435e..690b830bc2 100644
--- a/routers/web/repo/cherry_pick.go
+++ b/routers/web/repo/cherry_pick.go
@@ -6,6 +6,7 @@ package repo
import (
"bytes"
"errors"
+ "net/http"
"strings"
git_model "code.gitea.io/gitea/models/git"
@@ -59,7 +60,7 @@ func CherryPick(ctx *context.Context) {
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()
- ctx.HTML(200, tplCherryPick)
+ ctx.HTML(http.StatusOK, tplCherryPick)
}
// CherryPickPost handles cherrypick POSTs
@@ -88,7 +89,7 @@ func CherryPickPost(ctx *context.Context) {
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()
if ctx.HasError() {
- ctx.HTML(200, tplCherryPick)
+ ctx.HTML(http.StatusOK, tplCherryPick)
return
}
diff --git a/routers/web/repo/code_frequency.go b/routers/web/repo/code_frequency.go
index e212d3b60c..2b2dd5744a 100644
--- a/routers/web/repo/code_frequency.go
+++ b/routers/web/repo/code_frequency.go
@@ -34,7 +34,7 @@ func CodeFrequencyData(ctx *context.Context) {
ctx.Status(http.StatusAccepted)
return
}
- ctx.ServerError("GetCodeFrequencyData", err)
+ ctx.ServerError("GetContributorStats", err)
} else {
ctx.JSON(http.StatusOK, contributorStats["total"].Weeks)
}
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index bbdcf9875e..3fd1eacb58 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -284,7 +284,7 @@ func Diff(ctx *context.Context) {
)
if ctx.Data["PageIsWiki"] != nil {
- gitRepo, err = gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ gitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository.WikiStorageRepo())
if err != nil {
ctx.ServerError("Repo.GitRepo.GetCommit", err)
return
@@ -417,7 +417,7 @@ func Diff(ctx *context.Context) {
func RawDiff(ctx *context.Context) {
var gitRepo *git.Repository
if ctx.Data["PageIsWiki"] != nil {
- wikiRepo, err := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ wikiRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository.WikiStorageRepo())
if err != nil {
ctx.ServerError("OpenRepository", err)
return
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index 6cea95e387..2c36477e6a 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -569,19 +569,13 @@ func PrepareCompareDiff(
ctx *context.Context,
ci *common.CompareInfo,
whitespaceBehavior git.TrustedCmdArgs,
-) bool {
- var (
- repo = ctx.Repo.Repository
- err error
- title string
- )
-
- // Get diff information.
- ctx.Data["CommitRepoLink"] = ci.HeadRepo.Link()
-
+) (nothingToCompare bool) {
+ repo := ctx.Repo.Repository
headCommitID := ci.CompareInfo.HeadCommitID
+ ctx.Data["CommitRepoLink"] = ci.HeadRepo.Link()
ctx.Data["AfterCommitID"] = headCommitID
+ ctx.Data["ExpandNewPrForm"] = ctx.FormBool("expand")
if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) ||
headCommitID == ci.CompareInfo.BaseCommitID {
@@ -670,6 +664,7 @@ func PrepareCompareDiff(
ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits)
+ title := ci.HeadBranch
if len(commits) == 1 {
c := commits[0]
title = strings.TrimSpace(c.UserCommit.Summary())
@@ -678,9 +673,8 @@ func PrepareCompareDiff(
if len(body) > 1 {
ctx.Data["content"] = strings.Join(body[1:], "\n")
}
- } else {
- title = ci.HeadBranch
}
+
if len(title) > 255 {
var trailer string
title, trailer = util.EllipsisDisplayStringX(title, 255)
@@ -745,8 +739,7 @@ func CompareDiff(ctx *context.Context) {
ctx.Data["OtherCompareSeparator"] = "..."
}
- nothingToCompare := PrepareCompareDiff(ctx, ci,
- gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)))
+ nothingToCompare := PrepareCompareDiff(ctx, ci, gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)))
if ctx.Written() {
return
}
@@ -885,7 +878,7 @@ func ExcerptBlob(ctx *context.Context) {
gitRepo := ctx.Repo.GitRepo
if ctx.Data["PageIsWiki"] == true {
var err error
- gitRepo, err = gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ gitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository.WikiStorageRepo())
if err != nil {
ctx.ServerError("OpenRepository", err)
return
@@ -945,9 +938,10 @@ func ExcerptBlob(ctx *context.Context) {
RightHunkSize: rightHunkSize,
},
}
- if direction == "up" {
+ switch direction {
+ case "up":
section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...)
- } else if direction == "down" {
+ case "down":
section.Lines = append(section.Lines, lineSection)
}
}
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 113622f872..c181aad050 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -668,7 +668,7 @@ func UploadFilePost(ctx *context.Context) {
}
if oldBranchName != branchName {
- if _, err := ctx.Repo.GitRepo.GetBranch(branchName); err == nil {
+ if exist, err := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, branchName); err == nil && exist {
ctx.Data["Err_NewBranchName"] = true
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), tplUploadFile, &form)
return
@@ -875,12 +875,11 @@ func GetUniquePatchBranchName(ctx *context.Context) string {
prefix := ctx.Doer.LowerName + "-patch-"
for i := 1; i <= 1000; i++ {
branchName := fmt.Sprintf("%s%d", prefix, i)
- if _, err := ctx.Repo.GitRepo.GetBranch(branchName); err != nil {
- if git.IsErrBranchNotExist(err) {
- return branchName
- }
+ if exist, err := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, branchName); err != nil {
log.Error("GetUniquePatchBranchName: %v", err)
return ""
+ } else if !exist {
+ return branchName
}
}
return ""
diff --git a/routers/web/repo/editor_test.go b/routers/web/repo/editor_test.go
index 566db31693..89bf8f309c 100644
--- a/routers/web/repo/editor_test.go
+++ b/routers/web/repo/editor_test.go
@@ -36,7 +36,7 @@ func TestCleanUploadName(t *testing.T) {
"..a.dotty../.folder../.name...": "..a.dotty../.folder../.name...",
}
for k, v := range kases {
- assert.EqualValues(t, cleanUploadFileName(k), v)
+ assert.Equal(t, cleanUploadFileName(k), v)
}
}
diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go
index f93d7fc66a..f4ac9d769b 100644
--- a/routers/web/repo/githttp.go
+++ b/routers/web/repo/githttp.go
@@ -78,7 +78,7 @@ func httpBase(ctx *context.Context) *serviceHandler {
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
isPull = true
} else {
- isPull = ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
+ isPull = ctx.Req.Method == http.MethodHead || ctx.Req.Method == http.MethodGet
}
var accessMode perm.AccessMode
@@ -127,7 +127,7 @@ func httpBase(ctx *context.Context) *serviceHandler {
// Only public pull don't need auth.
isPublicPull := repoExist && !repo.IsPrivate && isPull
var (
- askAuth = !isPublicPull || setting.Service.RequireSignInView
+ askAuth = !isPublicPull || setting.Service.RequireSignInViewStrict
environ []string
)
@@ -360,8 +360,8 @@ func setHeaderNoCache(ctx *context.Context) {
func setHeaderCacheForever(ctx *context.Context) {
now := time.Now().Unix()
expires := now + 31536000
- ctx.Resp.Header().Set("Date", fmt.Sprintf("%d", now))
- ctx.Resp.Header().Set("Expires", fmt.Sprintf("%d", expires))
+ ctx.Resp.Header().Set("Date", strconv.FormatInt(now, 10))
+ ctx.Resp.Header().Set("Expires", strconv.FormatInt(expires, 10))
ctx.Resp.Header().Set("Cache-Control", "public, max-age=31536000")
}
@@ -394,7 +394,7 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
}
ctx.Resp.Header().Set("Content-Type", contentType)
- ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
+ ctx.Resp.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10))
// http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
ctx.Resp.Header().Set("Last-Modified", fi.ModTime().UTC().Format(http.TimeFormat))
http.ServeFile(ctx.Resp, ctx.Req, reqFile)
diff --git a/routers/web/repo/githttp_test.go b/routers/web/repo/githttp_test.go
index 5ba8de3d63..0164b11f66 100644
--- a/routers/web/repo/githttp_test.go
+++ b/routers/web/repo/githttp_test.go
@@ -37,6 +37,6 @@ func TestContainsParentDirectorySeparator(t *testing.T) {
}
for i := range tests {
- assert.EqualValues(t, tests[i].b, containsParentDirectorySeparator(tests[i].v))
+ assert.Equal(t, tests[i].b, containsParentDirectorySeparator(tests[i].v))
}
}
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index c2c208736c..3602f4ec8a 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -157,15 +157,16 @@ func GetContentHistoryDetail(ctx *context.Context) {
diffHTMLBuf := bytes.Buffer{}
diffHTMLBuf.WriteString("<pre class='chroma'>")
for _, it := range diff {
- if it.Type == diffmatchpatch.DiffInsert {
+ switch it.Type {
+ case diffmatchpatch.DiffInsert:
diffHTMLBuf.WriteString("<span class='gi'>")
diffHTMLBuf.WriteString(html.EscapeString(it.Text))
diffHTMLBuf.WriteString("</span>")
- } else if it.Type == diffmatchpatch.DiffDelete {
+ case diffmatchpatch.DiffDelete:
diffHTMLBuf.WriteString("<span class='gd'>")
diffHTMLBuf.WriteString(html.EscapeString(it.Text))
diffHTMLBuf.WriteString("</span>")
- } else {
+ default:
diffHTMLBuf.WriteString(html.EscapeString(it.Text))
}
}
diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go
index 486c2e35a2..c3fba07034 100644
--- a/routers/web/repo/issue_label_test.go
+++ b/routers/web/repo/issue_label_test.go
@@ -38,7 +38,7 @@ func TestInitializeLabels(t *testing.T) {
contexttest.LoadRepo(t, ctx, 2)
web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"})
InitializeLabels(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &issues_model.Label{
RepoID: 2,
Name: "enhancement",
@@ -68,7 +68,7 @@ func TestRetrieveLabels(t *testing.T) {
assert.True(t, ok)
if assert.Len(t, labels, len(testCase.ExpectedLabelIDs)) {
for i, label := range labels {
- assert.EqualValues(t, testCase.ExpectedLabelIDs[i], label.ID)
+ assert.Equal(t, testCase.ExpectedLabelIDs[i], label.ID)
}
}
}
@@ -84,7 +84,7 @@ func TestNewLabel(t *testing.T) {
Color: "#abcdef",
})
NewLabel(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &issues_model.Label{
Name: "newlabel",
Color: "#abcdef",
@@ -104,7 +104,7 @@ func TestUpdateLabel(t *testing.T) {
IsArchived: true,
})
UpdateLabel(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &issues_model.Label{
ID: 2,
Name: "newnameforlabel",
@@ -120,7 +120,7 @@ func TestDeleteLabel(t *testing.T) {
contexttest.LoadRepo(t, ctx, 1)
ctx.Req.Form.Set("id", "2")
DeleteLabel(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
unittest.AssertNotExistsBean(t, &issues_model.Label{ID: 2})
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{LabelID: 2})
assert.EqualValues(t, ctx.Tr("repo.issues.label_deletion_success"), ctx.Flash.SuccessMsg)
@@ -134,7 +134,7 @@ func TestUpdateIssueLabel_Clear(t *testing.T) {
ctx.Req.Form.Set("issue_ids", "1,3")
ctx.Req.Form.Set("action", "clear")
UpdateIssueLabel(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: 1})
unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: 3})
unittest.CheckConsistencyFor(t, &issues_model.Label{})
@@ -160,7 +160,7 @@ func TestUpdateIssueLabel_Toggle(t *testing.T) {
ctx.Req.Form.Set("action", testCase.Action)
ctx.Req.Form.Set("id", strconv.Itoa(int(testCase.LabelID)))
UpdateIssueLabel(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
for _, issueID := range testCase.IssueIDs {
if testCase.ExpectedAdd {
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issueID, LabelID: testCase.LabelID})
diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go
index a65ae77795..d8ab653584 100644
--- a/routers/web/repo/issue_list.go
+++ b/routers/web/repo/issue_list.go
@@ -208,10 +208,10 @@ func SearchIssues(ctx *context.Context) {
if ctx.IsSigned {
ctxUserID := ctx.Doer.ID
if ctx.FormBool("created") {
- searchOpt.PosterID = optional.Some(ctxUserID)
+ searchOpt.PosterID = strconv.FormatInt(ctxUserID, 10)
}
if ctx.FormBool("assigned") {
- searchOpt.AssigneeID = optional.Some(ctxUserID)
+ searchOpt.AssigneeID = strconv.FormatInt(ctxUserID, 10)
}
if ctx.FormBool("mentioned") {
searchOpt.MentionID = optional.Some(ctxUserID)
@@ -373,10 +373,10 @@ func SearchRepoIssuesJSON(ctx *context.Context) {
}
if createdByID > 0 {
- searchOpt.PosterID = optional.Some(createdByID)
+ searchOpt.PosterID = strconv.FormatInt(createdByID, 10)
}
if assignedByID > 0 {
- searchOpt.AssigneeID = optional.Some(assignedByID)
+ searchOpt.AssigneeID = strconv.FormatInt(assignedByID, 10)
}
if mentionedByID > 0 {
searchOpt.MentionID = optional.Some(mentionedByID)
@@ -490,7 +490,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
viewType = "all"
}
- assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
+ assigneeID := ctx.FormString("assignee")
posterUsername := ctx.FormString("poster")
posterUserID := shared_user.GetFilterUserIDByName(ctx, posterUsername)
var mentionedID, reviewRequestedID, reviewedID int64
@@ -498,11 +498,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
if ctx.IsSigned {
switch viewType {
case "created_by":
- posterUserID = optional.Some(ctx.Doer.ID)
+ posterUserID = strconv.FormatInt(ctx.Doer.ID, 10)
case "mentioned":
mentionedID = ctx.Doer.ID
case "assigned":
- assigneeID = ctx.Doer.ID
+ assigneeID = strconv.FormatInt(ctx.Doer.ID, 10)
case "review_requested":
reviewRequestedID = ctx.Doer.ID
case "reviewed_by":
@@ -532,7 +532,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
LabelIDs: labelIDs,
MilestoneIDs: mileIDs,
ProjectID: projectID,
- AssigneeID: optional.Some(assigneeID),
+ AssigneeID: assigneeID,
MentionedID: mentionedID,
PosterID: posterUserID,
ReviewRequestedID: reviewRequestedID,
@@ -613,7 +613,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
PageSize: setting.UI.IssuePagingNum,
},
RepoIDs: []int64{repo.ID},
- AssigneeID: optional.Some(assigneeID),
+ AssigneeID: assigneeID,
PosterID: posterUserID,
MentionedID: mentionedID,
ReviewRequestedID: reviewRequestedID,
@@ -696,9 +696,10 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
return 0
}
reviewTyp := issues_model.ReviewTypeApprove
- if typ == "reject" {
+ switch typ {
+ case "reject":
reviewTyp = issues_model.ReviewTypeReject
- } else if typ == "waiting" {
+ case "waiting":
reviewTyp = issues_model.ReviewTypeRequest
}
for _, count := range counts {
diff --git a/routers/web/repo/issue_new.go b/routers/web/repo/issue_new.go
index 9f52396414..d8863961ff 100644
--- a/routers/web/repo/issue_new.go
+++ b/routers/web/repo/issue_new.go
@@ -223,11 +223,11 @@ func DeleteIssue(ctx *context.Context) {
}
if issue.IsPull {
- ctx.Redirect(fmt.Sprintf("%s/pulls", ctx.Repo.Repository.Link()), http.StatusSeeOther)
+ ctx.Redirect(ctx.Repo.Repository.Link()+"/pulls", http.StatusSeeOther)
return
}
- ctx.Redirect(fmt.Sprintf("%s/issues", ctx.Repo.Repository.Link()), http.StatusSeeOther)
+ ctx.Redirect(ctx.Repo.Repository.Link()+"/issues", http.StatusSeeOther)
}
func toSet[ItemType any, KeyType comparable](slice []ItemType, keyFunc func(ItemType) KeyType) container.Set[KeyType] {
diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go
index 73e279e0a6..5a8d203771 100644
--- a/routers/web/repo/issue_stopwatch.go
+++ b/routers/web/repo/issue_stopwatch.go
@@ -4,8 +4,6 @@
package repo
import (
- "strings"
-
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/eventsource"
@@ -72,39 +70,3 @@ func CancelStopwatch(c *context.Context) {
c.JSONRedirect("")
}
-
-// GetActiveStopwatch is the middleware that sets .ActiveStopwatch on context
-func GetActiveStopwatch(ctx *context.Context) {
- if strings.HasPrefix(ctx.Req.URL.Path, "/api") {
- return
- }
-
- if !ctx.IsSigned {
- return
- }
-
- _, sw, issue, err := issues_model.HasUserStopwatch(ctx, ctx.Doer.ID)
- if err != nil {
- ctx.ServerError("HasUserStopwatch", err)
- return
- }
-
- if sw == nil || sw.ID == 0 {
- return
- }
-
- ctx.Data["ActiveStopwatch"] = StopwatchTmplInfo{
- issue.Link(),
- issue.Repo.FullName(),
- issue.Index,
- sw.Seconds() + 1, // ensure time is never zero in ui
- }
-}
-
-// StopwatchTmplInfo is a view on a stopwatch specifically for template rendering
-type StopwatchTmplInfo struct {
- IssueLink string
- RepoSlug string
- IssueIndex int64
- Seconds int64
-}
diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go
index 120b3469f6..ca346b7e6c 100644
--- a/routers/web/repo/patch.go
+++ b/routers/web/repo/patch.go
@@ -4,6 +4,7 @@
package repo
import (
+ "net/http"
"strings"
git_model "code.gitea.io/gitea/models/git"
@@ -39,7 +40,7 @@ func NewDiffPatch(ctx *context.Context) {
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()
- ctx.HTML(200, tplPatchFile)
+ ctx.HTML(http.StatusOK, tplPatchFile)
}
// NewDiffPatchPost response for sending patch page
@@ -62,7 +63,7 @@ func NewDiffPatchPost(ctx *context.Context) {
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
if ctx.HasError() {
- ctx.HTML(200, tplPatchFile)
+ ctx.HTML(http.StatusOK, tplPatchFile)
return
}
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 5b81a5e4d1..6810025c6f 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -315,12 +315,12 @@ func ViewProject(ctx *context.Context) {
labelIDs := issue.PrepareFilterIssueLabels(ctx, ctx.Repo.Repository.ID, ctx.Repo.Owner)
- assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
+ assigneeID := ctx.FormString("assignee")
issuesMap, err := project_service.LoadIssuesFromProject(ctx, project, &issues_model.IssuesOptions{
RepoIDs: []int64{ctx.Repo.Repository.ID},
LabelIDs: labelIDs,
- AssigneeID: optional.Some(assigneeID),
+ AssigneeID: assigneeID,
})
if err != nil {
ctx.ServerError("LoadIssuesOfColumns", err)
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index e12798f93d..c72664f8e9 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -1269,6 +1269,21 @@ func stopTimerIfAvailable(ctx *context.Context, user *user_model.User, issue *is
return nil
}
+func PullsNewRedirect(ctx *context.Context) {
+ branch := ctx.PathParam("*")
+ redirectRepo := ctx.Repo.Repository
+ repo := ctx.Repo.Repository
+ if repo.IsFork {
+ if err := repo.GetBaseRepo(ctx); err != nil {
+ ctx.ServerError("GetBaseRepo", err)
+ return
+ }
+ redirectRepo = repo.BaseRepo
+ branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
+ }
+ ctx.Redirect(fmt.Sprintf("%s/compare/%s...%s?expand=1", redirectRepo.Link(), util.PathEscapeSegments(redirectRepo.DefaultBranch), util.PathEscapeSegments(branch)))
+}
+
// CompareAndPullRequestPost response for creating pull request
func CompareAndPullRequestPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateIssueForm)
diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go
index fb92d24394..929e131d61 100644
--- a/routers/web/repo/pull_review.go
+++ b/routers/web/repo/pull_review.go
@@ -209,11 +209,12 @@ func renderConversation(ctx *context.Context, comment *issues_model.Comment, ori
return user_service.CanBlockUser(ctx, ctx.Doer, blocker, blockee)
}
- if origin == "diff" {
+ switch origin {
+ case "diff":
ctx.HTML(http.StatusOK, tplDiffConversation)
- } else if origin == "timeline" {
+ case "timeline":
ctx.HTML(http.StatusOK, tplTimelineConversation)
- } else {
+ default:
ctx.HTTPError(http.StatusBadRequest, "Unknown origin: "+origin)
}
}
diff --git a/routers/web/repo/recent_commits.go b/routers/web/repo/recent_commits.go
index 228eb0dbac..2660116062 100644
--- a/routers/web/repo/recent_commits.go
+++ b/routers/web/repo/recent_commits.go
@@ -4,12 +4,10 @@
package repo
import (
- "errors"
"net/http"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
- contributors_service "code.gitea.io/gitea/services/repository"
)
const (
@@ -26,16 +24,3 @@ func RecentCommits(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplRecentCommits)
}
-
-// RecentCommitsData returns JSON of recent commits data
-func RecentCommitsData(ctx *context.Context) {
- if contributorStats, err := contributors_service.GetContributorStats(ctx, ctx.Cache, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch); err != nil {
- if errors.Is(err, contributors_service.ErrAwaitGeneration) {
- ctx.Status(http.StatusAccepted)
- return
- }
- ctx.ServerError("RecentCommitsData", err)
- } else {
- ctx.JSON(http.StatusOK, contributorStats["total"].Weeks)
- }
-}
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 73baf683ed..e260ea36dd 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -154,8 +154,8 @@ func createCommon(ctx *context.Context) {
ctx.Data["Licenses"] = repo_module.Licenses
ctx.Data["Readmes"] = repo_module.Readmes
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
- ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo()
- ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit()
+ ctx.Data["CanCreateRepoInDoer"] = ctx.Doer.CanCreateRepo()
+ ctx.Data["MaxCreationLimitOfDoer"] = ctx.Doer.MaxCreationLimit()
ctx.Data["SupportedObjectFormats"] = git.DefaultFeatures().SupportedObjectFormats
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat
}
@@ -305,11 +305,15 @@ func CreatePost(ctx *context.Context) {
}
func handleActionError(ctx *context.Context, err error) {
- if errors.Is(err, user_model.ErrBlockedUser) {
+ switch {
+ case errors.Is(err, user_model.ErrBlockedUser):
ctx.Flash.Error(ctx.Tr("repo.action.blocked_user"))
- } else if errors.Is(err, util.ErrPermissionDenied) {
+ case repo_service.IsRepositoryLimitReached(err):
+ limit := err.(repo_service.LimitReachedError).Limit
+ ctx.Flash.Error(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit))
+ case errors.Is(err, util.ErrPermissionDenied):
ctx.HTTPError(http.StatusNotFound)
- } else {
+ default:
ctx.ServerError(fmt.Sprintf("Action (%s)", ctx.PathParam("action")), err)
}
}
diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go
index 75de2ba1e7..f241242f02 100644
--- a/routers/web/repo/setting/protected_branch.go
+++ b/routers/web/repo/setting/protected_branch.go
@@ -8,6 +8,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"strings"
"time"
@@ -110,7 +111,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
var protectBranch *git_model.ProtectedBranch
if f.RuleName == "" {
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_rule_name"))
- ctx.Redirect(fmt.Sprintf("%s/settings/branches/edit", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings/branches/edit")
return
}
@@ -283,32 +284,32 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
func DeleteProtectedBranchRulePost(ctx *context.Context) {
ruleID := ctx.PathParamInt64("id")
if ruleID <= 0 {
- ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", fmt.Sprintf("%d", ruleID)))
- ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", strconv.FormatInt(ruleID, 10)))
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/branches")
return
}
rule, err := git_model.GetProtectedBranchRuleByID(ctx, ctx.Repo.Repository.ID, ruleID)
if err != nil {
- ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", fmt.Sprintf("%d", ruleID)))
- ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", strconv.FormatInt(ruleID, 10)))
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/branches")
return
}
if rule == nil {
- ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", fmt.Sprintf("%d", ruleID)))
- ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", strconv.FormatInt(ruleID, 10)))
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/branches")
return
}
if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, ruleID); err != nil {
ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", rule.RuleName))
- ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/branches")
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", rule.RuleName))
- ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/branches")
}
func UpdateBranchProtectionPriories(ctx *context.Context) {
@@ -332,7 +333,7 @@ func RenameBranchPost(ctx *context.Context) {
if ctx.HasError() {
ctx.Flash.Error(ctx.GetErrMsg())
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
return
}
@@ -341,13 +342,13 @@ func RenameBranchPost(ctx *context.Context) {
switch {
case repo_model.IsErrUserDoesNotHaveAccessToRepo(err):
ctx.Flash.Error(ctx.Tr("repo.branch.rename_default_or_protected_branch_error"))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
case git_model.IsErrBranchAlreadyExists(err):
ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.To))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
case errors.Is(err, git_model.ErrBranchIsProtected):
ctx.Flash.Error(ctx.Tr("repo.branch.rename_protected_branch_failed"))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
default:
ctx.ServerError("RenameBranch", err)
}
@@ -356,16 +357,16 @@ func RenameBranchPost(ctx *context.Context) {
if msg == "target_exist" {
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
return
}
if msg == "from_not_exist" {
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_not_exist", form.From))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.rename_branch_success", form.From, form.To))
- ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ ctx.Redirect(ctx.Repo.RepoLink + "/branches")
}
diff --git a/routers/web/repo/setting/public_access.go b/routers/web/repo/setting/public_access.go
new file mode 100644
index 0000000000..368d34294a
--- /dev/null
+++ b/routers/web/repo/setting/public_access.go
@@ -0,0 +1,155 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "net/http"
+ "slices"
+ "strconv"
+
+ "code.gitea.io/gitea/models/perm"
+ "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/services/context"
+)
+
+const tplRepoSettingsPublicAccess templates.TplName = "repo/settings/public_access"
+
+func parsePublicAccessMode(permission string, allowed []string) (ret struct {
+ AnonymousAccessMode, EveryoneAccessMode perm.AccessMode
+},
+) {
+ ret.AnonymousAccessMode = perm.AccessModeNone
+ ret.EveryoneAccessMode = perm.AccessModeNone
+
+ // if site admin forces repositories to be private, then do not allow any other access mode,
+ // otherwise the "force private" setting would be bypassed
+ if setting.Repository.ForcePrivate {
+ return ret
+ }
+ if !slices.Contains(allowed, permission) {
+ return ret
+ }
+ switch permission {
+ case paAnonymousRead:
+ ret.AnonymousAccessMode = perm.AccessModeRead
+ case paEveryoneRead:
+ ret.EveryoneAccessMode = perm.AccessModeRead
+ case paEveryoneWrite:
+ ret.EveryoneAccessMode = perm.AccessModeWrite
+ }
+ return ret
+}
+
+const (
+ paNotSet = "not-set"
+ paAnonymousRead = "anonymous-read"
+ paEveryoneRead = "everyone-read"
+ paEveryoneWrite = "everyone-write"
+)
+
+type repoUnitPublicAccess struct {
+ UnitType unit.Type
+ FormKey string
+ DisplayName string
+ PublicAccessTypes []string
+ UnitPublicAccess string
+}
+
+func repoUnitPublicAccesses(ctx *context.Context) []*repoUnitPublicAccess {
+ accesses := []*repoUnitPublicAccess{
+ {
+ UnitType: unit.TypeCode,
+ DisplayName: ctx.Locale.TrString("repo.code"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypeIssues,
+ DisplayName: ctx.Locale.TrString("issues"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypePullRequests,
+ DisplayName: ctx.Locale.TrString("pull_requests"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypeReleases,
+ DisplayName: ctx.Locale.TrString("repo.releases"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypeWiki,
+ DisplayName: ctx.Locale.TrString("repo.wiki"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead, paEveryoneWrite},
+ },
+ {
+ UnitType: unit.TypeProjects,
+ DisplayName: ctx.Locale.TrString("repo.projects"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypePackages,
+ DisplayName: ctx.Locale.TrString("repo.packages"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ {
+ UnitType: unit.TypeActions,
+ DisplayName: ctx.Locale.TrString("repo.actions"),
+ PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
+ },
+ }
+ for _, ua := range accesses {
+ ua.FormKey = "repo-unit-access-" + strconv.Itoa(int(ua.UnitType))
+ for _, u := range ctx.Repo.Repository.Units {
+ if u.Type == ua.UnitType {
+ ua.UnitPublicAccess = paNotSet
+ switch {
+ case u.EveryoneAccessMode == perm.AccessModeWrite:
+ ua.UnitPublicAccess = paEveryoneWrite
+ case u.EveryoneAccessMode == perm.AccessModeRead:
+ ua.UnitPublicAccess = paEveryoneRead
+ case u.AnonymousAccessMode == perm.AccessModeRead:
+ ua.UnitPublicAccess = paAnonymousRead
+ }
+ break
+ }
+ }
+ }
+ return slices.DeleteFunc(accesses, func(ua *repoUnitPublicAccess) bool {
+ return ua.UnitPublicAccess == ""
+ })
+}
+
+func PublicAccess(ctx *context.Context) {
+ ctx.Data["PageIsSettingsPublicAccess"] = true
+ ctx.Data["RepoUnitPublicAccesses"] = repoUnitPublicAccesses(ctx)
+ ctx.Data["GlobalForcePrivate"] = setting.Repository.ForcePrivate
+ if setting.Repository.ForcePrivate {
+ ctx.Flash.Error(ctx.Tr("form.repository_force_private"), true)
+ }
+ ctx.HTML(http.StatusOK, tplRepoSettingsPublicAccess)
+}
+
+func PublicAccessPost(ctx *context.Context) {
+ accesses := repoUnitPublicAccesses(ctx)
+ for _, ua := range accesses {
+ formVal := ctx.FormString(ua.FormKey)
+ parsed := parsePublicAccessMode(formVal, ua.PublicAccessTypes)
+ err := repo.UpdateRepoUnitPublicAccess(ctx, &repo.RepoUnit{
+ RepoID: ctx.Repo.Repository.ID,
+ Type: ua.UnitType,
+ AnonymousAccessMode: parsed.AnonymousAccessMode,
+ EveryoneAccessMode: parsed.EveryoneAccessMode,
+ })
+ if err != nil {
+ ctx.ServerError("UpdateRepoUnitPublicAccess", err)
+ return
+ }
+ }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(ctx.Repo.Repository.Link() + "/settings/public_access")
+}
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index ac7eb768fa..380fec9d4a 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -6,14 +6,12 @@ package setting
import (
"errors"
- "fmt"
"net/http"
"strings"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
- "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -37,6 +35,8 @@ import (
mirror_service "code.gitea.io/gitea/services/mirror"
repo_service "code.gitea.io/gitea/services/repository"
wiki_service "code.gitea.io/gitea/services/wiki"
+
+ "xorm.io/xorm/convert"
)
const (
@@ -48,15 +48,6 @@ const (
tplDeployKeys templates.TplName = "repo/settings/deploy_keys"
)
-func parseEveryoneAccessMode(permission string, allowed ...perm.AccessMode) perm.AccessMode {
- // if site admin forces repositories to be private, then do not allow any other access mode,
- // otherwise the "force private" setting would be bypassed
- if setting.Repository.ForcePrivate {
- return perm.AccessModeNone
- }
- return perm.ParseAccessMode(permission, allowed...)
-}
-
// SettingsCtxData is a middleware that sets all the general context data for the
// settings template.
func SettingsCtxData(ctx *context.Context) {
@@ -105,8 +96,6 @@ func Settings(ctx *context.Context) {
// SettingsPost response for changes of a repository
func SettingsPost(ctx *context.Context) {
- form := web.GetForm(ctx).(*forms.RepoSettingForm)
-
ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
@@ -119,867 +108,940 @@ func SettingsPost(ctx *context.Context) {
ctx.Data["SigningSettings"] = setting.Repository.Signing
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
- repo := ctx.Repo.Repository
-
switch ctx.FormString("action") {
case "update":
- if ctx.HasError() {
- ctx.HTML(http.StatusOK, tplSettingsOptions)
- return
- }
+ handleSettingsPostUpdate(ctx)
+ case "mirror":
+ handleSettingsPostMirror(ctx)
+ case "mirror-sync":
+ handleSettingsPostMirrorSync(ctx)
+ case "push-mirror-sync":
+ handleSettingsPostPushMirrorSync(ctx)
+ case "push-mirror-update":
+ handleSettingsPostPushMirrorUpdate(ctx)
+ case "push-mirror-remove":
+ handleSettingsPostPushMirrorRemove(ctx)
+ case "push-mirror-add":
+ handleSettingsPostPushMirrorAdd(ctx)
+ case "advanced":
+ handleSettingsPostAdvanced(ctx)
+ case "signing":
+ handleSettingsPostSigning(ctx)
+ case "admin":
+ handleSettingsPostAdmin(ctx)
+ case "admin_index":
+ handleSettingsPostAdminIndex(ctx)
+ case "convert":
+ handleSettingsPostConvert(ctx)
+ case "convert_fork":
+ handleSettingsPostConvertFork(ctx)
+ case "transfer":
+ handleSettingsPostTransfer(ctx)
+ case "cancel_transfer":
+ handleSettingsPostCancelTransfer(ctx)
+ case "delete":
+ handleSettingsPostDelete(ctx)
+ case "delete-wiki":
+ handleSettingsPostDeleteWiki(ctx)
+ case "archive":
+ handleSettingsPostArchive(ctx)
+ case "unarchive":
+ handleSettingsPostUnarchive(ctx)
+ case "visibility":
+ handleSettingsPostVisibility(ctx)
+ default:
+ ctx.NotFound(nil)
+ }
+}
- newRepoName := form.RepoName
- // Check if repository name has been changed.
- if repo.LowerName != strings.ToLower(newRepoName) {
- // Close the GitRepo if open
- if ctx.Repo.GitRepo != nil {
- ctx.Repo.GitRepo.Close()
- ctx.Repo.GitRepo = nil
- }
- if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
+func handleSettingsPostUpdate(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if ctx.HasError() {
+ ctx.HTML(http.StatusOK, tplSettingsOptions)
+ return
+ }
+
+ newRepoName := form.RepoName
+ // Check if repository name has been changed.
+ if repo.LowerName != strings.ToLower(newRepoName) {
+ // Close the GitRepo if open
+ if ctx.Repo.GitRepo != nil {
+ ctx.Repo.GitRepo.Close()
+ ctx.Repo.GitRepo = nil
+ }
+ if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
+ ctx.Data["Err_RepoName"] = true
+ switch {
+ case repo_model.IsErrRepoAlreadyExist(err):
+ ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
+ case db.IsErrNameReserved(err):
+ ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
+ case repo_model.IsErrRepoFilesAlreadyExist(err):
ctx.Data["Err_RepoName"] = true
switch {
- case repo_model.IsErrRepoAlreadyExist(err):
- ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
- case db.IsErrNameReserved(err):
- ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
- case repo_model.IsErrRepoFilesAlreadyExist(err):
- ctx.Data["Err_RepoName"] = true
- switch {
- case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tplSettingsOptions, form)
- case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tplSettingsOptions, form)
- case setting.Repository.AllowDeleteOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tplSettingsOptions, form)
- default:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tplSettingsOptions, form)
- }
- case db.IsErrNamePatternNotAllowed(err):
- ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
+ case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
+ ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tplSettingsOptions, form)
+ case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
+ ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tplSettingsOptions, form)
+ case setting.Repository.AllowDeleteOfUnadoptedRepositories:
+ ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tplSettingsOptions, form)
default:
- ctx.ServerError("ChangeRepositoryName", err)
+ ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tplSettingsOptions, form)
}
- return
+ case db.IsErrNamePatternNotAllowed(err):
+ ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
+ default:
+ ctx.ServerError("ChangeRepositoryName", err)
}
-
- log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
- }
- // In case it's just a case change.
- repo.Name = newRepoName
- repo.LowerName = strings.ToLower(newRepoName)
- repo.Description = form.Description
- repo.Website = form.Website
- repo.IsTemplate = form.Template
-
- // Visibility of forked repository is forced sync with base repository.
- if repo.IsFork {
- form.Private = repo.BaseRepo.IsPrivate || repo.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate
- }
-
- if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
- ctx.ServerError("UpdateRepository", err)
return
}
- log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(repo.Link() + "/settings")
+ log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
+ }
+ // In case it's just a case change.
+ repo.Name = newRepoName
+ repo.LowerName = strings.ToLower(newRepoName)
+ repo.Description = form.Description
+ repo.Website = form.Website
+ repo.IsTemplate = form.Template
+
+ // Visibility of forked repository is forced sync with base repository.
+ if repo.IsFork {
+ form.Private = repo.BaseRepo.IsPrivate || repo.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate
+ }
- case "mirror":
- if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
- ctx.NotFound(nil)
- return
- }
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
+ ctx.ServerError("UpdateRepository", err)
+ return
+ }
+ log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- pullMirror, err := repo_model.GetMirrorByRepoID(ctx, ctx.Repo.Repository.ID)
- if err == repo_model.ErrMirrorNotExist {
- ctx.NotFound(nil)
- return
- }
- if err != nil {
- ctx.ServerError("GetMirrorByRepoID", err)
- return
- }
- // This section doesn't require repo_name/RepoName to be set in the form, don't show it
- // as an error on the UI for this action
- ctx.Data["Err_RepoName"] = nil
-
- interval, err := time.ParseDuration(form.Interval)
- if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
- ctx.Data["Err_Interval"] = true
- ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- pullMirror.EnablePrune = form.EnablePrune
- pullMirror.Interval = interval
- pullMirror.ScheduleNextUpdate()
- if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
- ctx.ServerError("UpdateMirror", err)
- return
- }
+func handleSettingsPostMirror(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
+ ctx.NotFound(nil)
+ return
+ }
- u, err := git.GetRemoteURL(ctx, ctx.Repo.Repository.RepoPath(), pullMirror.GetRemoteName())
- if err != nil {
- ctx.Data["Err_MirrorAddress"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
- if u.User != nil && form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
- form.MirrorPassword, _ = u.User.Password()
- }
+ pullMirror, err := repo_model.GetMirrorByRepoID(ctx, ctx.Repo.Repository.ID)
+ if err == repo_model.ErrMirrorNotExist {
+ ctx.NotFound(nil)
+ return
+ }
+ if err != nil {
+ ctx.ServerError("GetMirrorByRepoID", err)
+ return
+ }
+ // This section doesn't require repo_name/RepoName to be set in the form, don't show it
+ // as an error on the UI for this action
+ ctx.Data["Err_RepoName"] = nil
+
+ interval, err := time.ParseDuration(form.Interval)
+ if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
+ ctx.Data["Err_Interval"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
+ return
+ }
- address, err := git.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
- if err == nil {
- err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
- }
- if err != nil {
- ctx.Data["Err_MirrorAddress"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
+ pullMirror.EnablePrune = form.EnablePrune
+ pullMirror.Interval = interval
+ pullMirror.ScheduleNextUpdate()
+ if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
+ ctx.ServerError("UpdateMirror", err)
+ return
+ }
- if err := mirror_service.UpdateAddress(ctx, pullMirror, address); err != nil {
- ctx.ServerError("UpdateAddress", err)
- return
- }
+ u, err := git.GetRemoteURL(ctx, ctx.Repo.Repository.RepoPath(), pullMirror.GetRemoteName())
+ if err != nil {
+ ctx.Data["Err_MirrorAddress"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
+ return
+ }
+ if u.User != nil && form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
+ form.MirrorPassword, _ = u.User.Password()
+ }
- remoteAddress, err := util.SanitizeURL(form.MirrorAddress)
- if err != nil {
- ctx.Data["Err_MirrorAddress"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
- pullMirror.RemoteAddress = remoteAddress
+ address, err := git.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
+ if err == nil {
+ err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
+ }
+ if err != nil {
+ ctx.Data["Err_MirrorAddress"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
+ return
+ }
- form.LFS = form.LFS && setting.LFS.StartServer
+ if err := mirror_service.UpdateAddress(ctx, pullMirror, address); err != nil {
+ ctx.ServerError("UpdateAddress", err)
+ return
+ }
- if len(form.LFSEndpoint) > 0 {
- ep := lfs.DetermineEndpoint("", form.LFSEndpoint)
- if ep == nil {
- ctx.Data["Err_LFSEndpoint"] = true
- ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tplSettingsOptions, &form)
- return
- }
- err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
- if err != nil {
- ctx.Data["Err_LFSEndpoint"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
- }
+ remoteAddress, err := util.SanitizeURL(form.MirrorAddress)
+ if err != nil {
+ ctx.Data["Err_MirrorAddress"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
+ return
+ }
+ pullMirror.RemoteAddress = remoteAddress
+
+ form.LFS = form.LFS && setting.LFS.StartServer
- pullMirror.LFS = form.LFS
- pullMirror.LFSEndpoint = form.LFSEndpoint
- if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
- ctx.ServerError("UpdateMirror", err)
+ if len(form.LFSEndpoint) > 0 {
+ ep := lfs.DetermineEndpoint("", form.LFSEndpoint)
+ if ep == nil {
+ ctx.Data["Err_LFSEndpoint"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tplSettingsOptions, &form)
return
}
-
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(repo.Link() + "/settings")
-
- case "mirror-sync":
- if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
- ctx.NotFound(nil)
+ err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
+ if err != nil {
+ ctx.Data["Err_LFSEndpoint"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
return
}
+ }
- mirror_service.AddPullMirrorToQueue(repo.ID)
+ pullMirror.LFS = form.LFS
+ pullMirror.LFSEndpoint = form.LFSEndpoint
+ if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
+ ctx.ServerError("UpdateMirror", err)
+ return
+ }
- ctx.Flash.Info(ctx.Tr("repo.settings.pull_mirror_sync_in_progress", repo.OriginalURL))
- ctx.Redirect(repo.Link() + "/settings")
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- case "push-mirror-sync":
- if !setting.Mirror.Enabled {
- ctx.NotFound(nil)
- return
- }
+func handleSettingsPostMirrorSync(ctx *context.Context) {
+ repo := ctx.Repo.Repository
+ if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
+ ctx.NotFound(nil)
+ return
+ }
- m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
- if m == nil {
- ctx.NotFound(nil)
- return
- }
+ mirror_service.AddPullMirrorToQueue(repo.ID)
- mirror_service.AddPushMirrorToQueue(m.ID)
+ ctx.Flash.Info(ctx.Tr("repo.settings.pull_mirror_sync_in_progress", repo.OriginalURL))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- ctx.Flash.Info(ctx.Tr("repo.settings.push_mirror_sync_in_progress", m.RemoteAddress))
- ctx.Redirect(repo.Link() + "/settings")
+func handleSettingsPostPushMirrorSync(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
- case "push-mirror-update":
- if !setting.Mirror.Enabled || repo.IsArchived {
- ctx.NotFound(nil)
- return
- }
+ if !setting.Mirror.Enabled {
+ ctx.NotFound(nil)
+ return
+ }
- // This section doesn't require repo_name/RepoName to be set in the form, don't show it
- // as an error on the UI for this action
- ctx.Data["Err_RepoName"] = nil
+ m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
+ if m == nil {
+ ctx.NotFound(nil)
+ return
+ }
- interval, err := time.ParseDuration(form.PushMirrorInterval)
- if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
- ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &forms.RepoSettingForm{})
- return
- }
+ mirror_service.AddPushMirrorToQueue(m.ID)
- m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
- if m == nil {
- ctx.NotFound(nil)
- return
- }
+ ctx.Flash.Info(ctx.Tr("repo.settings.push_mirror_sync_in_progress", m.RemoteAddress))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- m.Interval = interval
- if err := repo_model.UpdatePushMirrorInterval(ctx, m); err != nil {
- ctx.ServerError("UpdatePushMirrorInterval", err)
- return
- }
- // Background why we are adding it to Queue
- // If we observed its implementation in the context of `push-mirror-sync` where it
- // is evident that pushing to the queue is necessary for updates.
- // So, there are updates within the given interval, it is necessary to update the queue accordingly.
- if !ctx.FormBool("push_mirror_defer_sync") {
- // push_mirror_defer_sync is mainly for testing purpose, we do not really want to sync the push mirror immediately
- mirror_service.AddPushMirrorToQueue(m.ID)
- }
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(repo.Link() + "/settings")
+func handleSettingsPostPushMirrorUpdate(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
- case "push-mirror-remove":
- if !setting.Mirror.Enabled || repo.IsArchived {
- ctx.NotFound(nil)
- return
- }
+ if !setting.Mirror.Enabled || repo.IsArchived {
+ ctx.NotFound(nil)
+ return
+ }
- // This section doesn't require repo_name/RepoName to be set in the form, don't show it
- // as an error on the UI for this action
- ctx.Data["Err_RepoName"] = nil
+ // This section doesn't require repo_name/RepoName to be set in the form, don't show it
+ // as an error on the UI for this action
+ ctx.Data["Err_RepoName"] = nil
- m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
- if m == nil {
- ctx.NotFound(nil)
- return
- }
+ interval, err := time.ParseDuration(form.PushMirrorInterval)
+ if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
+ ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &forms.RepoSettingForm{})
+ return
+ }
- if err := mirror_service.RemovePushMirrorRemote(ctx, m); err != nil {
- ctx.ServerError("RemovePushMirrorRemote", err)
- return
- }
+ m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
+ if m == nil {
+ ctx.NotFound(nil)
+ return
+ }
- if err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
- ctx.ServerError("DeletePushMirrorByID", err)
- return
- }
+ m.Interval = interval
+ if err := repo_model.UpdatePushMirrorInterval(ctx, m); err != nil {
+ ctx.ServerError("UpdatePushMirrorInterval", err)
+ return
+ }
+ // Background why we are adding it to Queue
+ // If we observed its implementation in the context of `push-mirror-sync` where it
+ // is evident that pushing to the queue is necessary for updates.
+ // So, there are updates within the given interval, it is necessary to update the queue accordingly.
+ if !ctx.FormBool("push_mirror_defer_sync") {
+ // push_mirror_defer_sync is mainly for testing purpose, we do not really want to sync the push mirror immediately
+ mirror_service.AddPushMirrorToQueue(m.ID)
+ }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(repo.Link() + "/settings")
+func handleSettingsPostPushMirrorRemove(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
- case "push-mirror-add":
- if setting.Mirror.DisableNewPush || repo.IsArchived {
- ctx.NotFound(nil)
- return
- }
+ if !setting.Mirror.Enabled || repo.IsArchived {
+ ctx.NotFound(nil)
+ return
+ }
- // This section doesn't require repo_name/RepoName to be set in the form, don't show it
- // as an error on the UI for this action
- ctx.Data["Err_RepoName"] = nil
+ // This section doesn't require repo_name/RepoName to be set in the form, don't show it
+ // as an error on the UI for this action
+ ctx.Data["Err_RepoName"] = nil
- interval, err := time.ParseDuration(form.PushMirrorInterval)
- if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
- ctx.Data["Err_PushMirrorInterval"] = true
- ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
- return
- }
+ m, _, _ := repo_model.GetPushMirrorByIDAndRepoID(ctx, form.PushMirrorID, repo.ID)
+ if m == nil {
+ ctx.NotFound(nil)
+ return
+ }
- address, err := git.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
- if err == nil {
- err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
- }
- if err != nil {
- ctx.Data["Err_PushMirrorAddress"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
+ if err := mirror_service.RemovePushMirrorRemote(ctx, m); err != nil {
+ ctx.ServerError("RemovePushMirrorRemote", err)
+ return
+ }
- remoteSuffix, err := util.CryptoRandomString(10)
- if err != nil {
- ctx.ServerError("RandomString", err)
- return
- }
+ if err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
+ ctx.ServerError("DeletePushMirrorByID", err)
+ return
+ }
- remoteAddress, err := util.SanitizeURL(form.PushMirrorAddress)
- if err != nil {
- ctx.Data["Err_PushMirrorAddress"] = true
- handleSettingRemoteAddrError(ctx, err, form)
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- m := &repo_model.PushMirror{
- RepoID: repo.ID,
- Repo: repo,
- RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix),
- SyncOnCommit: form.PushMirrorSyncOnCommit,
- Interval: interval,
- RemoteAddress: remoteAddress,
- }
- if err := db.Insert(ctx, m); err != nil {
- ctx.ServerError("InsertPushMirror", err)
- return
- }
+func handleSettingsPostPushMirrorAdd(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
- if err := mirror_service.AddPushMirrorRemote(ctx, m, address); err != nil {
- if err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
- log.Error("DeletePushMirrors %v", err)
- }
- ctx.ServerError("AddPushMirrorRemote", err)
- return
- }
+ if setting.Mirror.DisableNewPush || repo.IsArchived {
+ ctx.NotFound(nil)
+ return
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(repo.Link() + "/settings")
+ // This section doesn't require repo_name/RepoName to be set in the form, don't show it
+ // as an error on the UI for this action
+ ctx.Data["Err_RepoName"] = nil
- case "advanced":
- var repoChanged bool
- var units []repo_model.RepoUnit
- var deleteUnitTypes []unit_model.Type
+ interval, err := time.ParseDuration(form.PushMirrorInterval)
+ if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
+ ctx.Data["Err_PushMirrorInterval"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
+ return
+ }
- // This section doesn't require repo_name/RepoName to be set in the form, don't show it
- // as an error on the UI for this action
- ctx.Data["Err_RepoName"] = nil
+ address, err := git.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
+ if err == nil {
+ err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
+ }
+ if err != nil {
+ ctx.Data["Err_PushMirrorAddress"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
+ return
+ }
- if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
- repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
- repoChanged = true
- }
+ remoteSuffix, err := util.CryptoRandomString(10)
+ if err != nil {
+ ctx.ServerError("RandomString", err)
+ return
+ }
- if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeCode,
- EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultCodeEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
- })
- } else if !unit_model.TypeCode.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
- }
+ remoteAddress, err := util.SanitizeURL(form.PushMirrorAddress)
+ if err != nil {
+ ctx.Data["Err_PushMirrorAddress"] = true
+ handleSettingRemoteAddrError(ctx, err, form)
+ return
+ }
- if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
- if !validation.IsValidExternalURL(form.ExternalWikiURL) {
- ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
- ctx.Redirect(repo.Link() + "/settings")
- return
- }
+ m := &repo_model.PushMirror{
+ RepoID: repo.ID,
+ Repo: repo,
+ RemoteName: "remote_mirror_" + remoteSuffix,
+ SyncOnCommit: form.PushMirrorSyncOnCommit,
+ Interval: interval,
+ RemoteAddress: remoteAddress,
+ }
+ if err := db.Insert(ctx, m); err != nil {
+ ctx.ServerError("InsertPushMirror", err)
+ return
+ }
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeExternalWiki,
- Config: &repo_model.ExternalWikiConfig{
- ExternalWikiURL: form.ExternalWikiURL,
- },
- })
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
- } else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeWiki,
- Config: new(repo_model.UnitConfig),
- EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
- })
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
- } else {
- if !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
- }
- if !unit_model.TypeWiki.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
- }
+ if err := mirror_service.AddPushMirrorRemote(ctx, m, address); err != nil {
+ if err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
+ log.Error("DeletePushMirrors %v", err)
}
+ ctx.ServerError("AddPushMirrorRemote", err)
+ return
+ }
- if form.DefaultWikiBranch != "" {
- if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil {
- log.Error("ChangeDefaultWikiBranch failed, err: %v", err)
- ctx.Flash.Warning(ctx.Tr("repo.settings.failed_to_change_default_wiki_branch"))
- }
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
- if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
- ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
- ctx.Redirect(repo.Link() + "/settings")
- return
- }
- if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
- ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error"))
- ctx.Redirect(repo.Link() + "/settings")
- return
- }
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeExternalTracker,
- Config: &repo_model.ExternalTrackerConfig{
- ExternalTrackerURL: form.ExternalTrackerURL,
- ExternalTrackerFormat: form.TrackerURLFormat,
- ExternalTrackerStyle: form.TrackerIssueStyle,
- ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
- },
- })
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
- } else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeIssues,
- Config: &repo_model.IssuesConfig{
- EnableTimetracker: form.EnableTimetracker,
- AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
- EnableDependencies: form.EnableIssueDependencies,
- },
- EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultIssuesEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
- })
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
- } else {
- if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
- }
- if !unit_model.TypeIssues.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
- }
+func newRepoUnit(repo *repo_model.Repository, unitType unit_model.Type, config convert.Conversion) repo_model.RepoUnit {
+ repoUnit := repo_model.RepoUnit{RepoID: repo.ID, Type: unitType, Config: config}
+ for _, u := range repo.Units {
+ if u.Type == unitType {
+ repoUnit.EveryoneAccessMode = u.EveryoneAccessMode
+ repoUnit.AnonymousAccessMode = u.AnonymousAccessMode
}
+ }
+ return repoUnit
+}
- if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeProjects,
- Config: &repo_model.ProjectsConfig{
- ProjectsMode: repo_model.ProjectsMode(form.ProjectsMode),
- },
- })
- } else if !unit_model.TypeProjects.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
- }
+func handleSettingsPostAdvanced(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ var repoChanged bool
+ var units []repo_model.RepoUnit
+ var deleteUnitTypes []unit_model.Type
- if form.EnableReleases && !unit_model.TypeReleases.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeReleases,
- })
- } else if !unit_model.TypeReleases.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeReleases)
- }
+ // This section doesn't require repo_name/RepoName to be set in the form, don't show it
+ // as an error on the UI for this action
+ ctx.Data["Err_RepoName"] = nil
+
+ if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
+ repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
+ repoChanged = true
+ }
+
+ if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeCode, nil))
+ } else if !unit_model.TypeCode.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
+ }
- if form.EnablePackages && !unit_model.TypePackages.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypePackages,
- })
- } else if !unit_model.TypePackages.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePackages)
+ if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
+ if !validation.IsValidExternalURL(form.ExternalWikiURL) {
+ ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
+ ctx.Redirect(repo.Link() + "/settings")
+ return
}
- if form.EnableActions && !unit_model.TypeActions.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeActions,
- })
- } else if !unit_model.TypeActions.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeActions)
+ units = append(units, newRepoUnit(repo, unit_model.TypeExternalWiki, &repo_model.ExternalWikiConfig{
+ ExternalWikiURL: form.ExternalWikiURL,
+ }))
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
+ } else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeWiki, new(repo_model.UnitConfig)))
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
+ } else {
+ if !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
+ }
+ if !unit_model.TypeWiki.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
}
+ }
- if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypePullRequests,
- Config: &repo_model.PullRequestsConfig{
- IgnoreWhitespaceConflicts: form.PullsIgnoreWhitespace,
- AllowMerge: form.PullsAllowMerge,
- AllowRebase: form.PullsAllowRebase,
- AllowRebaseMerge: form.PullsAllowRebaseMerge,
- AllowSquash: form.PullsAllowSquash,
- AllowFastForwardOnly: form.PullsAllowFastForwardOnly,
- AllowManualMerge: form.PullsAllowManualMerge,
- AutodetectManualMerge: form.EnableAutodetectManualMerge,
- AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
- DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
- DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
- DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
- },
- })
- } else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
- deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
+ if form.DefaultWikiBranch != "" {
+ if err := wiki_service.ChangeDefaultWikiBranch(ctx, repo, form.DefaultWikiBranch); err != nil {
+ log.Error("ChangeDefaultWikiBranch failed, err: %v", err)
+ ctx.Flash.Warning(ctx.Tr("repo.settings.failed_to_change_default_wiki_branch"))
}
+ }
- if len(units) == 0 {
- ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
+ if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
+ ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
+ ctx.Redirect(repo.Link() + "/settings")
return
}
-
- if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
- ctx.ServerError("UpdateRepositoryUnits", err)
+ if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
+ ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error"))
+ ctx.Redirect(repo.Link() + "/settings")
return
}
- if repoChanged {
- if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
- ctx.ServerError("UpdateRepository", err)
- return
- }
+ units = append(units, newRepoUnit(repo, unit_model.TypeExternalTracker, &repo_model.ExternalTrackerConfig{
+ ExternalTrackerURL: form.ExternalTrackerURL,
+ ExternalTrackerFormat: form.TrackerURLFormat,
+ ExternalTrackerStyle: form.TrackerIssueStyle,
+ ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
+ }))
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
+ } else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeIssues, &repo_model.IssuesConfig{
+ EnableTimetracker: form.EnableTimetracker,
+ AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
+ EnableDependencies: form.EnableIssueDependencies,
+ }))
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
+ } else {
+ if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
}
- log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ if !unit_model.TypeIssues.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
+ }
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeProjects, &repo_model.ProjectsConfig{
+ ProjectsMode: repo_model.ProjectsMode(form.ProjectsMode),
+ }))
+ } else if !unit_model.TypeProjects.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
+ }
- case "signing":
- changed := false
- trustModel := repo_model.ToTrustModel(form.TrustModel)
- if trustModel != repo.TrustModel {
- repo.TrustModel = trustModel
- changed = true
- }
+ if form.EnableReleases && !unit_model.TypeReleases.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeReleases, nil))
+ } else if !unit_model.TypeReleases.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeReleases)
+ }
- if changed {
- if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
- ctx.ServerError("UpdateRepository", err)
- return
- }
- }
- log.Trace("Repository signing settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ if form.EnablePackages && !unit_model.TypePackages.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypePackages, nil))
+ } else if !unit_model.TypePackages.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePackages)
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ if form.EnableActions && !unit_model.TypeActions.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypeActions, nil))
+ } else if !unit_model.TypeActions.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeActions)
+ }
- case "admin":
- if !ctx.Doer.IsAdmin {
- ctx.HTTPError(http.StatusForbidden)
- return
- }
+ if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
+ units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, &repo_model.PullRequestsConfig{
+ IgnoreWhitespaceConflicts: form.PullsIgnoreWhitespace,
+ AllowMerge: form.PullsAllowMerge,
+ AllowRebase: form.PullsAllowRebase,
+ AllowRebaseMerge: form.PullsAllowRebaseMerge,
+ AllowSquash: form.PullsAllowSquash,
+ AllowFastForwardOnly: form.PullsAllowFastForwardOnly,
+ AllowManualMerge: form.PullsAllowManualMerge,
+ AutodetectManualMerge: form.EnableAutodetectManualMerge,
+ AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
+ DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
+ DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
+ DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
+ }))
+ } else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
+ deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
+ }
- if repo.IsFsckEnabled != form.EnableHealthCheck {
- repo.IsFsckEnabled = form.EnableHealthCheck
- }
+ if len(units) == 0 {
+ ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
+ }
+ if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
+ ctx.ServerError("UpdateRepositoryUnits", err)
+ return
+ }
+ if repoChanged {
if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
ctx.ServerError("UpdateRepository", err)
return
}
+ }
+ log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+func handleSettingsPostSigning(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ changed := false
+ trustModel := repo_model.ToTrustModel(form.TrustModel)
+ if trustModel != repo.TrustModel {
+ repo.TrustModel = trustModel
+ changed = true
+ }
- case "admin_index":
- if !ctx.Doer.IsAdmin {
- ctx.HTTPError(http.StatusForbidden)
+ if changed {
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
+ ctx.ServerError("UpdateRepository", err)
return
}
+ }
+ log.Trace("Repository signing settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- switch form.RequestReindexType {
- case "stats":
- if err := stats.UpdateRepoIndexer(ctx.Repo.Repository); err != nil {
- ctx.ServerError("UpdateStatsRepondexer", err)
- return
- }
- case "code":
- if !setting.Indexer.RepoIndexerEnabled {
- ctx.HTTPError(http.StatusForbidden)
- return
- }
- code.UpdateRepoIndexer(ctx.Repo.Repository)
- default:
- ctx.NotFound(nil)
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- log.Trace("Repository reindex for %s requested: %s/%s", form.RequestReindexType, ctx.Repo.Owner.Name, repo.Name)
+func handleSettingsPostAdmin(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Doer.IsAdmin {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.reindex_requested"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ if repo.IsFsckEnabled != form.EnableHealthCheck {
+ repo.IsFsckEnabled = form.EnableHealthCheck
+ }
- case "convert":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- if repo.Name != form.RepoName {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
- return
- }
+ if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
+ ctx.ServerError("UpdateRepository", err)
+ return
+ }
- if !repo.IsMirror {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- repo.IsMirror = false
+ log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- if _, err := repo_service.CleanUpMigrateInfo(ctx, repo); err != nil {
- ctx.ServerError("CleanUpMigrateInfo", err)
- return
- } else if err = repo_model.DeleteMirrorByRepoID(ctx, ctx.Repo.Repository.ID); err != nil {
- ctx.ServerError("DeleteMirrorByRepoID", err)
- return
- }
- log.Trace("Repository converted from mirror to regular: %s", repo.FullName())
- ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed"))
- ctx.Redirect(repo.Link())
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- case "convert_fork":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- if err := repo.LoadOwner(ctx); err != nil {
- ctx.ServerError("Convert Fork", err)
+func handleSettingsPostAdminIndex(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Doer.IsAdmin {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
+
+ switch form.RequestReindexType {
+ case "stats":
+ if err := stats.UpdateRepoIndexer(ctx.Repo.Repository); err != nil {
+ ctx.ServerError("UpdateStatsRepondexer", err)
return
}
- if repo.Name != form.RepoName {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ case "code":
+ if !setting.Indexer.RepoIndexerEnabled {
+ ctx.HTTPError(http.StatusForbidden)
return
}
+ code.UpdateRepoIndexer(ctx.Repo.Repository)
+ default:
+ ctx.NotFound(nil)
+ return
+ }
- if !repo.IsFork {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
+ log.Trace("Repository reindex for %s requested: %s/%s", form.RequestReindexType, ctx.Repo.Owner.Name, repo.Name)
- if !ctx.Repo.Owner.CanCreateRepo() {
- maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
- msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
- ctx.Flash.Error(msg)
- ctx.Redirect(repo.Link() + "/settings")
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.reindex_requested"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- if err := repo_service.ConvertForkToNormalRepository(ctx, repo); err != nil {
- log.Error("Unable to convert repository %-v from fork. Error: %v", repo, err)
- ctx.ServerError("Convert Fork", err)
- return
- }
+func handleSettingsPostConvert(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ if repo.Name != form.RepoName {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ return
+ }
- log.Trace("Repository converted from fork to regular: %s", repo.FullName())
- ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed"))
- ctx.Redirect(repo.Link())
+ if !repo.IsMirror {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ repo.IsMirror = false
- case "transfer":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- if repo.Name != form.RepoName {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
- return
- }
+ if _, err := repo_service.CleanUpMigrateInfo(ctx, repo); err != nil {
+ ctx.ServerError("CleanUpMigrateInfo", err)
+ return
+ } else if err = repo_model.DeleteMirrorByRepoID(ctx, ctx.Repo.Repository.ID); err != nil {
+ ctx.ServerError("DeleteMirrorByRepoID", err)
+ return
+ }
+ log.Trace("Repository converted from mirror to regular: %s", repo.FullName())
+ ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed"))
+ ctx.Redirect(repo.Link())
+}
- newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name"))
- if err != nil {
- if user_model.IsErrUserNotExist(err) {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
- return
- }
- ctx.ServerError("IsUserExist", err)
- return
- }
+func handleSettingsPostConvertFork(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ if err := repo.LoadOwner(ctx); err != nil {
+ ctx.ServerError("Convert Fork", err)
+ return
+ }
+ if repo.Name != form.RepoName {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ return
+ }
- if newOwner.Type == user_model.UserTypeOrganization {
- if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) {
- // The user shouldn't know about this organization
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
- return
- }
- }
+ if !repo.IsFork {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
- // Close the GitRepo if open
- if ctx.Repo.GitRepo != nil {
- ctx.Repo.GitRepo.Close()
- ctx.Repo.GitRepo = nil
- }
+ if !ctx.Repo.Owner.CanCreateRepo() {
+ maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
+ msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
+ ctx.Flash.Error(msg)
+ ctx.Redirect(repo.Link() + "/settings")
+ return
+ }
- oldFullname := repo.FullName()
- if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
- if repo_model.IsErrRepoAlreadyExist(err) {
- ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
- } else if repo_model.IsErrRepoTransferInProgress(err) {
- ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
- } else if errors.Is(err, user_model.ErrBlockedUser) {
- ctx.RenderWithErr(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil)
- } else {
- ctx.ServerError("TransferOwnership", err)
- }
+ if err := repo_service.ConvertForkToNormalRepository(ctx, repo); err != nil {
+ log.Error("Unable to convert repository %-v from fork. Error: %v", repo, err)
+ ctx.ServerError("Convert Fork", err)
+ return
+ }
- return
- }
+ log.Trace("Repository converted from fork to regular: %s", repo.FullName())
+ ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed"))
+ ctx.Redirect(repo.Link())
+}
- if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
- log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
- ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
- } else {
- log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName())
- ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
- }
- ctx.Redirect(repo.Link() + "/settings")
+func handleSettingsPostTransfer(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ if repo.Name != form.RepoName {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ return
+ }
- case "cancel_transfer":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
+ newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name"))
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
return
}
+ ctx.ServerError("IsUserExist", err)
+ return
+ }
- repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
- if err != nil {
- if repo_model.IsErrNoPendingTransfer(err) {
- ctx.Flash.Error("repo.settings.transfer_abort_invalid")
- ctx.Redirect(repo.Link() + "/settings")
- } else {
- ctx.ServerError("GetPendingRepositoryTransfer", err)
- }
+ if newOwner.Type == user_model.UserTypeOrganization {
+ if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) {
+ // The user shouldn't know about this organization
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
return
}
+ }
- if err := repo_service.CancelRepositoryTransfer(ctx, repoTransfer, ctx.Doer); err != nil {
- ctx.ServerError("CancelRepositoryTransfer", err)
- return
+ // Close the GitRepo if open
+ if ctx.Repo.GitRepo != nil {
+ ctx.Repo.GitRepo.Close()
+ ctx.Repo.GitRepo = nil
+ }
+
+ oldFullname := repo.FullName()
+ if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
+ if repo_model.IsErrRepoAlreadyExist(err) {
+ ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
+ } else if repo_model.IsErrRepoTransferInProgress(err) {
+ ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
+ } else if repo_service.IsRepositoryLimitReached(err) {
+ limit := err.(repo_service.LimitReachedError).Limit
+ ctx.RenderWithErr(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit), tplSettingsOptions, nil)
+ } else if errors.Is(err, user_model.ErrBlockedUser) {
+ ctx.RenderWithErr(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil)
+ } else {
+ ctx.ServerError("TransferOwnership", err)
}
- log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
- ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
- ctx.Redirect(repo.Link() + "/settings")
+ return
+ }
- case "delete":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- if repo.Name != form.RepoName {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
- return
- }
+ if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
+ log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
+ ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
+ } else {
+ log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName())
+ ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
+ }
+ ctx.Redirect(repo.Link() + "/settings")
+}
- // Close the gitrepository before doing this.
- if ctx.Repo.GitRepo != nil {
- ctx.Repo.GitRepo.Close()
- }
+func handleSettingsPostCancelTransfer(ctx *context.Context) {
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
- if err := repo_service.DeleteRepository(ctx, ctx.Doer, ctx.Repo.Repository, true); err != nil {
- ctx.ServerError("DeleteRepository", err)
- return
+ repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
+ if err != nil {
+ if repo_model.IsErrNoPendingTransfer(err) {
+ ctx.Flash.Error("repo.settings.transfer_abort_invalid")
+ ctx.Redirect(repo.Link() + "/settings")
+ } else {
+ ctx.ServerError("GetPendingRepositoryTransfer", err)
}
- log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ return
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
- ctx.Redirect(ctx.Repo.Owner.DashboardLink())
+ if err := repo_service.CancelRepositoryTransfer(ctx, repoTransfer, ctx.Doer); err != nil {
+ ctx.ServerError("CancelRepositoryTransfer", err)
+ return
+ }
- case "delete-wiki":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusNotFound)
- return
- }
- if repo.Name != form.RepoName {
- ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
- return
- }
+ log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
+ ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
+ ctx.Redirect(repo.Link() + "/settings")
+}
- err := wiki_service.DeleteWiki(ctx, repo)
- if err != nil {
- log.Error("Delete Wiki: %v", err.Error())
- }
- log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+func handleSettingsPostDelete(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ if repo.Name != form.RepoName {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ return
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ // Close the gitrepository before doing this.
+ if ctx.Repo.GitRepo != nil {
+ ctx.Repo.GitRepo.Close()
+ }
- case "archive":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusForbidden)
- return
- }
+ if err := repo_service.DeleteRepository(ctx, ctx.Doer, ctx.Repo.Repository, true); err != nil {
+ ctx.ServerError("DeleteRepository", err)
+ return
+ }
+ log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- if repo.IsMirror {
- ctx.Flash.Error(ctx.Tr("repo.settings.archive.error_ismirror"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
+ ctx.Redirect(ctx.Repo.Owner.DashboardLink())
+}
- if err := repo_model.SetArchiveRepoState(ctx, repo, true); err != nil {
- log.Error("Tried to archive a repo: %s", err)
- ctx.Flash.Error(ctx.Tr("repo.settings.archive.error"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
- return
- }
+func handleSettingsPostDeleteWiki(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusNotFound)
+ return
+ }
+ if repo.Name != form.RepoName {
+ ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
+ return
+ }
- if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
- log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
- }
+ err := wiki_service.DeleteWiki(ctx, repo)
+ if err != nil {
+ log.Error("Delete Wiki: %v", err.Error())
+ }
+ log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- // update issue indexer
- issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
+ ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
+func handleSettingsPostArchive(ctx *context.Context) {
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
- log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ if repo.IsMirror {
+ ctx.Flash.Error(ctx.Tr("repo.settings.archive.error_ismirror"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
+ }
- case "unarchive":
- if !ctx.Repo.IsOwner() {
- ctx.HTTPError(http.StatusForbidden)
- return
- }
+ if err := repo_model.SetArchiveRepoState(ctx, repo, true); err != nil {
+ log.Error("Tried to archive a repo: %s", err)
+ ctx.Flash.Error(ctx.Tr("repo.settings.archive.error"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
+ }
- if err := repo_model.SetArchiveRepoState(ctx, repo, false); err != nil {
- log.Error("Tried to unarchive a repo: %s", err)
- ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
- return
- }
+ if err := actions_service.CleanRepoScheduleTasks(ctx, repo); err != nil {
+ log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
+ }
- if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) {
- if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
- log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
- }
- }
+ // update issue indexer
+ issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
- // update issue indexer
- issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
+ ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
- ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
+ log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
+
+func handleSettingsPostUnarchive(ctx *context.Context) {
+ repo := ctx.Repo.Repository
+ if !ctx.Repo.IsOwner() {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
- log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ if err := repo_model.SetArchiveRepoState(ctx, repo, false); err != nil {
+ log.Error("Tried to unarchive a repo: %s", err)
+ ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
+ }
- case "visibility":
- if repo.IsFork {
- ctx.Flash.Error(ctx.Tr("repo.settings.visibility.fork_error"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
- return
+ if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) {
+ if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
+ log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
}
+ }
- var err error
+ // update issue indexer
+ issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
- // when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
- if setting.Repository.ForcePrivate && repo.IsPrivate && !ctx.Doer.IsAdmin {
- ctx.RenderWithErr(ctx.Tr("form.repository_force_private"), tplSettingsOptions, form)
- return
- }
+ ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
- if repo.IsPrivate {
- err = repo_service.MakeRepoPublic(ctx, repo)
- } else {
- err = repo_service.MakeRepoPrivate(ctx, repo)
- }
+ log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+}
- if err != nil {
- log.Error("Tried to change the visibility of the repo: %s", err)
- ctx.Flash.Error(ctx.Tr("repo.settings.visibility.error"))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
- return
- }
+func handleSettingsPostVisibility(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.RepoSettingForm)
+ repo := ctx.Repo.Repository
+ if repo.IsFork {
+ ctx.Flash.Error(ctx.Tr("repo.settings.visibility.fork_error"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
+ }
- ctx.Flash.Success(ctx.Tr("repo.settings.visibility.success"))
+ var err error
- log.Trace("Repository visibility changed: %s/%s", ctx.Repo.Owner.Name, repo.Name)
- ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ // when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
+ if setting.Repository.ForcePrivate && repo.IsPrivate && !ctx.Doer.IsAdmin {
+ ctx.RenderWithErr(ctx.Tr("form.repository_force_private"), tplSettingsOptions, form)
+ return
+ }
- default:
- ctx.NotFound(nil)
+ if repo.IsPrivate {
+ err = repo_service.MakeRepoPublic(ctx, repo)
+ } else {
+ err = repo_service.MakeRepoPrivate(ctx, repo)
+ }
+
+ if err != nil {
+ log.Error("Tried to change the visibility of the repo: %s", err)
+ ctx.Flash.Error(ctx.Tr("repo.settings.visibility.error"))
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
+ return
}
+
+ ctx.Flash.Success(ctx.Tr("repo.settings.visibility.success"))
+
+ log.Trace("Repository visibility changed: %s/%s", ctx.Repo.Owner.Name, repo.Name)
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings")
}
func handleSettingRemoteAddrError(ctx *context.Context, err error, form *forms.RepoSettingForm) {
diff --git a/routers/web/repo/setting/settings_test.go b/routers/web/repo/setting/settings_test.go
index ad33dac514..ba6b0d1efc 100644
--- a/routers/web/repo/setting/settings_test.go
+++ b/routers/web/repo/setting/settings_test.go
@@ -54,7 +54,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) {
}
web.SetForm(ctx, &addKeyForm)
DeployKeysPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title,
@@ -84,7 +84,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) {
}
web.SetForm(ctx, &addKeyForm)
DeployKeysPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title,
@@ -121,7 +121,7 @@ func TestCollaborationPost(t *testing.T) {
CollaborationPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
exists, err := repo_model.IsCollaborator(ctx, re.ID, 4)
assert.NoError(t, err)
@@ -147,7 +147,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) {
CollaborationPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -179,7 +179,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) {
CollaborationPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
exists, err := repo_model.IsCollaborator(ctx, re.ID, 4)
assert.NoError(t, err)
@@ -188,7 +188,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) {
// Try adding the same collaborator again
CollaborationPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -210,7 +210,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) {
CollaborationPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -250,7 +250,7 @@ func TestAddTeamPost(t *testing.T) {
AddTeamPost(ctx)
assert.True(t, repo_service.HasRepository(db.DefaultContext, team, re.ID))
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.Empty(t, ctx.Flash.ErrorMsg)
}
@@ -290,7 +290,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) {
AddTeamPost(ctx)
assert.False(t, repo_service.HasRepository(db.DefaultContext, team, re.ID))
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -331,7 +331,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) {
AddTeamPost(ctx)
assert.True(t, repo_service.HasRepository(db.DefaultContext, team, re.ID))
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -364,7 +364,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) {
ctx.Repo = repo
AddTeamPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go
index d538406035..c6f462bccf 100644
--- a/routers/web/repo/view_home.go
+++ b/routers/web/repo/view_home.go
@@ -76,7 +76,7 @@ func prepareOpenWithEditorApps(ctx *context.Context) {
schema, _, _ := strings.Cut(app.OpenURL, ":")
var iconHTML template.HTML
if schema == "vscode" || schema == "vscodium" || schema == "jetbrains" {
- iconHTML = svg.RenderHTML(fmt.Sprintf("gitea-%s", schema), 16)
+ iconHTML = svg.RenderHTML("gitea-"+schema, 16)
} else {
iconHTML = svg.RenderHTML("gitea-git", 16) // TODO: it could support user's customized icon in the future
}
@@ -269,7 +269,7 @@ func handleRepoEmptyOrBroken(ctx *context.Context) {
} else if reallyEmpty {
showEmpty = true // the repo is really empty
updateContextRepoEmptyAndStatus(ctx, true, repo_model.RepositoryReady)
- } else if branches, _, _ := ctx.Repo.GitRepo.GetBranches(0, 1); len(branches) == 0 {
+ } else if branches, _, _ := ctx.Repo.GitRepo.GetBranchNames(0, 1); len(branches) == 0 {
showEmpty = true // it is not really empty, but there is no branch
// at the moment, other repo units like "actions" are not able to handle such case,
// so we just mark the repo as empty to prevent from displaying these units.
@@ -343,12 +343,25 @@ func prepareHomeTreeSideBarSwitch(ctx *context.Context) {
ctx.Data["UserSettingCodeViewShowFileTree"] = showFileTree
}
+func redirectSrcToRaw(ctx *context.Context) bool {
+ // GitHub redirects a tree path with "?raw=1" to the raw path
+ // It is useful to embed some raw contents into markdown files,
+ // then viewing the markdown in "src" path could embed the raw content correctly.
+ if ctx.Repo.TreePath != "" && ctx.FormBool("raw") {
+ ctx.Redirect(ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath))
+ return true
+ }
+ return false
+}
+
// Home render repository home page
func Home(ctx *context.Context) {
if handleRepoHomeFeed(ctx) {
return
}
-
+ if redirectSrcToRaw(ctx) {
+ return
+ }
// Check whether the repo is viewable: not in migration, and the code unit should be enabled
// Ideally the "feed" logic should be after this, but old code did so, so keep it as-is.
checkHomeCodeViewable(ctx)
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 0f8e1223c6..d70760bc36 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -7,7 +7,6 @@ package repo
import (
"bytes"
gocontext "context"
- "fmt"
"io"
"net/http"
"net/url"
@@ -96,7 +95,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
}
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
- wikiGitRepo, errGitRepo := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ wikiGitRepo, errGitRepo := gitrepo.OpenRepository(ctx, ctx.Repo.Repository.WikiStorageRepo())
if errGitRepo != nil {
ctx.ServerError("OpenRepository", errGitRepo)
return nil, nil, errGitRepo
@@ -105,7 +104,7 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err
commit, errCommit := wikiGitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultWikiBranch)
if git.IsErrNotExist(errCommit) {
// if the default branch recorded in database is out of sync, then re-sync it
- gitRepoDefaultBranch, errBranch := gitrepo.GetWikiDefaultBranch(ctx, ctx.Repo.Repository)
+ gitRepoDefaultBranch, errBranch := gitrepo.GetDefaultBranch(ctx, ctx.Repo.Repository.WikiStorageRepo())
if errBranch != nil {
return wikiGitRepo, nil, errBranch
}
@@ -581,7 +580,7 @@ func Wiki(ctx *context.Context) {
wikiPath := entry.Name()
if markup.DetectMarkupTypeByFileName(wikiPath) != markdown.MarkupName {
ext := strings.ToUpper(filepath.Ext(wikiPath))
- ctx.Data["FormatWarning"] = fmt.Sprintf("%s rendering is not supported at the moment. Rendered as Markdown.", ext)
+ ctx.Data["FormatWarning"] = ext + " rendering is not supported at the moment. Rendered as Markdown."
}
// Get last change information.
lastCommit, err := wikiRepo.GetCommitByPath(wikiPath)
diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go
index 99114c93e0..b5dfa9f856 100644
--- a/routers/web/repo/wiki_test.go
+++ b/routers/web/repo/wiki_test.go
@@ -29,7 +29,7 @@ const (
)
func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.WebPath) *git.TreeEntry {
- wikiRepo, err := gitrepo.OpenWikiRepository(git.DefaultContext, repo)
+ wikiRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo.WikiStorageRepo())
assert.NoError(t, err)
defer wikiRepo.Close()
commit, err := wikiRepo.GetBranchCommit("master")
@@ -71,7 +71,7 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas any) {
require.Len(t, pageMetas, len(expectedNames))
for i, pageMeta := range pageMetas {
- assert.EqualValues(t, expectedNames[i], pageMeta.Name)
+ assert.Equal(t, expectedNames[i], pageMeta.Name)
}
}
@@ -82,7 +82,7 @@ func TestWiki(t *testing.T) {
ctx.SetPathParam("*", "Home")
contexttest.LoadRepo(t, ctx, 1)
Wiki(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, "Home", ctx.Data["Title"])
assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"])
@@ -90,7 +90,7 @@ func TestWiki(t *testing.T) {
ctx.SetPathParam("*", "jpeg.jpg")
contexttest.LoadRepo(t, ctx, 1)
Wiki(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.Equal(t, "/user2/repo1/wiki/raw/jpeg.jpg", ctx.Resp.Header().Get("Location"))
}
@@ -100,7 +100,7 @@ func TestWikiPages(t *testing.T) {
ctx, _ := contexttest.MockContext(t, "user2/repo1/wiki/?action=_pages")
contexttest.LoadRepo(t, ctx, 1)
WikiPages(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"])
}
@@ -111,7 +111,7 @@ func TestNewWiki(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
contexttest.LoadRepo(t, ctx, 1)
NewWiki(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, ctx.Tr("repo.wiki.new_page"), ctx.Data["Title"])
}
@@ -131,7 +131,7 @@ func TestNewWikiPost(t *testing.T) {
Message: message,
})
NewWikiPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assertWikiExists(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title))
assert.Equal(t, content, wikiContent(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title)))
}
@@ -149,7 +149,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) {
Message: message,
})
NewWikiPost(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, ctx.Tr("repo.wiki.reserved_page", "_edit"), ctx.Flash.ErrorMsg)
assertWikiNotExists(t, ctx.Repo.Repository, "_edit")
}
@@ -162,7 +162,7 @@ func TestEditWiki(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
contexttest.LoadRepo(t, ctx, 1)
EditWiki(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, "Home", ctx.Data["Title"])
assert.Equal(t, wikiContent(t, ctx.Repo.Repository, "Home"), ctx.Data["content"])
@@ -171,7 +171,7 @@ func TestEditWiki(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
contexttest.LoadRepo(t, ctx, 1)
EditWiki(ctx)
- assert.EqualValues(t, http.StatusForbidden, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusForbidden, ctx.Resp.WrittenStatus())
}
func TestEditWikiPost(t *testing.T) {
@@ -190,7 +190,7 @@ func TestEditWikiPost(t *testing.T) {
Message: message,
})
EditWikiPost(ctx)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assertWikiExists(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title))
assert.Equal(t, content, wikiContent(t, ctx.Repo.Repository, wiki_service.UserTitleToWebPath("", title)))
if title != "Home" {
@@ -206,7 +206,7 @@ func TestDeleteWikiPagePost(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
contexttest.LoadRepo(t, ctx, 1)
DeleteWikiPagePost(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assertWikiNotExists(t, ctx.Repo.Repository, "Home")
}
@@ -228,10 +228,10 @@ func TestWikiRaw(t *testing.T) {
contexttest.LoadRepo(t, ctx, 1)
WikiRaw(ctx)
if filetype == "" {
- assert.EqualValues(t, http.StatusNotFound, ctx.Resp.WrittenStatus(), "filepath: %s", filepath)
+ assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus(), "filepath: %s", filepath)
} else {
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus(), "filepath: %s", filepath)
- assert.EqualValues(t, filetype, ctx.Resp.Header().Get("Content-Type"), "filepath: %s", filepath)
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus(), "filepath: %s", filepath)
+ assert.Equal(t, filetype, ctx.Resp.Header().Get("Content-Type"), "filepath: %s", filepath)
}
}
}
diff --git a/routers/web/shared/user/helper.go b/routers/web/shared/user/helper.go
index b82181a1df..3fc39fd3ab 100644
--- a/routers/web/shared/user/helper.go
+++ b/routers/web/shared/user/helper.go
@@ -8,9 +8,7 @@ import (
"slices"
"strconv"
- "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/optional"
)
func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
@@ -34,19 +32,20 @@ func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
// So it's better to make it work like GitHub: users could input username directly.
// Since it only converts the username to ID directly and is only used internally (to search issues), so no permission check is needed.
// Return values:
-// * nil: no filter
-// * some(id): match the id, the id could be -1 to match the issues without assignee
-// * some(NonExistingID): match no issue (due to the user doesn't exist)
-func GetFilterUserIDByName(ctx context.Context, name string) optional.Option[int64] {
+// * "": no filter
+// * "{the-id}": match the id
+// * "(none)": match no issue (due to the user doesn't exist)
+func GetFilterUserIDByName(ctx context.Context, name string) string {
if name == "" {
- return optional.None[int64]()
+ return ""
}
u, err := user.GetUserByName(ctx, name)
if err != nil {
if id, err := strconv.ParseInt(name, 10, 64); err == nil {
- return optional.Some(id)
+ return strconv.FormatInt(id, 10)
}
- return optional.Some(db.NonExistingID)
+ // The "(none)" is for internal usage only: when doer tries to search non-existing user, use "(none)" to return empty result.
+ return "(none)"
}
- return optional.Some(u.ID)
+ return strconv.FormatInt(u.ID, 10)
}
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 8e030a62a2..77f9cb8cca 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -119,7 +119,7 @@ func Dashboard(ctx *context.Context) {
ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
}
- feeds, count, err := feed_service.GetFeeds(ctx, activities_model.GetFeedsOptions{
+ feeds, count, err := feed_service.GetFeedsForDashboard(ctx, activities_model.GetFeedsOptions{
RequestedUser: ctxUser,
RequestedTeam: ctx.Org.Team,
Actor: ctx.Doer,
@@ -137,11 +137,10 @@ func Dashboard(ctx *context.Context) {
return
}
- ctx.Data["Feeds"] = feeds
-
- pager := context.NewPagination(int(count), setting.UI.FeedPagingNum, page, 5)
+ pager := context.NewPagination(count, setting.UI.FeedPagingNum, page, 5).WithCurRows(len(feeds))
pager.AddParamFromRequest(ctx.Req)
ctx.Data["Page"] = pager
+ ctx.Data["Feeds"] = feeds
ctx.HTML(http.StatusOK, tplDashboard)
}
@@ -501,9 +500,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
case issues_model.FilterModeAll:
case issues_model.FilterModeYourRepositories:
case issues_model.FilterModeAssign:
- opts.AssigneeID = optional.Some(ctx.Doer.ID)
+ opts.AssigneeID = strconv.FormatInt(ctx.Doer.ID, 10)
case issues_model.FilterModeCreate:
- opts.PosterID = optional.Some(ctx.Doer.ID)
+ opts.PosterID = strconv.FormatInt(ctx.Doer.ID, 10)
case issues_model.FilterModeMention:
opts.MentionedID = ctx.Doer.ID
case issues_model.FilterModeReviewRequested:
@@ -618,9 +617,10 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
return 0
}
reviewTyp := issues_model.ReviewTypeApprove
- if typ == "reject" {
+ switch typ {
+ case "reject":
reviewTyp = issues_model.ReviewTypeReject
- } else if typ == "waiting" {
+ case "waiting":
reviewTyp = issues_model.ReviewTypeRequest
}
for _, count := range counts {
@@ -699,7 +699,7 @@ func ShowGPGKeys(ctx *context.Context) {
headers := make(map[string]string)
if len(failedEntitiesID) > 0 { // If some key need re-import to be exported
- headers["Note"] = fmt.Sprintf("The keys with the following IDs couldn't be exported and need to be reuploaded %s", strings.Join(failedEntitiesID, ", "))
+ headers["Note"] = "The keys with the following IDs couldn't be exported and need to be reuploaded " + strings.Join(failedEntitiesID, ", ")
} else if len(entities) == 0 {
headers["Note"] = "This user hasn't uploaded any GPG keys."
}
@@ -792,9 +792,9 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
case issues_model.FilterModeYourRepositories:
openClosedOpts.AllPublic = false
case issues_model.FilterModeAssign:
- openClosedOpts.AssigneeID = optional.Some(doerID)
+ openClosedOpts.AssigneeID = strconv.FormatInt(doerID, 10)
case issues_model.FilterModeCreate:
- openClosedOpts.PosterID = optional.Some(doerID)
+ openClosedOpts.PosterID = strconv.FormatInt(doerID, 10)
case issues_model.FilterModeMention:
openClosedOpts.MentionID = optional.Some(doerID)
case issues_model.FilterModeReviewRequested:
@@ -816,8 +816,8 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
// Below stats are for the left sidebar
opts = opts.Copy(func(o *issue_indexer.SearchOptions) {
- o.AssigneeID = nil
- o.PosterID = nil
+ o.AssigneeID = ""
+ o.PosterID = ""
o.MentionID = nil
o.ReviewRequestedID = nil
o.ReviewedID = nil
@@ -827,11 +827,11 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
if err != nil {
return nil, err
}
- ret.AssignCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AssigneeID = optional.Some(doerID) }))
+ ret.AssignCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AssigneeID = strconv.FormatInt(doerID, 10) }))
if err != nil {
return nil, err
}
- ret.CreateCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.PosterID = optional.Some(doerID) }))
+ ret.CreateCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.PosterID = strconv.FormatInt(doerID, 10) }))
if err != nil {
return nil, err
}
diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go
index b2c8ad98ba..2a8a8812e3 100644
--- a/routers/web/user/home_test.go
+++ b/routers/web/user/home_test.go
@@ -37,15 +37,15 @@ func TestArchivedIssues(t *testing.T) {
NumIssues[repo.ID] = repo.NumIssues
}
assert.False(t, IsArchived[50])
- assert.EqualValues(t, 1, NumIssues[50])
+ assert.Equal(t, 1, NumIssues[50])
assert.True(t, IsArchived[51])
- assert.EqualValues(t, 1, NumIssues[51])
+ assert.Equal(t, 1, NumIssues[51])
// Act
Issues(ctx)
// Assert: One Issue (ID 30) from one Repo (ID 50) is retrieved, while nothing from archived Repo 51 is retrieved
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.Len(t, ctx.Data["Issues"], 1)
}
@@ -58,7 +58,7 @@ func TestIssues(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
ctx.Req.Form.Set("state", "closed")
Issues(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
assert.Len(t, ctx.Data["Issues"], 1)
@@ -72,7 +72,7 @@ func TestPulls(t *testing.T) {
contexttest.LoadUser(t, ctx, 2)
ctx.Req.Form.Set("state", "open")
Pulls(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.Len(t, ctx.Data["Issues"], 5)
}
@@ -87,7 +87,7 @@ func TestMilestones(t *testing.T) {
ctx.Req.Form.Set("state", "closed")
ctx.Req.Form.Set("sort", "furthestduedate")
Milestones(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, map[int64]int64{1: 1}, ctx.Data["Counts"])
assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
@@ -107,7 +107,7 @@ func TestMilestonesForSpecificRepo(t *testing.T) {
ctx.Req.Form.Set("state", "closed")
ctx.Req.Form.Set("sort", "furthestduedate")
Milestones(ctx)
- assert.EqualValues(t, http.StatusOK, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.EqualValues(t, map[int64]int64{1: 1}, ctx.Data["Counts"])
assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 1c91ff6364..89f3c6956f 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -4,7 +4,6 @@
package user
import (
- goctx "context"
"errors"
"fmt"
"net/http"
@@ -35,32 +34,6 @@ const (
tplNotificationSubscriptions templates.TplName = "user/notification/notification_subscriptions"
)
-// GetNotificationCount is the middleware that sets the notification count in the context
-func GetNotificationCount(ctx *context.Context) {
- if strings.HasPrefix(ctx.Req.URL.Path, "/api") {
- return
- }
-
- if !ctx.IsSigned {
- return
- }
-
- ctx.Data["NotificationUnreadCount"] = func() int64 {
- count, err := db.Count[activities_model.Notification](ctx, activities_model.FindNotificationOptions{
- UserID: ctx.Doer.ID,
- Status: []activities_model.NotificationStatus{activities_model.NotificationStatusUnread},
- })
- if err != nil {
- if err != goctx.Canceled {
- log.Error("Unable to GetNotificationCount for user:%-v: %v", ctx.Doer, err)
- }
- return -1
- }
-
- return count
- }
-}
-
// Notifications is the notifications page
func Notifications(ctx *context.Context) {
getNotifications(ctx)
@@ -335,9 +308,10 @@ func NotificationSubscriptions(ctx *context.Context) {
return 0
}
reviewTyp := issues_model.ReviewTypeApprove
- if typ == "reject" {
+ switch typ {
+ case "reject":
reviewTyp = issues_model.ReviewTypeReject
- } else if typ == "waiting" {
+ case "waiting":
reviewTyp = issues_model.ReviewTypeRequest
}
for _, count := range counts {
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index 94577832a9..b124d5e1de 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -6,7 +6,6 @@ package setting
import (
"errors"
- "fmt"
"net/http"
"time"
@@ -37,7 +36,7 @@ const (
// Account renders change user's password, user's email and user suicide page
func Account(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) && !setting.Service.EnableNotifyMail {
- ctx.NotFound(fmt.Errorf("account setting are not allowed to be changed"))
+ ctx.NotFound(errors.New("account setting are not allowed to be changed"))
return
}
@@ -54,7 +53,7 @@ func Account(ctx *context.Context) {
// AccountPost response for change user's password
func AccountPost(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("password setting is not allowed to be changed"))
+ ctx.NotFound(errors.New("password setting is not allowed to be changed"))
return
}
@@ -105,7 +104,7 @@ func AccountPost(ctx *context.Context) {
// EmailPost response for change user's email
func EmailPost(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("emails are not allowed to be changed"))
+ ctx.NotFound(errors.New("emails are not allowed to be changed"))
return
}
@@ -239,7 +238,7 @@ func EmailPost(ctx *context.Context) {
// DeleteEmail response for delete user's email
func DeleteEmail(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("emails are not allowed to be changed"))
+ ctx.NotFound(errors.New("emails are not allowed to be changed"))
return
}
email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, ctx.FormInt64("id"))
diff --git a/routers/web/user/setting/account_test.go b/routers/web/user/setting/account_test.go
index 13caa33771..9b8cffc868 100644
--- a/routers/web/user/setting/account_test.go
+++ b/routers/web/user/setting/account_test.go
@@ -95,7 +95,7 @@ func TestChangePassword(t *testing.T) {
AccountPost(ctx)
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
})
}
}
diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go
index 1f6c97a5cc..c3d8b93adb 100644
--- a/routers/web/user/setting/applications.go
+++ b/routers/web/user/setting/applications.go
@@ -54,7 +54,7 @@ func ApplicationsPost(ctx *context.Context) {
ctx.ServerError("GetScope", err)
return
}
- if scope == "" || scope == auth_model.AccessTokenScopePublicOnly {
+ if !scope.HasPermissionScope() {
ctx.Flash.Error(ctx.Tr("settings.at_least_one_permission"), true)
}
diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go
index 17e32f5403..6b5a7a2e2a 100644
--- a/routers/web/user/setting/keys.go
+++ b/routers/web/user/setting/keys.go
@@ -5,7 +5,7 @@
package setting
import (
- "fmt"
+ "errors"
"net/http"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -26,7 +26,7 @@ const (
// Keys render user's SSH/GPG public keys page
func Keys(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("keys setting is not allowed to be changed"))
+ ctx.NotFound(errors.New("keys setting is not allowed to be changed"))
return
}
@@ -87,7 +87,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "gpg":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
return
}
@@ -168,7 +168,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
@@ -212,7 +212,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "verify_ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
@@ -249,7 +249,7 @@ func DeleteKey(ctx *context.Context) {
switch ctx.FormString("type") {
case "gpg":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
return
}
if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
@@ -259,7 +259,7 @@ func DeleteKey(ctx *context.Context) {
}
case "ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
diff --git a/routers/web/web.go b/routers/web/web.go
index f4bd3ef4bc..7948c5f5ff 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -178,7 +178,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.Cont
return
}
- if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" {
+ if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == http.MethodPost {
ctx.Csrf.Validate(ctx)
if ctx.Written() {
return
@@ -280,28 +280,26 @@ func Routes() *web.Router {
routes.Get("/api/swagger", append(mid, misc.Swagger)...) // Render V1 by default
}
- // TODO: These really seem like things that could be folded into Contexter or as helper functions
- mid = append(mid, user.GetNotificationCount)
- mid = append(mid, repo.GetActiveStopwatch)
mid = append(mid, goGet)
+ mid = append(mid, common.PageTmplFunctions)
- others := web.NewRouter()
- others.Use(mid...)
- registerRoutes(others)
- routes.Mount("", others)
+ webRoutes := web.NewRouter()
+ webRoutes.Use(mid...)
+ webRoutes.Group("", func() { registerWebRoutes(webRoutes) }, common.BlockExpensive())
+ routes.Mount("", webRoutes)
return routes
}
var optSignInIgnoreCsrf = verifyAuthWithOptions(&common.VerifyOptions{DisableCSRF: true})
-// registerRoutes register routes
-func registerRoutes(m *web.Router) {
+// registerWebRoutes register routes
+func registerWebRoutes(m *web.Router) {
// required to be signed in or signed out
reqSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true})
reqSignOut := verifyAuthWithOptions(&common.VerifyOptions{SignOutRequired: true})
// optional sign in (if signed in, use the user as doer, if not, no doer)
- optSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView})
- optExploreSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView})
+ optSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInViewStrict})
+ optExploreSignIn := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: setting.Service.RequireSignInViewStrict || setting.Service.Explore.RequireSigninView})
validation.AddBindingRules()
@@ -856,13 +854,13 @@ func registerRoutes(m *web.Router) {
individualPermsChecker := func(ctx *context.Context) {
// org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
if ctx.ContextUser.IsIndividual() {
- switch {
- case ctx.ContextUser.Visibility == structs.VisibleTypePrivate:
+ switch ctx.ContextUser.Visibility {
+ case structs.VisibleTypePrivate:
if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
ctx.NotFound(nil)
return
}
- case ctx.ContextUser.Visibility == structs.VisibleTypeLimited:
+ case structs.VisibleTypeLimited:
if ctx.Doer == nil {
ctx.NotFound(nil)
return
@@ -1080,6 +1078,8 @@ func registerRoutes(m *web.Router) {
m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo_setting.SettingsAvatar)
m.Post("/avatar/delete", repo_setting.SettingsDeleteAvatar)
+ m.Combo("/public_access").Get(repo_setting.PublicAccess).Post(repo_setting.PublicAccessPost)
+
m.Group("/collaboration", func() {
m.Combo("").Get(repo_setting.Collaboration).Post(repo_setting.CollaborationPost)
m.Post("/access_mode", repo_setting.ChangeCollaborationAccessMode)
@@ -1185,6 +1185,7 @@ func registerRoutes(m *web.Router) {
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Post(reqSignIn, context.RepoMustNotBeArchived(), reqUnitPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
+ m.Get("/pulls/new/*", repo.PullsNewRedirect)
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code: find, compare, list
@@ -1489,7 +1490,7 @@ func registerRoutes(m *web.Router) {
})
m.Group("/recent-commits", func() {
m.Get("", repo.RecentCommits)
- m.Get("/data", repo.RecentCommitsData)
+ m.Get("/data", repo.CodeFrequencyData) // "recent-commits" also uses the same data as "code-frequency"
})
}, reqUnitCodeReader)
},
@@ -1640,7 +1641,7 @@ func registerRoutes(m *web.Router) {
m.Group("/devtest", func() {
m.Any("", devtest.List)
m.Any("/fetch-action-test", devtest.FetchActionTest)
- m.Any("/{sub}", devtest.Tmpl)
+ m.Any("/{sub}", devtest.TmplCommon)
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
})
diff --git a/routers/web/webfinger.go b/routers/web/webfinger.go
index afcfdc8252..a4c9bf902b 100644
--- a/routers/web/webfinger.go
+++ b/routers/web/webfinger.go
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"strings"
user_model "code.gitea.io/gitea/models/user"
@@ -85,10 +86,10 @@ func WebfingerQuery(ctx *context.Context) {
aliases := []string{
u.HTMLURL(),
- appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
+ appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(u.ID, 10),
}
if !u.KeepEmailPrivate {
- aliases = append(aliases, fmt.Sprintf("mailto:%s", u.Email))
+ aliases = append(aliases, "mailto:"+u.Email)
}
links := []*webfingerLink{
@@ -104,7 +105,7 @@ func WebfingerQuery(ctx *context.Context) {
{
Rel: "self",
Type: "application/activity+json",
- Href: appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
+ Href: appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(u.ID, 10),
},
{
Rel: "http://openid.net/specs/connect/1.0/issuer",