This commit is contained in:
@@ -13,31 +13,34 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/label"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
actions_service "code.gitea.io/gitea/services/actions"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
feed_service "code.gitea.io/gitea/services/feed"
|
||||
"code.gitea.io/gitea/services/issue"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
activities_model "gitea.dev/models/activities"
|
||||
"gitea.dev/models/db"
|
||||
"gitea.dev/models/organization"
|
||||
"gitea.dev/models/perm"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
unit_model "gitea.dev/models/unit"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/gitrepo"
|
||||
"gitea.dev/modules/label"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/optional"
|
||||
repo_module "gitea.dev/modules/repository"
|
||||
"gitea.dev/modules/setting"
|
||||
api "gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/util"
|
||||
"gitea.dev/modules/validation"
|
||||
"gitea.dev/modules/web"
|
||||
"gitea.dev/routers/api/v1/utils"
|
||||
actions_service "gitea.dev/services/actions"
|
||||
"gitea.dev/services/context"
|
||||
"gitea.dev/services/convert"
|
||||
feed_service "gitea.dev/services/feed"
|
||||
"gitea.dev/services/issue"
|
||||
"gitea.dev/services/migrations"
|
||||
mirror_service "gitea.dev/services/mirror"
|
||||
repo_service "gitea.dev/services/repository"
|
||||
)
|
||||
|
||||
// Search repositories via options
|
||||
@@ -170,7 +173,7 @@ func Search(ctx *context.APIContext) {
|
||||
opts.Collaborate = optional.Some(true)
|
||||
case "":
|
||||
default:
|
||||
ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("Invalid search mode: \"%s\"", mode))
|
||||
ctx.APIError(http.StatusUnprocessableEntity, "invalid search mode")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -182,24 +185,11 @@ func Search(ctx *context.APIContext) {
|
||||
opts.IsPrivate = optional.Some(ctx.FormBool("is_private"))
|
||||
}
|
||||
|
||||
sortMode := ctx.FormString("sort")
|
||||
if len(sortMode) > 0 {
|
||||
sortOrder := ctx.FormString("order")
|
||||
if len(sortOrder) == 0 {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
if searchModeMap, ok := repo_model.OrderByMap[sortOrder]; ok {
|
||||
if orderBy, ok := searchModeMap[sortMode]; ok {
|
||||
opts.OrderBy = orderBy
|
||||
} else {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("Invalid sort mode: \"%s\"", sortMode))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("Invalid sort order: \"%s\"", sortOrder))
|
||||
return
|
||||
}
|
||||
orderBy, ok := utils.ResolveSortOrder(ctx, repo_model.OrderByMap, "")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
opts.OrderBy = orderBy
|
||||
|
||||
repos, count, err := repo_model.SearchRepository(ctx, opts)
|
||||
if err != nil {
|
||||
@@ -244,7 +234,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||
|
||||
// If the readme template does not exist, a 400 will be returned.
|
||||
if opt.AutoInit && len(opt.Readme) > 0 && !slices.Contains(repo_module.Readmes, opt.Readme) {
|
||||
ctx.APIError(http.StatusBadRequest, fmt.Errorf("readme template does not exist, available templates: %v", repo_module.Readmes))
|
||||
ctx.APIError(http.StatusBadRequest, fmt.Sprintf("readme template does not exist, available templates: %v", repo_module.Readmes))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -260,7 +250,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||
DefaultBranch: opt.DefaultBranch,
|
||||
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
||||
IsTemplate: opt.Template,
|
||||
ObjectFormatName: opt.ObjectFormatName,
|
||||
ObjectFormatName: string(opt.ObjectFormatName),
|
||||
})
|
||||
if err != nil {
|
||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||
@@ -268,9 +258,9 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||
} else if db.IsErrNameReserved(err) ||
|
||||
db.IsErrNamePatternNotAllowed(err) ||
|
||||
label.IsErrTemplateLoad(err) {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
} else if errors.Is(err, util.ErrPermissionDenied) {
|
||||
ctx.APIError(http.StatusForbidden, err)
|
||||
ctx.APIError(http.StatusForbidden, err.Error())
|
||||
} else {
|
||||
ctx.APIErrorInternal(err)
|
||||
}
|
||||
@@ -423,7 +413,7 @@ func Generate(ctx *context.APIContext) {
|
||||
ctx.APIError(http.StatusConflict, "The repository with the same name already exists.")
|
||||
} else if db.IsErrNameReserved(err) ||
|
||||
db.IsErrNamePatternNotAllowed(err) {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
} else {
|
||||
ctx.APIErrorInternal(err)
|
||||
}
|
||||
@@ -630,7 +620,11 @@ func Edit(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.MirrorInterval != nil || opts.EnablePrune != nil {
|
||||
if opts.MirrorInterval != nil ||
|
||||
opts.EnablePrune != nil ||
|
||||
opts.MirrorUsername != nil ||
|
||||
opts.MirrorPassword != nil ||
|
||||
opts.MirrorToken != nil {
|
||||
if err := updateMirror(ctx, opts); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -658,13 +652,13 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
|
||||
if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
|
||||
switch {
|
||||
case repo_model.IsErrRepoAlreadyExist(err):
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
case db.IsErrNameReserved(err):
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
case db.IsErrNamePatternNotAllowed(err):
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
default:
|
||||
ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("ChangeRepositoryName: %w", err))
|
||||
ctx.APIError(http.StatusUnprocessableEntity, fmt.Sprintf("ChangeRepositoryName: %v", err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -698,7 +692,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
|
||||
// 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 := errors.New("cannot change private repository to public")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -760,14 +754,14 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
if opts.HasIssues != nil {
|
||||
if *opts.HasIssues && opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
||||
// Check that values are valid
|
||||
if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||
if !validation.IsValidURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||
err := errors.New("External tracker URL not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
|
||||
err := errors.New("External tracker URL format not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -822,7 +816,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
if opts.HasWiki != nil {
|
||||
if *opts.HasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
||||
// Check that values are valid
|
||||
if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
|
||||
if !validation.IsValidURL(opts.ExternalWiki.ExternalWikiURL) {
|
||||
err := errors.New("External wiki URL not valid")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, "Invalid external wiki URL")
|
||||
return err
|
||||
@@ -893,10 +887,20 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
optional.AssignPtrValue(changed, &config.AllowFastForwardOnly, opts.AllowFastForwardOnly)
|
||||
optional.AssignPtrValue(changed, &config.AllowManualMerge, opts.AllowManualMerge)
|
||||
optional.AssignPtrValue(changed, &config.AutodetectManualMerge, opts.AutodetectManualMerge)
|
||||
optional.AssignPtrValue(changed, &config.AllowMergeUpdate, opts.AllowMergeUpdate)
|
||||
optional.AssignPtrValue(changed, &config.AllowRebaseUpdate, opts.AllowRebaseUpdate)
|
||||
optional.AssignPtrValue(changed, &config.DefaultDeleteBranchAfterMerge, opts.DefaultDeleteBranchAfterMerge)
|
||||
optional.AssignPtrValue(changed, &config.DefaultAllowMaintainerEdit, opts.DefaultAllowMaintainerEdit)
|
||||
optional.AssignPtrString(changed, &config.DefaultMergeStyle, opts.DefaultMergeStyle)
|
||||
optional.AssignPtrString(changed, &config.DefaultUpdateStyle, opts.DefaultUpdateStyle)
|
||||
// only validate update-style fields when the caller is actually changing one of them,
|
||||
// so unrelated PATCH calls don't reject historical configs.
|
||||
if opts.AllowMergeUpdate != nil || opts.AllowRebaseUpdate != nil || opts.DefaultUpdateStyle != nil {
|
||||
if err := config.ValidateUpdateSettings(); err != nil {
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
if *changed || mustInsertPullRequestUnit {
|
||||
units = append(units, repo_model.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
@@ -984,7 +988,7 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
||||
if opts.Archived != nil {
|
||||
if repo.IsMirror {
|
||||
err := errors.New("repo is a mirror, cannot archive/un-archive")
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
if *opts.Archived {
|
||||
@@ -1038,14 +1042,14 @@ func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
interval, err := time.ParseDuration(*opts.MirrorInterval)
|
||||
if err != nil {
|
||||
log.Error("Wrong format for MirrorInternal Sent: %s", err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the provided duration is not too short
|
||||
if interval != 0 && interval < setting.Mirror.MinInterval {
|
||||
err := fmt.Errorf("invalid mirror interval: %s is below minimum interval: %s", interval, setting.Mirror.MinInterval)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1061,10 +1065,61 @@ func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
log.Trace("Repository %s Mirror[%d] Set EnablePrune: %t", repo.FullName(), mirror.ID, mirror.EnablePrune)
|
||||
}
|
||||
|
||||
authUpdateRequested := opts.MirrorPassword != nil || opts.MirrorToken != nil || opts.MirrorUsername != nil
|
||||
if authUpdateRequested {
|
||||
remoteURL, err := gitrepo.GitRemoteGetURL(ctx, repo, mirror.GetRemoteName())
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
authUsername := ""
|
||||
if opts.MirrorUsername != nil {
|
||||
authUsername = *opts.MirrorUsername
|
||||
} else if remoteURL.User != nil {
|
||||
authUsername = remoteURL.User.Username()
|
||||
}
|
||||
|
||||
authPassword := ""
|
||||
authToken := ""
|
||||
if opts.MirrorPassword != nil {
|
||||
authPassword = *opts.MirrorPassword
|
||||
}
|
||||
if opts.MirrorToken != nil {
|
||||
authToken = *opts.MirrorToken
|
||||
}
|
||||
|
||||
if opts.MirrorPassword == nil && opts.MirrorToken == nil && remoteURL.User != nil && (authUsername == "" || authUsername == remoteURL.User.Username()) {
|
||||
authPassword, _ = remoteURL.User.Password()
|
||||
}
|
||||
|
||||
if authToken != "" {
|
||||
authPassword = authToken
|
||||
}
|
||||
|
||||
composedAddress, err := git.ParseRemoteAddr(repo.OriginalURL, authUsername, authPassword)
|
||||
if err == nil {
|
||||
err = migrations.IsMigrateURLAllowed(composedAddress, ctx.Doer)
|
||||
}
|
||||
if err != nil {
|
||||
handleRemoteAddrError(ctx, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mirror_service.UpdateAddress(ctx, mirror, composedAddress); err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if sanitized, err := util.SanitizeURL(repo.OriginalURL); err == nil {
|
||||
mirror.RemoteAddress = sanitized
|
||||
}
|
||||
}
|
||||
|
||||
// finally update the mirror in the DB
|
||||
if err := repo_model.UpdateMirror(ctx, mirror); err != nil {
|
||||
log.Error("Failed to Set Mirror Interval: %s", err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err)
|
||||
ctx.APIError(http.StatusUnprocessableEntity, err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user