feat(quota): Quota enforcement
The previous commit laid out the foundation of the quota engine, this one builds on top of it, and implements the actual enforcement. Enforcement happens at the route decoration level, whenever possible. In case of the API, when over quota, a 413 error is returned, with an appropriate JSON payload. In case of web routes, a 413 HTML page is rendered with similar information. This implementation is for a **soft quota**: quota usage is checked before an operation is to be performed, and the operation is *only* denied if the user is already over quota. This makes it possible to go over quota, but has the significant advantage of being practically implementable within the current Forgejo architecture. The goal of enforcement is to deny actions that can make the user go over quota, and allow the rest. As such, deleting things should - in almost all cases - be possible. A prime exemption is deleting files via the web ui: that creates a new commit, which in turn increases repo size, thus, is denied if the user is over quota. Limitations ----------- Because we generally work at a route decorator level, and rarely look *into* the operation itself, `size:repos:public` and `size:repos:private` are not enforced at this level, the engine enforces against `size:repos:all`. This will be improved in the future. AGit does not play very well with this system, because AGit PRs count toward the repo they're opened against, while in the GitHub-style fork + pull model, it counts against the fork. This too, can be improved in the future. There's very little done on the UI side to guard against going over quota. What this patch implements, is enforcement, not prevention. The UI will still let you *try* operations that *will* result in a denial. Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
This commit is contained in:
parent
a414703c09
commit
67fa52dedb
33 changed files with 3172 additions and 66 deletions
|
@ -71,6 +71,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -240,6 +241,18 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
|
|||
return
|
||||
}
|
||||
|
||||
// check the owner's quota
|
||||
ok, err := quota_model.EvaluateForUser(ctx, ctx.ActionTask.OwnerID, quota_model.LimitSubjectSizeAssetsArtifacts)
|
||||
if err != nil {
|
||||
log.Error("quota_model.EvaluateForUser: %v", err)
|
||||
ctx.Error(http.StatusInternalServerError, "Error checking quota")
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.Error(http.StatusRequestEntityTooLarge, "Quota exceeded")
|
||||
return
|
||||
}
|
||||
|
||||
// get upload file size
|
||||
fileRealTotalSize, contentLength := getUploadFileSize(ctx)
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
|
@ -290,6 +291,18 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
|
|||
return
|
||||
}
|
||||
|
||||
// check the owner's quota
|
||||
ok, err := quota_model.EvaluateForUser(ctx, task.OwnerID, quota_model.LimitSubjectSizeAssetsArtifacts)
|
||||
if err != nil {
|
||||
log.Error("quota_model.EvaluateForUser: %v", err)
|
||||
ctx.Error(http.StatusInternalServerError, "Error checking quota")
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.Error(http.StatusRequestEntityTooLarge, "Quota exceeded")
|
||||
return
|
||||
}
|
||||
|
||||
comp := ctx.Req.URL.Query().Get("comp")
|
||||
switch comp {
|
||||
case "block", "appendBlock":
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
|
@ -74,6 +75,21 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func enforcePackagesQuota() func(ctx *context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
ok, err := quota_model.EvaluateForUser(ctx, ctx.Doer.ID, quota_model.LimitSubjectSizeAssetsPackagesAll)
|
||||
if err != nil {
|
||||
log.Error("quota_model.EvaluateForUser: %v", err)
|
||||
ctx.Error(http.StatusInternalServerError, "Error checking quota")
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.Error(http.StatusRequestEntityTooLarge, "enforcePackagesQuota", "quota exceeded")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func verifyAuth(r *web.Route, authMethods []auth.Method) {
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
authMethods = append(authMethods, &auth.ReverseProxy{})
|
||||
|
@ -111,7 +127,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/alpine", func() {
|
||||
r.Get("/key", alpine.GetRepositoryKey)
|
||||
r.Group("/{branch}/{repository}", func() {
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), alpine.UploadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), alpine.UploadPackageFile)
|
||||
r.Group("/{architecture}", func() {
|
||||
r.Get("/APKINDEX.tar.gz", alpine.GetRepositoryFile)
|
||||
r.Group("/{filename}", func() {
|
||||
|
@ -124,12 +140,12 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/cargo", func() {
|
||||
r.Group("/api/v1/crates", func() {
|
||||
r.Get("", cargo.SearchPackages)
|
||||
r.Put("/new", reqPackageAccess(perm.AccessModeWrite), cargo.UploadPackage)
|
||||
r.Put("/new", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), cargo.UploadPackage)
|
||||
r.Group("/{package}", func() {
|
||||
r.Group("/{version}", func() {
|
||||
r.Get("/download", cargo.DownloadPackageFile)
|
||||
r.Delete("/yank", reqPackageAccess(perm.AccessModeWrite), cargo.YankPackage)
|
||||
r.Put("/unyank", reqPackageAccess(perm.AccessModeWrite), cargo.UnyankPackage)
|
||||
r.Put("/unyank", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), cargo.UnyankPackage)
|
||||
})
|
||||
r.Get("/owners", cargo.ListOwners)
|
||||
})
|
||||
|
@ -147,7 +163,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/search", chef.EnumeratePackages)
|
||||
r.Group("/cookbooks", func() {
|
||||
r.Get("", chef.EnumeratePackages)
|
||||
r.Post("", reqPackageAccess(perm.AccessModeWrite), chef.UploadPackage)
|
||||
r.Post("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), chef.UploadPackage)
|
||||
r.Group("/{name}", func() {
|
||||
r.Get("", chef.PackageMetadata)
|
||||
r.Group("/versions/{version}", func() {
|
||||
|
@ -167,7 +183,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/p2/{vendorname}/{projectname}~dev.json", composer.PackageMetadata)
|
||||
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
||||
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), composer.UploadPackage)
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/conan", func() {
|
||||
r.Group("/v1", func() {
|
||||
|
@ -183,14 +199,14 @@ func CommonRoutes() *web.Route {
|
|||
r.Delete("", reqPackageAccess(perm.AccessModeWrite), conan.DeleteRecipeV1)
|
||||
r.Get("/search", conan.SearchPackagesV1)
|
||||
r.Get("/digest", conan.RecipeDownloadURLs)
|
||||
r.Post("/upload_urls", reqPackageAccess(perm.AccessModeWrite), conan.RecipeUploadURLs)
|
||||
r.Post("/upload_urls", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.RecipeUploadURLs)
|
||||
r.Get("/download_urls", conan.RecipeDownloadURLs)
|
||||
r.Group("/packages", func() {
|
||||
r.Post("/delete", reqPackageAccess(perm.AccessModeWrite), conan.DeletePackageV1)
|
||||
r.Group("/{package_reference}", func() {
|
||||
r.Get("", conan.PackageSnapshot)
|
||||
r.Get("/digest", conan.PackageDownloadURLs)
|
||||
r.Post("/upload_urls", reqPackageAccess(perm.AccessModeWrite), conan.PackageUploadURLs)
|
||||
r.Post("/upload_urls", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.PackageUploadURLs)
|
||||
r.Get("/download_urls", conan.PackageDownloadURLs)
|
||||
})
|
||||
})
|
||||
|
@ -199,11 +215,11 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/files/{name}/{version}/{user}/{channel}/{recipe_revision}", func() {
|
||||
r.Group("/recipe/{filename}", func() {
|
||||
r.Get("", conan.DownloadRecipeFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), conan.UploadRecipeFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.UploadRecipeFile)
|
||||
})
|
||||
r.Group("/package/{package_reference}/{package_revision}/{filename}", func() {
|
||||
r.Get("", conan.DownloadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), conan.UploadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.UploadPackageFile)
|
||||
})
|
||||
}, conan.ExtractPathParameters)
|
||||
})
|
||||
|
@ -228,7 +244,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("", conan.ListRecipeRevisionFiles)
|
||||
r.Group("/{filename}", func() {
|
||||
r.Get("", conan.DownloadRecipeFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), conan.UploadRecipeFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.UploadRecipeFile)
|
||||
})
|
||||
})
|
||||
r.Group("/packages", func() {
|
||||
|
@ -244,7 +260,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("", conan.ListPackageRevisionFiles)
|
||||
r.Group("/{filename}", func() {
|
||||
r.Get("", conan.DownloadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), conan.UploadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), conan.UploadPackageFile)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -281,7 +297,7 @@ func CommonRoutes() *web.Route {
|
|||
conda.DownloadPackageFile(ctx)
|
||||
}
|
||||
})
|
||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), func(ctx *context.Context) {
|
||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), func(ctx *context.Context) {
|
||||
m := uploadPattern.FindStringSubmatch(ctx.Params("*"))
|
||||
if len(m) == 0 {
|
||||
ctx.Status(http.StatusNotFound)
|
||||
|
@ -301,7 +317,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/PACKAGES{format}", cran.EnumerateSourcePackages)
|
||||
r.Get("/{filename}", cran.DownloadSourcePackageFile)
|
||||
})
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), cran.UploadSourcePackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), cran.UploadSourcePackageFile)
|
||||
})
|
||||
r.Group("/bin", func() {
|
||||
r.Group("/{platform}/contrib/{rversion}", func() {
|
||||
|
@ -309,7 +325,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/PACKAGES{format}", cran.EnumerateBinaryPackages)
|
||||
r.Get("/{filename}", cran.DownloadBinaryPackageFile)
|
||||
})
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), cran.UploadBinaryPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), cran.UploadBinaryPackageFile)
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/debian", func() {
|
||||
|
@ -325,13 +341,13 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/pool/{distribution}/{component}", func() {
|
||||
r.Get("/{name}_{version}_{architecture}.deb", debian.DownloadPackageFile)
|
||||
r.Group("", func() {
|
||||
r.Put("/upload", debian.UploadPackageFile)
|
||||
r.Put("/upload", enforcePackagesQuota(), debian.UploadPackageFile)
|
||||
r.Delete("/{name}/{version}/{architecture}", debian.DeletePackageFile)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/go", func() {
|
||||
r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), goproxy.UploadPackage)
|
||||
r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), goproxy.UploadPackage)
|
||||
r.Get("/sumdb/sum.golang.org/supported", func(ctx *context.Context) {
|
||||
ctx.Status(http.StatusNotFound)
|
||||
})
|
||||
|
@ -394,7 +410,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/{filename}", func() {
|
||||
r.Get("", generic.DownloadPackageFile)
|
||||
r.Group("", func() {
|
||||
r.Put("", generic.UploadPackage)
|
||||
r.Put("", enforcePackagesQuota(), generic.UploadPackage)
|
||||
r.Delete("", generic.DeletePackageFile)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
})
|
||||
|
@ -403,10 +419,10 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/helm", func() {
|
||||
r.Get("/index.yaml", helm.Index)
|
||||
r.Get("/{filename}", helm.DownloadPackageFile)
|
||||
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
||||
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), helm.UploadPackage)
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/maven", func() {
|
||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), maven.UploadPackageFile)
|
||||
r.Get("/*", maven.DownloadPackageFile)
|
||||
r.Head("/*", maven.ProvidePackageFileHeader)
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
|
@ -427,8 +443,8 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
||||
})
|
||||
r.Group("", func() {
|
||||
r.Put("/", nuget.UploadPackage)
|
||||
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
||||
r.Put("/", enforcePackagesQuota(), nuget.UploadPackage)
|
||||
r.Put("/symbolpackage", enforcePackagesQuota(), nuget.UploadSymbolPackage)
|
||||
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
r.Get("/symbols/{filename}/{guid:[0-9a-fA-F]{32}[fF]{8}}/{filename2}", nuget.DownloadSymbolFile)
|
||||
|
@ -450,7 +466,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/npm", func() {
|
||||
r.Group("/@{scope}/{id}", func() {
|
||||
r.Get("", npm.PackageMetadata)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), npm.UploadPackage)
|
||||
r.Group("/-/{version}/{filename}", func() {
|
||||
r.Get("", npm.DownloadPackageFile)
|
||||
r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
|
||||
|
@ -463,7 +479,7 @@ func CommonRoutes() *web.Route {
|
|||
})
|
||||
r.Group("/{id}", func() {
|
||||
r.Get("", npm.PackageMetadata)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), npm.UploadPackage)
|
||||
r.Group("/-/{version}/{filename}", func() {
|
||||
r.Get("", npm.DownloadPackageFile)
|
||||
r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
|
||||
|
@ -496,7 +512,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Group("/api/packages", func() {
|
||||
r.Group("/versions/new", func() {
|
||||
r.Get("", pub.RequestUpload)
|
||||
r.Post("/upload", pub.UploadPackageFile)
|
||||
r.Post("/upload", enforcePackagesQuota(), pub.UploadPackageFile)
|
||||
r.Get("/finalize/{id}/{version}", pub.FinalizePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
r.Group("/{id}", func() {
|
||||
|
@ -507,7 +523,7 @@ func CommonRoutes() *web.Route {
|
|||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/pypi", func() {
|
||||
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
||||
r.Post("/", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), pypi.UploadPackageFile)
|
||||
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
||||
r.Get("/simple/{id}", pypi.PackageMetadata)
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
|
@ -556,6 +572,10 @@ func CommonRoutes() *web.Route {
|
|||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
enforcePackagesQuota()(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
ctx.SetParams("group", strings.Trim(m[1], "/"))
|
||||
rpm.UploadPackageFile(ctx)
|
||||
return
|
||||
|
@ -591,7 +611,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("/quick/Marshal.4.8/{filename}", rubygems.ServePackageSpecification)
|
||||
r.Get("/gems/{filename}", rubygems.DownloadPackageFile)
|
||||
r.Group("/api/v1/gems", func() {
|
||||
r.Post("/", rubygems.UploadPackageFile)
|
||||
r.Post("/", enforcePackagesQuota(), rubygems.UploadPackageFile)
|
||||
r.Delete("/yank", rubygems.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
|
@ -603,7 +623,7 @@ func CommonRoutes() *web.Route {
|
|||
}, swift.CheckAcceptMediaType(swift.AcceptJSON))
|
||||
r.Group("/{version}", func() {
|
||||
r.Get("/Package.swift", swift.CheckAcceptMediaType(swift.AcceptSwift), swift.DownloadManifest)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), swift.UploadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), swift.CheckAcceptMediaType(swift.AcceptJSON), enforcePackagesQuota(), swift.UploadPackageFile)
|
||||
r.Get("", func(ctx *context.Context) {
|
||||
// Can't use normal routes here: https://github.com/go-chi/chi/issues/781
|
||||
|
||||
|
@ -639,7 +659,7 @@ func CommonRoutes() *web.Route {
|
|||
r.Get("", vagrant.EnumeratePackageVersions)
|
||||
r.Group("/{version}/{provider}", func() {
|
||||
r.Get("", vagrant.DownloadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), vagrant.UploadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), enforcePackagesQuota(), vagrant.UploadPackageFile)
|
||||
})
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
|
|
|
@ -77,6 +77,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -973,7 +974,7 @@ func Routes() *web.Route {
|
|||
|
||||
// (repo scope)
|
||||
m.Combo("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(user.ListMyRepos).
|
||||
Post(bind(api.CreateRepoOption{}), repo.Create)
|
||||
Post(bind(api.CreateRepoOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetUser), repo.Create)
|
||||
|
||||
// (repo scope)
|
||||
if !setting.Repository.DisableStars {
|
||||
|
@ -1104,7 +1105,7 @@ func Routes() *web.Route {
|
|||
m.Get("", repo.ListBranches)
|
||||
m.Get("/*", repo.GetBranch)
|
||||
m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteBranch)
|
||||
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
|
||||
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateBranchRepoOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.CreateBranch)
|
||||
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
|
||||
m.Group("/branch_protections", func() {
|
||||
m.Get("", repo.ListBranchProtections)
|
||||
|
@ -1118,7 +1119,7 @@ func Routes() *web.Route {
|
|||
m.Group("/tags", func() {
|
||||
m.Get("", repo.ListTags)
|
||||
m.Get("/*", repo.GetTag)
|
||||
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), repo.CreateTag)
|
||||
m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.CreateTag)
|
||||
m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteTag)
|
||||
}, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true))
|
||||
m.Group("/tag_protections", func() {
|
||||
|
@ -1152,10 +1153,10 @@ func Routes() *web.Route {
|
|||
m.Group("/wiki", func() {
|
||||
m.Combo("/page/{pageName}").
|
||||
Get(repo.GetWikiPage).
|
||||
Patch(mustNotBeArchived, reqToken(), reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
|
||||
Patch(mustNotBeArchived, reqToken(), reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeWiki, context.QuotaTargetRepo), repo.EditWikiPage).
|
||||
Delete(mustNotBeArchived, reqToken(), reqRepoWriter(unit.TypeWiki), repo.DeleteWikiPage)
|
||||
m.Get("/revisions/{pageName}", repo.ListPageRevisions)
|
||||
m.Post("/new", reqToken(), mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
|
||||
m.Post("/new", reqToken(), mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeWiki, context.QuotaTargetRepo), repo.NewWikiPage)
|
||||
m.Get("/pages", repo.ListWikiPages)
|
||||
}, mustEnableWiki)
|
||||
m.Post("/markup", reqToken(), bind(api.MarkupOption{}), misc.Markup)
|
||||
|
@ -1172,15 +1173,15 @@ func Routes() *web.Route {
|
|||
}, reqToken())
|
||||
m.Group("/releases", func() {
|
||||
m.Combo("").Get(repo.ListReleases).
|
||||
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
|
||||
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.CreateRelease)
|
||||
m.Combo("/latest").Get(repo.GetLatestRelease)
|
||||
m.Group("/{id}", func() {
|
||||
m.Combo("").Get(repo.GetRelease).
|
||||
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
|
||||
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.EditRelease).
|
||||
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
|
||||
m.Group("/assets", func() {
|
||||
m.Combo("").Get(repo.ListReleaseAttachments).
|
||||
Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
|
||||
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeAssetsAttachmentsReleases, context.QuotaTargetRepo), repo.CreateReleaseAttachment)
|
||||
m.Combo("/{attachment_id}").Get(repo.GetReleaseAttachment).
|
||||
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
|
||||
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
|
||||
|
@ -1192,7 +1193,7 @@ func Routes() *web.Route {
|
|||
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseByTag)
|
||||
})
|
||||
}, reqRepoReader(unit.TypeReleases))
|
||||
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.MirrorSync)
|
||||
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MirrorSync)
|
||||
m.Post("/push_mirrors-sync", reqAdmin(), reqToken(), mustNotBeArchived, repo.PushMirrorSync)
|
||||
m.Group("/push_mirrors", func() {
|
||||
m.Combo("").Get(repo.ListPushMirrors).
|
||||
|
@ -1211,11 +1212,11 @@ func Routes() *web.Route {
|
|||
m.Combo("").Get(repo.GetPullRequest).
|
||||
Patch(reqToken(), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
|
||||
m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch)
|
||||
m.Post("/update", reqToken(), repo.UpdatePullRequest)
|
||||
m.Post("/update", reqToken(), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.UpdatePullRequest)
|
||||
m.Get("/commits", repo.GetPullRequestCommits)
|
||||
m.Get("/files", repo.GetPullRequestFiles)
|
||||
m.Combo("/merge").Get(repo.IsPullRequestMerged).
|
||||
Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest).
|
||||
Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MergePullRequest).
|
||||
Delete(reqToken(), mustNotBeArchived, repo.CancelScheduledAutoMerge)
|
||||
m.Group("/reviews", func() {
|
||||
m.Combo("").
|
||||
|
@ -1270,15 +1271,15 @@ func Routes() *web.Route {
|
|||
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
|
||||
m.Get("/notes/{sha}", repo.GetNote)
|
||||
}, context.ReferencesGitRepo(true), reqRepoReader(unit.TypeCode))
|
||||
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), mustNotBeArchived, repo.ApplyDiffPatch)
|
||||
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.ApplyDiffPatch)
|
||||
m.Group("/contents", func() {
|
||||
m.Get("", repo.GetContentsList)
|
||||
m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.ChangeFiles)
|
||||
m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.ChangeFiles)
|
||||
m.Get("/*", repo.GetContents)
|
||||
m.Group("/*", func() {
|
||||
m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.CreateFile)
|
||||
m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.UpdateFile)
|
||||
m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.DeleteFile)
|
||||
m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.CreateFile)
|
||||
m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.UpdateFile)
|
||||
m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.DeleteFile)
|
||||
}, reqToken())
|
||||
}, reqRepoReader(unit.TypeCode))
|
||||
m.Get("/signing-key.gpg", misc.SigningKey)
|
||||
|
@ -1335,7 +1336,7 @@ func Routes() *web.Route {
|
|||
m.Group("/assets", func() {
|
||||
m.Combo("").
|
||||
Get(repo.ListIssueCommentAttachments).
|
||||
Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment)
|
||||
Post(reqToken(), mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeAssetsAttachmentsIssues, context.QuotaTargetRepo), repo.CreateIssueCommentAttachment)
|
||||
m.Combo("/{attachment_id}").
|
||||
Get(repo.GetIssueCommentAttachment).
|
||||
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
|
||||
|
@ -1387,7 +1388,7 @@ func Routes() *web.Route {
|
|||
m.Group("/assets", func() {
|
||||
m.Combo("").
|
||||
Get(repo.ListIssueAttachments).
|
||||
Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment)
|
||||
Post(reqToken(), mustNotBeArchived, context.EnforceQuotaAPI(quota_model.LimitSubjectSizeAssetsAttachmentsIssues, context.QuotaTargetRepo), repo.CreateIssueAttachment)
|
||||
m.Combo("/{attachment_id}").
|
||||
Get(repo.GetIssueAttachment).
|
||||
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
|
||||
|
@ -1449,7 +1450,7 @@ func Routes() *web.Route {
|
|||
Patch(reqToken(), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
|
||||
Delete(reqToken(), reqOrgOwnership(), org.Delete)
|
||||
m.Combo("/repos").Get(user.ListOrgRepos).
|
||||
Post(reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
|
||||
Post(reqToken(), bind(api.CreateRepoOption{}), context.EnforceQuotaAPI(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetOrg), repo.CreateOrgRepo)
|
||||
m.Group("/members", func() {
|
||||
m.Get("", reqToken(), org.ListMembers)
|
||||
m.Combo("/{username}").Get(reqToken(), org.IsMember).
|
||||
|
|
|
@ -210,6 +210,8 @@ func CreateBranch(ctx *context.APIContext) {
|
|||
// description: The old branch does not exist.
|
||||
// "409":
|
||||
// description: The branch with the same name already exists.
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
|
|
@ -477,6 +477,8 @@ func ChangeFiles(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/error"
|
||||
// "423":
|
||||
|
@ -579,6 +581,8 @@ func CreateFile(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/error"
|
||||
// "423":
|
||||
|
@ -677,6 +681,8 @@ func UpdateFile(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/error"
|
||||
// "423":
|
||||
|
@ -842,6 +848,8 @@ func DeleteFile(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
@ -105,6 +106,8 @@ func CreateFork(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/notFound"
|
||||
// "409":
|
||||
// description: The repository with the same name already exists.
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
|
||||
|
@ -134,6 +137,10 @@ func CreateFork(ctx *context.APIContext) {
|
|||
forker = org.AsUser()
|
||||
}
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, forker.ID, forker.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
var name string
|
||||
if form.Name == nil {
|
||||
name = repo.Name
|
||||
|
|
|
@ -160,6 +160,8 @@ func CreateIssueAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
// "423":
|
||||
|
@ -269,6 +271,8 @@ func EditIssueAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/Attachment"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
|
|
@ -157,6 +157,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
// "423":
|
||||
|
@ -274,6 +276,8 @@ func EditIssueCommentAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/Attachment"
|
||||
// "404":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
attach := getIssueCommentAttachmentSafeWrite(ctx)
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
|
@ -54,6 +55,8 @@ func Migrate(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "409":
|
||||
// description: The repository with the same name already exists.
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
|
||||
|
@ -85,6 +88,10 @@ func Migrate(ctx *context.APIContext) {
|
|||
return
|
||||
}
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, repoOwner.ID, repoOwner.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Doer.IsAdmin {
|
||||
if !repoOwner.IsOrganization() && ctx.Doer.ID != repoOwner.ID {
|
||||
ctx.Error(http.StatusForbidden, "", "Given user is not an organization.")
|
||||
|
|
|
@ -50,6 +50,8 @@ func MirrorSync(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
|
@ -103,6 +105,8 @@ func PushMirrorSync(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
if !setting.Mirror.Enabled {
|
||||
ctx.Error(http.StatusBadRequest, "PushMirrorSync", "Mirror feature is disabled")
|
||||
|
@ -279,6 +283,8 @@ func AddPushMirror(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
if !setting.Mirror.Enabled {
|
||||
ctx.Error(http.StatusBadRequest, "AddPushMirror", "Mirror feature is disabled")
|
||||
|
|
|
@ -47,6 +47,8 @@ func ApplyDiffPatch(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/FileResponse"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions)
|
||||
|
|
|
@ -387,6 +387,8 @@ func CreatePullRequest(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/notFound"
|
||||
// "409":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
// "423":
|
||||
|
@ -857,6 +859,8 @@ func MergePullRequest(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/empty"
|
||||
// "409":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
@ -1218,6 +1222,8 @@ func UpdatePullRequest(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/notFound"
|
||||
// "409":
|
||||
// "$ref": "#/responses/error"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
|
||||
|
|
|
@ -201,6 +201,8 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
// Check if attachments are enabled
|
||||
if !setting.Attachment.Enabled {
|
||||
|
@ -348,6 +350,8 @@ func EditReleaseAttachment(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/Attachment"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
form := web.GetForm(ctx).(*api.EditAttachmentOptions)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -302,6 +303,8 @@ func Create(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/error"
|
||||
// "409":
|
||||
// description: The repository with the same name already exists.
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
opt := web.GetForm(ctx).(*api.CreateRepoOption)
|
||||
|
@ -346,6 +349,8 @@ func Generate(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/notFound"
|
||||
// "409":
|
||||
// description: The repository with the same name already exists.
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
form := web.GetForm(ctx).(*api.GenerateRepoOption)
|
||||
|
@ -412,6 +417,10 @@ func Generate(ctx *context.APIContext) {
|
|||
}
|
||||
}
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, ctxUser.ID, ctxUser.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := repo_service.GenerateRepository(ctx, ctx.Doer, ctxUser, ctx.Repo.Repository, opts)
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||
|
|
|
@ -208,6 +208,8 @@ func CreateTag(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/empty"
|
||||
// "409":
|
||||
// "$ref": "#/responses/conflict"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
// "423":
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
@ -53,6 +54,8 @@ func Transfer(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
|
||||
|
@ -76,6 +79,10 @@ func Transfer(ctx *context.APIContext) {
|
|||
}
|
||||
}
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, newOwner.ID, newOwner.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
var teams []*organization.Team
|
||||
if opts.TeamIDs != nil {
|
||||
if !newOwner.IsOrganization() {
|
||||
|
@ -162,6 +169,8 @@ func AcceptTransfer(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
|
||||
err := acceptOrRejectRepoTransfer(ctx, true)
|
||||
if ctx.Written() {
|
||||
|
@ -233,6 +242,11 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error {
|
|||
}
|
||||
|
||||
if accept {
|
||||
recipient := repoTransfer.Recipient
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, recipient.ID, recipient.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams)
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ func NewWikiPage(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
@ -131,6 +133,8 @@ func EditWikiPage(ctx *context.APIContext) {
|
|||
// "$ref": "#/responses/forbidden"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "413":
|
||||
// "$ref": "#/responses/quotaExceeded"
|
||||
// "423":
|
||||
// "$ref": "#/responses/repoArchivedError"
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@ import (
|
|||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
perm_model "code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
gitea_context "code.gitea.io/gitea/services/context"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
|
@ -47,6 +49,8 @@ type preReceiveContext struct {
|
|||
|
||||
opts *private.HookOptions
|
||||
|
||||
isOverQuota bool
|
||||
|
||||
branchName string
|
||||
}
|
||||
|
||||
|
@ -140,6 +144,36 @@ func (ctx *preReceiveContext) assertPushOptions() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (ctx *preReceiveContext) checkQuota() error {
|
||||
if !setting.Quota.Enabled {
|
||||
ctx.isOverQuota = false
|
||||
return nil
|
||||
}
|
||||
|
||||
if !ctx.loadPusherAndPermission() {
|
||||
ctx.isOverQuota = true
|
||||
return nil
|
||||
}
|
||||
|
||||
ok, err := quota_model.EvaluateForUser(ctx, ctx.PrivateContext.Repo.Repository.OwnerID, quota_model.LimitSubjectSizeReposAll)
|
||||
if err != nil {
|
||||
log.Error("quota_model.EvaluateForUser: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
UserMsg: "Error checking user quota",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.isOverQuota = !ok
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *preReceiveContext) quotaExceeded() {
|
||||
ctx.JSON(http.StatusRequestEntityTooLarge, private.Response{
|
||||
UserMsg: "Quota exceeded",
|
||||
})
|
||||
}
|
||||
|
||||
// HookPreReceive checks whether a individual commit is acceptable
|
||||
func HookPreReceive(ctx *gitea_context.PrivateContext) {
|
||||
opts := web.GetForm(ctx).(*private.HookOptions)
|
||||
|
@ -156,6 +190,10 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
|
|||
}
|
||||
log.Trace("Git push options validation succeeded")
|
||||
|
||||
if err := ourCtx.checkQuota(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Iterate across the provided old commit IDs
|
||||
for i := range opts.OldCommitIDs {
|
||||
oldCommitID := opts.OldCommitIDs[i]
|
||||
|
@ -170,6 +208,10 @@ func HookPreReceive(ctx *gitea_context.PrivateContext) {
|
|||
case git.SupportProcReceive && refFullName.IsFor():
|
||||
preReceiveFor(ourCtx, oldCommitID, newCommitID, refFullName)
|
||||
default:
|
||||
if ourCtx.isOverQuota {
|
||||
ourCtx.quotaExceeded()
|
||||
return
|
||||
}
|
||||
ourCtx.AssertCanWriteCode()
|
||||
}
|
||||
if ctx.Written() {
|
||||
|
@ -211,6 +253,11 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
|
|||
|
||||
// Allow pushes to non-protected branches
|
||||
if protectBranch == nil {
|
||||
// ...unless the user is over quota, and the operation is not a delete
|
||||
if newCommitID != objectFormat.EmptyObjectID().String() && ctx.isOverQuota {
|
||||
ctx.quotaExceeded()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
protectBranch.Repo = repo
|
||||
|
@ -452,6 +499,15 @@ func preReceiveTag(ctx *preReceiveContext, oldCommitID, newCommitID string, refF
|
|||
})
|
||||
return
|
||||
}
|
||||
|
||||
// If the user is over quota, and the push isn't a tag deletion, deny it
|
||||
if ctx.isOverQuota {
|
||||
objectFormat := ctx.Repo.GetObjectFormat()
|
||||
if newCommitID != objectFormat.EmptyObjectID().String() {
|
||||
ctx.quotaExceeded()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func preReceiveFor(ctx *preReceiveContext, oldCommitID, newCommitID string, refFullName git.RefName) { //nolint:unparam
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"code.gitea.io/gitea/models"
|
||||
admin_model "code.gitea.io/gitea/models/admin"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
|
@ -170,6 +171,10 @@ func MigratePost(ctx *context.Context) {
|
|||
|
||||
tpl := base.TplName("repo/migrate/" + form.Service.Name())
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, ctxUser.ID, ctxUser.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, tpl)
|
||||
return
|
||||
|
@ -260,6 +265,25 @@ func setMigrationContextData(ctx *context.Context, serviceType structs.GitServic
|
|||
}
|
||||
|
||||
func MigrateRetryPost(ctx *context.Context) {
|
||||
ok, err := quota_model.EvaluateForUser(ctx, ctx.Repo.Repository.OwnerID, quota_model.LimitSubjectSizeReposAll)
|
||||
if err != nil {
|
||||
log.Error("quota_model.EvaluateForUser: %v", err)
|
||||
ctx.ServerError("quota_model.EvaluateForUser", err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
if err := task.SetMigrateTaskMessage(ctx, ctx.Repo.Repository.ID, ctx.Locale.TrString("repo.settings.pull_mirror_sync_quota_exceeded")); err != nil {
|
||||
log.Error("SetMigrateTaskMessage failed: %v", err)
|
||||
ctx.ServerError("task.SetMigrateTaskMessage", err)
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusRequestEntityTooLarge, map[string]any{
|
||||
"ok": false,
|
||||
"error": ctx.Tr("repo.settings.pull_mirror_sync_quota_exceeded"),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := task.RetryMigrateTask(ctx, ctx.Repo.Repository.ID); err != nil {
|
||||
log.Error("Retry task failed: %v", err)
|
||||
ctx.ServerError("task.RetryMigrateTask", err)
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
pull_model "code.gitea.io/gitea/models/pull"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -250,6 +251,10 @@ func ForkPost(ctx *context.Context) {
|
|||
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, ctxUser.ID, ctxUser.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, tplFork)
|
||||
return
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
git_model "code.gitea.io/gitea/models/git"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -240,6 +241,10 @@ func CreatePost(ctx *context.Context) {
|
|||
}
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, ctxUser.ID, ctxUser.Name) {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(http.StatusOK, tplCreate)
|
||||
return
|
||||
|
@ -363,49 +368,56 @@ func ActionTransfer(accept bool) func(ctx *context.Context) {
|
|||
action = "reject_transfer"
|
||||
}
|
||||
|
||||
err := acceptOrRejectRepoTransfer(ctx, accept)
|
||||
ok, err := acceptOrRejectRepoTransfer(ctx, accept)
|
||||
if err != nil {
|
||||
ctx.ServerError(fmt.Sprintf("Action (%s)", action), err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.RedirectToFirst(ctx.FormString("redirect_to"), ctx.Repo.RepoLink)
|
||||
}
|
||||
}
|
||||
|
||||
func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error {
|
||||
func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) (bool, error) {
|
||||
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
|
||||
if err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := repoTransfer.LoadAttributes(ctx); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer) {
|
||||
return errors.New("user does not have enough permissions")
|
||||
return false, errors.New("user does not have enough permissions")
|
||||
}
|
||||
|
||||
if accept {
|
||||
if !ctx.CheckQuota(quota_model.LimitSubjectSizeReposAll, ctx.Doer.ID, ctx.Doer.Name) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
ctx.Repo.GitRepo = nil
|
||||
}
|
||||
|
||||
if err := repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success"))
|
||||
} else {
|
||||
if err := repo_service.CancelRepositoryTransfer(ctx, ctx.Repo.Repository); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected"))
|
||||
}
|
||||
|
||||
ctx.Redirect(ctx.Repo.Repository.Link())
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// RedirectDownload return a file based on the following infos:
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -518,6 +519,20 @@ func SettingsPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
ok, err := quota_model.EvaluateForUser(ctx, repo.OwnerID, quota_model.LimitSubjectSizeReposAll)
|
||||
if err != nil {
|
||||
ctx.ServerError("quota_model.EvaluateForUser", err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
// 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
|
||||
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.pull_mirror_sync_quota_exceeded"), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
mirror_service.AddPullMirrorToQueue(repo.ID)
|
||||
|
||||
ctx.Flash.Info(ctx.Tr("repo.settings.pull_mirror_sync_in_progress", repo.OriginalURL))
|
||||
|
@ -828,6 +843,17 @@ func SettingsPost(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check the quota of the new owner
|
||||
ok, err := quota_model.EvaluateForUser(ctx, newOwner.ID, quota_model.LimitSubjectSizeReposAll)
|
||||
if err != nil {
|
||||
ctx.ServerError("quota_model.EvaluateForUser", err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_quota_exceeded", newOwner.Name), tplSettingsOptions, &form)
|
||||
return
|
||||
}
|
||||
|
||||
// Close the GitRepo if open
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
quota_model "code.gitea.io/gitea/models/quota"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/metrics"
|
||||
|
@ -1196,7 +1197,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
|
||||
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
|
||||
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
|
||||
m.Post("/attachments", repo.UploadIssueAttachment)
|
||||
m.Post("/attachments", context.EnforceQuotaWeb(quota_model.LimitSubjectSizeAssetsAttachmentsIssues, context.QuotaTargetRepo), repo.UploadIssueAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
||||
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
|
||||
|
@ -1244,9 +1245,9 @@ func registerRoutes(m *web.Route) {
|
|||
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
||||
m.Combo("/_cherrypick/{sha:([a-f0-9]{4,64})}/*").Get(repo.CherryPick).
|
||||
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
||||
}, repo.MustBeEditable, repo.CommonEditorData)
|
||||
}, repo.MustBeEditable, repo.CommonEditorData, context.EnforceQuotaWeb(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo))
|
||||
m.Group("", func() {
|
||||
m.Post("/upload-file", repo.UploadFileToServer)
|
||||
m.Post("/upload-file", context.EnforceQuotaWeb(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo), repo.UploadFileToServer)
|
||||
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
||||
}, repo.MustBeEditable, repo.MustBeAbleToUpload)
|
||||
}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived())
|
||||
|
@ -1256,7 +1257,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch)
|
||||
m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch)
|
||||
m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch)
|
||||
}, web.Bind(forms.NewBranchForm{}))
|
||||
}, web.Bind(forms.NewBranchForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo))
|
||||
m.Post("/delete", repo.DeleteBranchPost)
|
||||
m.Post("/restore", repo.RestoreBranchPost)
|
||||
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
|
||||
|
@ -1288,16 +1289,17 @@ func registerRoutes(m *web.Route) {
|
|||
m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, repo.GetAttachment)
|
||||
m.Get("/releases/download/{vTag}/{fileName}", repo.MustBeNotEmpty, repo.RedirectDownload)
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
|
||||
m.Combo("/new", context.EnforceQuotaWeb(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo)).
|
||||
Get(repo.NewRelease).
|
||||
Post(web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
|
||||
m.Post("/delete", repo.DeleteRelease)
|
||||
m.Post("/attachments", repo.UploadReleaseAttachment)
|
||||
m.Post("/attachments", context.EnforceQuotaWeb(quota_model.LimitSubjectSizeAssetsAttachmentsReleases, context.QuotaTargetRepo), repo.UploadReleaseAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef())
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache)
|
||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache, context.EnforceQuotaWeb(quota_model.LimitSubjectSizeReposAll, context.QuotaTargetRepo))
|
||||
}, ignSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoReleaseReader)
|
||||
|
||||
// to maintain compatibility with old attachments
|
||||
|
@ -1410,10 +1412,10 @@ func registerRoutes(m *web.Route) {
|
|||
m.Group("/wiki", func() {
|
||||
m.Combo("/").
|
||||
Get(repo.Wiki).
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeWiki, context.QuotaTargetRepo), repo.WikiPost)
|
||||
m.Combo("/*").
|
||||
Get(repo.Wiki).
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeWiki, context.QuotaTargetRepo), repo.WikiPost)
|
||||
m.Get("/commit/{sha:[a-f0-9]{4,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||
m.Get("/commit/{sha:[a-f0-9]{4,64}}.{ext:patch|diff}", repo.RawDiff)
|
||||
}, repo.MustEnableWiki, func(ctx *context.Context) {
|
||||
|
@ -1490,7 +1492,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Get("/list", context.RepoRef(), repo.GetPullCommits)
|
||||
m.Get("/{sha:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
|
||||
})
|
||||
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
|
||||
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MergePullRequest)
|
||||
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
|
||||
m.Post("/update", repo.UpdatePullRequest)
|
||||
m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue