diff --git a/server/api/agent.go b/server/api/agent.go index c1d3baa52..52731a6b5 100644 --- a/server/api/agent.go +++ b/server/api/agent.go @@ -21,7 +21,6 @@ import ( "github.com/gin-gonic/gin" "github.com/gorilla/securecookie" - "github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/router/middleware/session" "github.com/woodpecker-ci/woodpecker/server/store" @@ -45,7 +44,7 @@ func GetAgent(c *gin.Context) { agent, err := store.FromContext(c).AgentFind(agentID) if err != nil { - c.String(http.StatusNotFound, "Cannot find agent. %s", err) + handleDbGetError(c, err) return } c.JSON(http.StatusOK, agent) @@ -69,7 +68,7 @@ func PatchAgent(c *gin.Context) { agent, err := _store.AgentFind(agentID) if err != nil { - c.AbortWithStatus(http.StatusNotFound) + handleDbGetError(c, err) return } agent.Name = in.Name @@ -121,12 +120,12 @@ func DeleteAgent(c *gin.Context) { agent, err := _store.AgentFind(agentID) if err != nil { - c.String(http.StatusNotFound, "Cannot find user. %s", err) + handleDbGetError(c, err) return } if err = _store.AgentDelete(agent); err != nil { c.String(http.StatusInternalServerError, "Error deleting user. %s", err) return } - c.String(http.StatusOK, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/badge.go b/server/api/badge.go index 35a344e35..4ff4f73ba 100644 --- a/server/api/badge.go +++ b/server/api/badge.go @@ -19,10 +19,12 @@ package api import ( + "errors" "fmt" "net/http" "github.com/rs/zerolog/log" + "github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/gin-gonic/gin" @@ -36,7 +38,11 @@ func GetBadge(c *gin.Context) { _store := store.FromContext(c) repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name")) if err != nil || !repo.IsActive { - c.AbortWithStatus(404) + if err == nil || errors.Is(err, types.RecordNotExist) { + c.AbortWithStatus(http.StatusNotFound) + return + } + _ = c.AbortWithError(http.StatusInternalServerError, err) return } @@ -63,17 +69,17 @@ func GetCC(c *gin.Context) { _store := store.FromContext(c) repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name")) if err != nil { - c.AbortWithStatus(404) + handleDbGetError(c, err) return } pipelines, err := _store.GetPipelineList(repo, 1) if err != nil || len(pipelines) == 0 { - c.AbortWithStatus(404) + c.AbortWithStatus(http.StatusNotFound) return } url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number) cc := ccmenu.New(repo, pipelines[0], url) - c.XML(200, cc) + c.XML(http.StatusOK, cc) } diff --git a/server/api/cron.go b/server/api/cron.go index ea141ddbc..bc15389c0 100644 --- a/server/api/cron.go +++ b/server/api/cron.go @@ -34,16 +34,16 @@ func GetCron(c *gin.Context) { repo := session.Repo(c) id, err := strconv.ParseInt(c.Param("cron"), 10, 64) if err != nil { - c.String(400, "Error parsing cron id. %s", err) + c.String(http.StatusBadRequest, "Error parsing cron id. %s", err) return } cron, err := store.FromContext(c).CronFind(repo, id) if err != nil { - c.String(404, "Error getting cron %q. %s", id, err) + handleDbGetError(c, err) return } - c.JSON(200, cron) + c.JSON(http.StatusOK, cron) } // RunCron starts a cron job now. @@ -52,13 +52,13 @@ func RunCron(c *gin.Context) { _store := store.FromContext(c) id, err := strconv.ParseInt(c.Param("cron"), 10, 64) if err != nil { - c.String(400, "Error parsing cron id. %s", err) + c.String(http.StatusBadRequest, "Error parsing cron id. %s", err) return } cron, err := _store.CronFind(repo, id) if err != nil { - c.String(http.StatusNotFound, "Error getting cron %q. %s", id, err) + handleDbGetError(c, err) return } @@ -74,14 +74,14 @@ func RunCron(c *gin.Context) { return } - c.JSON(200, pl) + c.JSON(http.StatusOK, pl) } // PostCron persists the cron job to the database. func PostCron(c *gin.Context) { repo := session.Repo(c) user := session.User(c) - store := store.FromContext(c) + _store := store.FromContext(c) forge := server.Config.Services.Forge in := new(model.Cron) @@ -97,13 +97,13 @@ func PostCron(c *gin.Context) { Branch: in.Branch, } if err := cron.Validate(); err != nil { - c.String(400, "Error inserting cron. validate failed: %s", err) + c.String(http.StatusUnprocessableEntity, "Error inserting cron. validate failed: %s", err) return } nextExec, err := cronScheduler.CalcNewNext(in.Schedule, time.Now()) if err != nil { - c.String(400, "Error inserting cron. schedule could not parsed: %s", err) + c.String(http.StatusBadRequest, "Error inserting cron. schedule could not parsed: %s", err) return } cron.NextExec = nextExec.Unix() @@ -112,28 +112,28 @@ func PostCron(c *gin.Context) { // check if branch exists on forge _, err := forge.BranchHead(c, user, repo, in.Branch) if err != nil { - c.String(400, "Error inserting cron. branch not resolved: %s", err) + c.String(http.StatusBadRequest, "Error inserting cron. branch not resolved: %s", err) return } } - if err := store.CronCreate(cron); err != nil { - c.String(500, "Error inserting cron %q. %s", in.Name, err) + if err := _store.CronCreate(cron); err != nil { + c.String(http.StatusInternalServerError, "Error inserting cron %q. %s", in.Name, err) return } - c.JSON(200, cron) + c.JSON(http.StatusOK, cron) } // PatchCron updates the cron job in the database. func PatchCron(c *gin.Context) { repo := session.Repo(c) user := session.User(c) - store := store.FromContext(c) + _store := store.FromContext(c) forge := server.Config.Services.Forge id, err := strconv.ParseInt(c.Param("cron"), 10, 64) if err != nil { - c.String(400, "Error parsing cron id. %s", err) + c.String(http.StatusBadRequest, "Error parsing cron id. %s", err) return } @@ -144,16 +144,16 @@ func PatchCron(c *gin.Context) { return } - cron, err := store.CronFind(repo, id) + cron, err := _store.CronFind(repo, id) if err != nil { - c.String(404, "Error getting cron %d. %s", id, err) + handleDbGetError(c, err) return } if in.Branch != "" { // check if branch exists on forge _, err := forge.BranchHead(c, user, repo, in.Branch) if err != nil { - c.String(400, "Error inserting cron. branch not resolved: %s", err) + c.String(http.StatusBadRequest, "Error inserting cron. branch not resolved: %s", err) return } cron.Branch = in.Branch @@ -162,7 +162,7 @@ func PatchCron(c *gin.Context) { cron.Schedule = in.Schedule nextExec, err := cronScheduler.CalcNewNext(in.Schedule, time.Now()) if err != nil { - c.String(400, "Error inserting cron. schedule could not parsed: %s", err) + c.String(http.StatusBadRequest, "Error inserting cron. schedule could not parsed: %s", err) return } cron.NextExec = nextExec.Unix() @@ -173,14 +173,14 @@ func PatchCron(c *gin.Context) { cron.CreatorID = user.ID if err := cron.Validate(); err != nil { - c.String(400, "Error inserting cron. validate failed: %s", err) + c.String(http.StatusUnprocessableEntity, "Error inserting cron. validate failed: %s", err) return } - if err := store.CronUpdate(repo, cron); err != nil { - c.String(500, "Error updating cron %q. %s", in.Name, err) + if err := _store.CronUpdate(repo, cron); err != nil { + c.String(http.StatusInternalServerError, "Error updating cron %q. %s", in.Name, err) return } - c.JSON(200, cron) + c.JSON(http.StatusOK, cron) } // GetCronList gets the cron job list from the database and writes @@ -189,10 +189,10 @@ func GetCronList(c *gin.Context) { repo := session.Repo(c) list, err := store.FromContext(c).CronList(repo) if err != nil { - c.String(500, "Error getting cron list. %s", err) + c.String(http.StatusInternalServerError, "Error getting cron list. %s", err) return } - c.JSON(200, list) + c.JSON(http.StatusOK, list) } // DeleteCron deletes the named cron job from the database. @@ -200,12 +200,12 @@ func DeleteCron(c *gin.Context) { repo := session.Repo(c) id, err := strconv.ParseInt(c.Param("cron"), 10, 64) if err != nil { - c.String(400, "Error parsing cron id. %s", err) + c.String(http.StatusBadRequest, "Error parsing cron id. %s", err) return } if err := store.FromContext(c).CronDelete(repo, id); err != nil { - c.String(500, "Error deleting cron %d. %s", id, err) + c.String(http.StatusInternalServerError, "Error deleting cron %d. %s", id, err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/file.go b/server/api/file.go index 99ce7dcee..9bc47dee8 100644 --- a/server/api/file.go +++ b/server/api/file.go @@ -23,7 +23,6 @@ import ( "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" - "github.com/woodpecker-ci/woodpecker/server/router/middleware/session" "github.com/woodpecker-ci/woodpecker/server/store" ) @@ -40,7 +39,7 @@ func FileList(c *gin.Context) { repo := session.Repo(c) pipeline, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) + handleDbGetError(c, err) return } @@ -79,7 +78,7 @@ func FileGet(c *gin.Context) { pipeline, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) + handleDbGetError(c, err) return } @@ -91,18 +90,18 @@ func FileGet(c *gin.Context) { file, err := _store.FileFind(step, name) if err != nil { - c.String(404, "Error getting file %q. %s", name, err) + c.String(http.StatusNotFound, "Error getting file %q. %s", name, err) return } if !raw { - c.JSON(200, file) + c.JSON(http.StatusOK, file) return } rc, err := _store.FileRead(step, file.Name) if err != nil { - c.String(404, "Error getting file stream %q. %s", name, err) + c.String(http.StatusNotFound, "Error getting file stream %q. %s", name, err) return } defer rc.Close() diff --git a/server/api/global_secret.go b/server/api/global_secret.go index b1ea3b3ac..fc90d2ffc 100644 --- a/server/api/global_secret.go +++ b/server/api/global_secret.go @@ -17,10 +17,9 @@ package api import ( "net/http" + "github.com/gin-gonic/gin" "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" - - "github.com/gin-gonic/gin" ) // GetGlobalSecretList gets the global secret list from @@ -45,10 +44,10 @@ func GetGlobalSecret(c *gin.Context) { name := c.Param("secret") secret, err := server.Config.Services.Secrets.GlobalSecretFind(name) if err != nil { - c.String(404, "Error getting global secret %q. %s", name, err) + handleDbGetError(c, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // PostGlobalSecret persists a global secret to the database. @@ -66,14 +65,14 @@ func PostGlobalSecret(c *gin.Context) { PluginsOnly: in.PluginsOnly, } if err := secret.Validate(); err != nil { - c.String(400, "Error inserting global secret. %s", err) + c.String(http.StatusBadRequest, "Error inserting global secret. %s", err) return } if err := server.Config.Services.Secrets.GlobalSecretCreate(secret); err != nil { - c.String(500, "Error inserting global secret %q. %s", in.Name, err) + c.String(http.StatusInternalServerError, "Error inserting global secret %q. %s", in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // PatchGlobalSecret updates a global secret in the database. @@ -89,7 +88,7 @@ func PatchGlobalSecret(c *gin.Context) { secret, err := server.Config.Services.Secrets.GlobalSecretFind(name) if err != nil { - c.String(404, "Error getting global secret %q. %s", name, err) + handleDbGetError(c, err) return } if in.Value != "" { @@ -104,22 +103,22 @@ func PatchGlobalSecret(c *gin.Context) { secret.PluginsOnly = in.PluginsOnly if err := secret.Validate(); err != nil { - c.String(400, "Error updating global secret. %s", err) + c.String(http.StatusBadRequest, "Error updating global secret. %s", err) return } if err := server.Config.Services.Secrets.GlobalSecretUpdate(secret); err != nil { - c.String(500, "Error updating global secret %q. %s", in.Name, err) + c.String(http.StatusInternalServerError, "Error updating global secret %q. %s", in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // DeleteGlobalSecret deletes the named global secret from the database. func DeleteGlobalSecret(c *gin.Context) { name := c.Param("secret") if err := server.Config.Services.Secrets.GlobalSecretDelete(name); err != nil { - c.String(500, "Error deleting global secret %q. %s", name, err) + c.String(http.StatusInternalServerError, "Error deleting global secret %q. %s", name, err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/helper.go b/server/api/helper.go index e123e63c5..e55572346 100644 --- a/server/api/helper.go +++ b/server/api/helper.go @@ -20,6 +20,7 @@ import ( "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" + "github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/forge" @@ -40,6 +41,14 @@ func handlePipelineErr(c *gin.Context, err error) { } } +func handleDbGetError(c *gin.Context, err error) { + if errors.Is(err, types.RecordNotExist) { + c.AbortWithStatus(http.StatusNotFound) + return + } + _ = c.AbortWithError(http.StatusInternalServerError, err) +} + // if the forge has a refresh token, the current access token may be stale. // Therefore, we should refresh prior to dispatching the job. func refreshUserToken(c *gin.Context, user *model.User) { diff --git a/server/api/hook.go b/server/api/hook.go index ff4c73a0f..043a5c6b0 100644 --- a/server/api/hook.go +++ b/server/api/hook.go @@ -42,7 +42,7 @@ func init() { } func GetQueueInfo(c *gin.Context) { - c.IndentedJSON(200, + c.IndentedJSON(http.StatusOK, server.Config.Services.Queue.Info(c), ) } @@ -179,6 +179,6 @@ func PostHook(c *gin.Context) { if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, pl) + c.JSON(http.StatusOK, pl) } } diff --git a/server/api/login.go b/server/api/login.go index 271fe04a1..9419b8025 100644 --- a/server/api/login.go +++ b/server/api/login.go @@ -16,12 +16,14 @@ package api import ( "encoding/base32" + "errors" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gorilla/securecookie" "github.com/rs/zerolog/log" + "github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" @@ -52,7 +54,7 @@ func HandleAuth(c *gin.Context) { tmpuser, err := server.Config.Services.Forge.Login(c, c.Writer, c.Request) if err != nil { log.Error().Msgf("cannot authenticate user. %s", err) - c.Redirect(303, "/login?error=oauth_error") + c.Redirect(http.StatusSeeOther, "/login?error=oauth_error") return } // this will happen when the user is redirected by the forge as @@ -65,10 +67,15 @@ func HandleAuth(c *gin.Context) { // get the user from the database u, err := _store.GetUserLogin(tmpuser.Login) if err != nil { + if !errors.Is(err, types.RecordNotExist) { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + // if self-registration is disabled we should return a not authorized error if !config.Open && !config.IsAdmin(tmpuser) { log.Error().Msgf("cannot register %s. registration closed", tmpuser.Login) - c.Redirect(303, "/login?error=access_denied") + c.Redirect(http.StatusSeeOther, "/login?error=access_denied") return } @@ -98,7 +105,7 @@ func HandleAuth(c *gin.Context) { // insert the user into the database if err := _store.CreateUser(u); err != nil { log.Error().Msgf("cannot insert %s. %s", u.Login, err) - c.Redirect(303, "/login?error=internal_error") + c.Redirect(http.StatusSeeOther, "/login?error=internal_error") return } } @@ -116,14 +123,14 @@ func HandleAuth(c *gin.Context) { teams, terr := server.Config.Services.Forge.Teams(c, u) if terr != nil || !config.IsMember(teams) { log.Error().Msgf("cannot verify team membership for %s.", u.Login) - c.Redirect(303, "/login?error=access_denied") + c.Redirect(http.StatusSeeOther, "/login?error=access_denied") return } } if err := _store.UpdateUser(u); err != nil { log.Error().Msgf("cannot update %s. %s", u.Login, err) - c.Redirect(303, "/login?error=internal_error") + c.Redirect(http.StatusSeeOther, "/login?error=internal_error") return } @@ -131,19 +138,19 @@ func HandleAuth(c *gin.Context) { tokenString, err := token.New(token.SessToken, u.Login).SignExpires(u.Hash, exp) if err != nil { log.Error().Msgf("cannot create token for %s. %s", u.Login, err) - c.Redirect(303, "/login?error=internal_error") + c.Redirect(http.StatusSeeOther, "/login?error=internal_error") return } httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenString) - c.Redirect(303, "/") + c.Redirect(http.StatusSeeOther, "/") } func GetLogout(c *gin.Context) { httputil.DelCookie(c.Writer, c.Request, "user_sess") httputil.DelCookie(c.Writer, c.Request, "user_last") - c.Redirect(303, "/") + c.Redirect(http.StatusSeeOther, "/") } func GetLoginToken(c *gin.Context) { diff --git a/server/api/org_secret.go b/server/api/org_secret.go index aa5e262bb..e2204a208 100644 --- a/server/api/org_secret.go +++ b/server/api/org_secret.go @@ -17,10 +17,9 @@ package api import ( "net/http" + "github.com/gin-gonic/gin" "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" - - "github.com/gin-gonic/gin" ) // GetOrgSecret gets the named organization secret from the database @@ -32,10 +31,10 @@ func GetOrgSecret(c *gin.Context) { ) secret, err := server.Config.Services.Secrets.OrgSecretFind(owner, name) if err != nil { - c.String(404, "Error getting org %q secret %q. %s", owner, name, err) + handleDbGetError(c, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // GetOrgSecretList gest the organization secret list from @@ -73,14 +72,14 @@ func PostOrgSecret(c *gin.Context) { PluginsOnly: in.PluginsOnly, } if err := secret.Validate(); err != nil { - c.String(400, "Error inserting org %q secret. %s", owner, err) + c.String(http.StatusUnprocessableEntity, "Error inserting org %q secret. %s", owner, err) return } if err := server.Config.Services.Secrets.OrgSecretCreate(owner, secret); err != nil { - c.String(500, "Error inserting org %q secret %q. %s", owner, in.Name, err) + c.String(http.StatusInternalServerError, "Error inserting org %q secret %q. %s", owner, in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // PatchOrgSecret updates an organization secret in the database. @@ -99,7 +98,7 @@ func PatchOrgSecret(c *gin.Context) { secret, err := server.Config.Services.Secrets.OrgSecretFind(owner, name) if err != nil { - c.String(404, "Error getting org %q secret %q. %s", owner, name, err) + handleDbGetError(c, err) return } if in.Value != "" { @@ -114,14 +113,14 @@ func PatchOrgSecret(c *gin.Context) { secret.PluginsOnly = in.PluginsOnly if err := secret.Validate(); err != nil { - c.String(400, "Error updating org %q secret. %s", owner, err) + c.String(http.StatusUnprocessableEntity, "Error updating org %q secret. %s", owner, err) return } if err := server.Config.Services.Secrets.OrgSecretUpdate(owner, secret); err != nil { - c.String(500, "Error updating org %q secret %q. %s", owner, in.Name, err) + c.String(http.StatusInternalServerError, "Error updating org %q secret %q. %s", owner, in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // DeleteOrgSecret deletes the named organization secret from the database. @@ -131,8 +130,8 @@ func DeleteOrgSecret(c *gin.Context) { name = c.Param("secret") ) if err := server.Config.Services.Secrets.OrgSecretDelete(owner, name); err != nil { - c.String(500, "Error deleting org %q secret %q. %s", owner, name, err) + c.String(http.StatusInternalServerError, "Error deleting org %q secret %q. %s", owner, name, err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/pipeline.go b/server/api/pipeline.go index 022852515..4c87c91e8 100644 --- a/server/api/pipeline.go +++ b/server/api/pipeline.go @@ -148,7 +148,7 @@ func GetPipelineLast(c *gin.Context) { pl, err := _store.GetPipelineLast(repo, branch) if err != nil { - c.String(http.StatusInternalServerError, err.Error()) + handleDbGetError(c, err) return } @@ -176,19 +176,19 @@ func GetPipelineLogs(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(404, err) + handleDbGetError(c, err) return } step, err := _store.StepChild(pl, ppid, name) if err != nil { - _ = c.AbortWithError(404, err) + handleDbGetError(c, err) return } rc, err := _store.LogFind(step) if err != nil { - _ = c.AbortWithError(404, err) + handleDbGetError(c, err) return } @@ -211,19 +211,19 @@ func GetStepLogs(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(http.StatusNotFound, err) + handleDbGetError(c, err) return } step, err := _store.StepFind(pl, pid) if err != nil { - _ = c.AbortWithError(http.StatusNotFound, err) + handleDbGetError(c, err) return } rc, err := _store.LogFind(step) if err != nil { - _ = c.AbortWithError(http.StatusNotFound, err) + handleDbGetError(c, err) return } @@ -246,7 +246,7 @@ func GetPipelineConfig(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) + handleDbGetError(c, err) return } @@ -267,7 +267,7 @@ func CancelPipeline(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(http.StatusNotFound, err) + handleDbGetError(c, err) return } @@ -289,7 +289,7 @@ func PostApproval(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(404, err) + handleDbGetError(c, err) return } @@ -297,7 +297,7 @@ func PostApproval(c *gin.Context) { if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, newpipeline) + c.JSON(http.StatusOK, newpipeline) } } @@ -320,17 +320,17 @@ func PostDecline(c *gin.Context) { if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, pl) + c.JSON(http.StatusOK, pl) } } func GetPipelineQueue(c *gin.Context) { out, err := store.FromContext(c).GetPipelineQueue() if err != nil { - c.String(500, "Error getting pipeline queue. %s", err) + c.String(http.StatusInternalServerError, "Error getting pipeline queue. %s", err) return } - c.JSON(200, out) + c.JSON(http.StatusOK, out) } // PostPipeline restarts a pipeline optional with altered event, deploy or environment @@ -346,15 +346,21 @@ func PostPipeline(c *gin.Context) { user, err := _store.GetUser(repo.UserID) if err != nil { - log.Error().Msgf("failure to find repo owner %s. %s", repo.FullName, err) - _ = c.AbortWithError(500, err) + if errors.Is(err, types.RecordNotExist) { + c.AbortWithStatus(http.StatusNotFound) + return + } + _ = c.AbortWithError(http.StatusInternalServerError, err) return } pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - log.Error().Msgf("failure to get pipeline %d. %s", num, err) - _ = c.AbortWithError(404, err) + if errors.Is(err, types.RecordNotExist) { + c.AbortWithStatus(http.StatusNotFound) + return + } + _ = c.AbortWithError(http.StatusInternalServerError, err) return } @@ -394,7 +400,7 @@ func PostPipeline(c *gin.Context) { if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, newpipeline) + c.JSON(http.StatusOK, newpipeline) } } @@ -407,19 +413,19 @@ func DeletePipelineLogs(c *gin.Context) { pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - _ = c.AbortWithError(404, err) + handleDbGetError(c, err) return } steps, err := _store.StepList(pl) if err != nil { - _ = c.AbortWithError(404, err) + _ = c.AbortWithError(http.StatusNotFound, err) return } switch pl.Status { case model.StatusRunning, model.StatusPending: - c.String(400, "Cannot delete logs for a pending or running pipeline") + c.String(http.StatusUnprocessableEntity, "Cannot delete logs for a pending or running pipeline") return } @@ -432,11 +438,11 @@ func DeletePipelineLogs(c *gin.Context) { } } if err != nil { - c.String(400, "There was a problem deleting your logs. %s", err) + c.String(http.StatusInternalServerError, "There was a problem deleting your logs. %s", err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } var deleteStr = `[ diff --git a/server/api/registry.go b/server/api/registry.go index caa4f6c9f..99f901d6d 100644 --- a/server/api/registry.go +++ b/server/api/registry.go @@ -15,7 +15,6 @@ package api import ( - "errors" "net/http" "github.com/gin-gonic/gin" @@ -23,7 +22,6 @@ import ( "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/router/middleware/session" - "github.com/woodpecker-ci/woodpecker/server/store/types" ) // GetRegistry gets the name registry from the database and writes @@ -35,7 +33,7 @@ func GetRegistry(c *gin.Context) { ) registry, err := server.Config.Services.Registries.RegistryFind(repo, name) if err != nil { - c.String(404, "Error getting registry %q. %s", name, err) + handleDbGetError(c, err) return } c.JSON(200, registry.Copy()) @@ -59,14 +57,14 @@ func PostRegistry(c *gin.Context) { Email: in.Email, } if err := registry.Validate(); err != nil { - c.String(400, "Error inserting registry. %s", err) + c.String(http.StatusBadRequest, "Error inserting registry. %s", err) return } if err := server.Config.Services.Registries.RegistryCreate(repo, registry); err != nil { - c.String(500, "Error inserting registry %q. %s", in.Address, err) + c.String(http.StatusInternalServerError, "Error inserting registry %q. %s", in.Address, err) return } - c.JSON(200, in.Copy()) + c.JSON(http.StatusOK, in.Copy()) } // PatchRegistry updates the registry in the database. @@ -85,7 +83,7 @@ func PatchRegistry(c *gin.Context) { registry, err := server.Config.Services.Registries.RegistryFind(repo, name) if err != nil { - c.String(404, "Error getting registry %q. %s", name, err) + handleDbGetError(c, err) return } if in.Username != "" { @@ -102,14 +100,14 @@ func PatchRegistry(c *gin.Context) { } if err := registry.Validate(); err != nil { - c.String(400, "Error updating registry. %s", err) + c.String(http.StatusUnprocessableEntity, "Error updating registry. %s", err) return } if err := server.Config.Services.Registries.RegistryUpdate(repo, registry); err != nil { - c.String(500, "Error updating registry %q. %s", in.Address, err) + c.String(http.StatusInternalServerError, "Error updating registry %q. %s", in.Address, err) return } - c.JSON(200, in.Copy()) + c.JSON(http.StatusOK, in.Copy()) } // GetRegistryList gets the registry list from the database and writes @@ -118,7 +116,7 @@ func GetRegistryList(c *gin.Context) { repo := session.Repo(c) list, err := server.Config.Services.Registries.RegistryList(repo) if err != nil { - c.String(500, "Error getting registry list. %s", err) + c.String(http.StatusInternalServerError, "Error getting registry list. %s", err) return } // copy the registry detail to remove the sensitive @@ -126,7 +124,7 @@ func GetRegistryList(c *gin.Context) { for i, registry := range list { list[i] = registry.Copy() } - c.JSON(200, list) + c.JSON(http.StatusOK, list) } // DeleteRegistry deletes the named registry from the database. @@ -137,12 +135,8 @@ func DeleteRegistry(c *gin.Context) { ) err := server.Config.Services.Registries.RegistryDelete(repo, name) if err != nil { - if errors.Is(err, types.RecordNotExist) { - c.String(404, "no records found, cannot delete registry") - return - } - c.String(500, "Error deleting registry %q. %s", name, err) + c.String(http.StatusInternalServerError, "Error deleting registry %q. %s", name, err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/repo.go b/server/api/repo.go index 10073271a..394215e20 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -263,7 +263,7 @@ func RepairRepo(c *gin.Context) { t := token.New(token.HookToken, repo.FullName) sig, err := t.Sign(repo.Hash) if err != nil { - c.String(500, err.Error()) + c.String(http.StatusInternalServerError, err.Error()) return } @@ -301,7 +301,7 @@ func RepairRepo(c *gin.Context) { log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { - c.String(500, err.Error()) + c.String(http.StatusInternalServerError, err.Error()) return } @@ -355,7 +355,7 @@ func MoveRepo(c *gin.Context) { t := token.New(token.HookToken, repo.FullName) sig, err := t.Sign(repo.Hash) if err != nil { - c.String(500, err.Error()) + c.String(http.StatusInternalServerError, err.Error()) return } @@ -371,7 +371,7 @@ func MoveRepo(c *gin.Context) { log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName) } if err := forge.Activate(c, user, repo, link); err != nil { - c.String(500, err.Error()) + c.String(http.StatusInternalServerError, err.Error()) return } c.Writer.WriteHeader(http.StatusOK) diff --git a/server/api/repo_secret.go b/server/api/repo_secret.go index 15a276d25..bf5142d22 100644 --- a/server/api/repo_secret.go +++ b/server/api/repo_secret.go @@ -19,7 +19,6 @@ import ( "strings" "github.com/gin-gonic/gin" - "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/router/middleware/session" @@ -34,10 +33,10 @@ func GetSecret(c *gin.Context) { ) secret, err := server.Config.Services.Secrets.SecretFind(repo, name) if err != nil { - c.String(404, "Error getting secret %q. %s", name, err) + handleDbGetError(c, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // PostSecret persists the secret to the database. @@ -58,14 +57,14 @@ func PostSecret(c *gin.Context) { PluginsOnly: in.PluginsOnly, } if err := secret.Validate(); err != nil { - c.String(400, "Error inserting secret. %s", err) + c.String(http.StatusUnprocessableEntity, "Error inserting secret. %s", err) return } if err := server.Config.Services.Secrets.SecretCreate(repo, secret); err != nil { - c.String(500, "Error inserting secret %q. %s", in.Name, err) + c.String(http.StatusInternalServerError, "Error inserting secret %q. %s", in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // PatchSecret updates the secret in the database. @@ -84,7 +83,7 @@ func PatchSecret(c *gin.Context) { secret, err := server.Config.Services.Secrets.SecretFind(repo, name) if err != nil { - c.String(404, "Error getting secret %q. %s", name, err) + handleDbGetError(c, err) return } if in.Value != "" { @@ -99,14 +98,14 @@ func PatchSecret(c *gin.Context) { secret.PluginsOnly = in.PluginsOnly if err := secret.Validate(); err != nil { - c.String(400, "Error updating secret. %s", err) + c.String(http.StatusUnprocessableEntity, "Error updating secret. %s", err) return } if err := server.Config.Services.Secrets.SecretUpdate(repo, secret); err != nil { - c.String(500, "Error updating secret %q. %s", in.Name, err) + c.String(http.StatusInternalServerError, "Error updating secret %q. %s", in.Name, err) return } - c.JSON(200, secret.Copy()) + c.JSON(http.StatusOK, secret.Copy()) } // GetSecretList gets the secret list from the database and writes @@ -115,7 +114,7 @@ func GetSecretList(c *gin.Context) { repo := session.Repo(c) list, err := server.Config.Services.Secrets.SecretList(repo) if err != nil { - c.String(500, "Error getting secret list. %s", err) + c.String(http.StatusInternalServerError, "Error getting secret list. %s", err) return } // copy the secret detail to remove the sensitive @@ -123,7 +122,7 @@ func GetSecretList(c *gin.Context) { for i, secret := range list { list[i] = secret.Copy() } - c.JSON(200, list) + c.JSON(http.StatusOK, list) } // DeleteSecret deletes the named secret from the database. @@ -133,8 +132,8 @@ func DeleteSecret(c *gin.Context) { name = c.Param("secret") ) if err := server.Config.Services.Secrets.SecretDelete(repo, name); err != nil { - c.String(500, "Error deleting secret %q. %s", name, err) + c.String(http.StatusInternalServerError, "Error deleting secret %q. %s", name, err) return } - c.String(204, "") + c.String(http.StatusNoContent, "") } diff --git a/server/api/signature_public_key.go b/server/api/signature_public_key.go index c09c36fe5..9e4688407 100644 --- a/server/api/signature_public_key.go +++ b/server/api/signature_public_key.go @@ -37,5 +37,5 @@ func GetSignaturePublicKey(c *gin.Context) { Bytes: b, } - c.String(200, "%s", pem.EncodeToMemory(block)) + c.String(http.StatusOK, "%s", pem.EncodeToMemory(block)) } diff --git a/server/api/stream.go b/server/api/stream.go index 409b16da7..869852ef1 100644 --- a/server/api/stream.go +++ b/server/api/stream.go @@ -48,7 +48,7 @@ func EventStreamSSE(c *gin.Context) { flusher, ok := rw.(http.Flusher) if !ok { - c.String(500, "Streaming not supported") + c.String(http.StatusInternalServerError, "Streaming not supported") return } @@ -131,7 +131,7 @@ func LogStreamSSE(c *gin.Context) { flusher, ok := rw.(http.Flusher) if !ok { - c.String(500, "Streaming not supported") + c.String(http.StatusInternalServerError, "Streaming not supported") return } diff --git a/server/api/user.go b/server/api/user.go index 8e14a8383..6a7cede6a 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -33,7 +33,7 @@ import ( ) func GetSelf(c *gin.Context) { - c.JSON(200, session.User(c)) + c.JSON(http.StatusOK, session.User(c)) } func GetFeed(c *gin.Context) { @@ -70,19 +70,19 @@ func GetFeed(c *gin.Context) { if latest { feed, err := _store.RepoListLatest(user) if err != nil { - c.String(500, "Error fetching feed. %s", err) + c.String(http.StatusInternalServerError, "Error fetching feed. %s", err) } else { - c.JSON(200, feed) + c.JSON(http.StatusOK, feed) } return } feed, err := _store.UserFeed(user) if err != nil { - c.String(500, "Error fetching user feed. %s", err) + c.String(http.StatusInternalServerError, "Error fetching user feed. %s", err) return } - c.JSON(200, feed) + c.JSON(http.StatusOK, feed) } func GetRepos(c *gin.Context) { @@ -119,7 +119,7 @@ func GetRepos(c *gin.Context) { repos, err := _store.RepoList(user, true) if err != nil { - c.String(500, "Error fetching repository list. %s", err) + c.String(http.StatusInternalServerError, "Error fetching repository list. %s", err) return } @@ -155,7 +155,7 @@ func DeleteToken(c *gin.Context) { securecookie.GenerateRandomKey(32), ) if err := _store.UpdateUser(user); err != nil { - c.String(500, "Error revoking tokens. %s", err) + c.String(http.StatusInternalServerError, "Error revoking tokens. %s", err) return } diff --git a/server/api/users.go b/server/api/users.go index 6bf325984..60f52c7c4 100644 --- a/server/api/users.go +++ b/server/api/users.go @@ -20,7 +20,6 @@ import ( "github.com/gin-gonic/gin" "github.com/gorilla/securecookie" - "github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/store" ) @@ -37,7 +36,7 @@ func GetUsers(c *gin.Context) { func GetUser(c *gin.Context) { user, err := store.FromContext(c).GetUserLogin(c.Param("login")) if err != nil { - c.String(404, "Cannot find user. %s", err) + handleDbGetError(c, err) return } c.JSON(200, user) @@ -55,7 +54,7 @@ func PatchUser(c *gin.Context) { user, err := _store.GetUserLogin(c.Param("login")) if err != nil { - c.AbortWithStatus(http.StatusNotFound) + handleDbGetError(c, err) return } diff --git a/server/api/z.go b/server/api/z.go index 6a7a851f6..80ae496f9 100644 --- a/server/api/z.go +++ b/server/api/z.go @@ -28,15 +28,15 @@ import ( // Health endpoint returns a 500 if the server state is unhealthy. func Health(c *gin.Context) { if err := store.FromContext(c).Ping(); err != nil { - c.String(500, err.Error()) + c.String(http.StatusInternalServerError, err.Error()) return } - c.String(200, "") + c.String(http.StatusOK, "") } // Version endpoint returns the server version and build information. func Version(c *gin.Context) { - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "source": "https://github.com/woodpecker-ci/woodpecker", "version": version.String(), }) @@ -44,7 +44,7 @@ func Version(c *gin.Context) { // LogLevel endpoint returns the current logging level func LogLevel(c *gin.Context) { - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "log-level": zerolog.GlobalLevel().String(), }) } @@ -67,5 +67,5 @@ func SetLogLevel(c *gin.Context) { log.Log().Msgf("log level set to %s", lvl.String()) zerolog.SetGlobalLevel(lvl) - c.JSON(200, logLevel) + c.JSON(http.StatusOK, logLevel) } diff --git a/server/router/middleware/session/repo.go b/server/router/middleware/session/repo.go index 34866b7a1..67c29c99e 100644 --- a/server/router/middleware/session/repo.go +++ b/server/router/middleware/session/repo.go @@ -15,11 +15,13 @@ package session import ( + "errors" "net/http" "time" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" + "github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server/model" @@ -62,7 +64,11 @@ func SetRepo() gin.HandlerFunc { ) if user != nil { - c.AbortWithStatus(http.StatusNotFound) + if errors.Is(err, types.RecordNotExist) { + c.AbortWithStatus(http.StatusNotFound) + return + } + _ = c.AbortWithError(http.StatusInternalServerError, err) } else { c.AbortWithStatus(http.StatusUnauthorized) } diff --git a/server/store/datastore/repo.go b/server/store/datastore/repo.go index 05fc17f5d..ae5b27fa1 100644 --- a/server/store/datastore/repo.go +++ b/server/store/datastore/repo.go @@ -16,6 +16,7 @@ package datastore import ( "errors" + "strings" "github.com/rs/zerolog/log" "xorm.io/builder" @@ -72,7 +73,7 @@ func (s storage) GetRepoName(fullName string) (*model.Repo, error) { func (s storage) getRepoName(e *xorm.Session, fullName string) (*model.Repo, error) { repo := new(model.Repo) - return repo, wrapGet(e.Where("repo_full_name = ?", fullName).Get(repo)) + return repo, wrapGet(e.Where("LOWER(repo_full_name) = ?", strings.ToLower(fullName)).Get(repo)) } func (s storage) GetRepoCount() (int64, error) { diff --git a/server/store/datastore/repo_test.go b/server/store/datastore/repo_test.go index 91807053a..66e0309dd 100644 --- a/server/store/datastore/repo_test.go +++ b/server/store/datastore/repo_test.go @@ -103,6 +103,22 @@ func TestRepos(t *testing.T) { g.Assert(repo.Name).Equal(getrepo.Name) }) + g.It("Should Get a Repo by Name (case-insensitive)", func() { + repo := model.Repo{ + UserID: 1, + FullName: "bradrydzewski/TEST", + Owner: "bradrydzewski", + Name: "TEST", + } + g.Assert(store.CreateRepo(&repo)).IsNil() + getrepo, err := store.GetRepoName("Bradrydzewski/test") + g.Assert(err).IsNil() + g.Assert(repo.ID).Equal(getrepo.ID) + g.Assert(repo.UserID).Equal(getrepo.UserID) + g.Assert(repo.Owner).Equal(getrepo.Owner) + g.Assert(repo.Name).Equal(getrepo.Name) + }) + g.It("Should Enforce Unique Repo Name", func() { repo1 := model.Repo{ UserID: 1, diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 80afa3af6..b84949bea 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -358,6 +358,7 @@ }, "capacity": { "capacity": "Capacity", + "desc": "The max amount of parallel pipelines executed by this agent.", "badge": "capacity" }, "version": "Version", diff --git a/web/src/components/admin/settings/AdminAgentsTab.vue b/web/src/components/admin/settings/AdminAgentsTab.vue index 5c445bbbe..2a4f7a60b 100644 --- a/web/src/components/admin/settings/AdminAgentsTab.vue +++ b/web/src/components/admin/settings/AdminAgentsTab.vue @@ -78,7 +78,7 @@ :label="$t('admin.settings.agents.capacity.capacity')" docs-url="docs/next/administration/agent-config#woodpecker_max_procs" > - The max amount of parallel pipelines executed by this agent. + {{ $t('admin.settings.agents.capacity.desc') }} @@ -98,11 +98,15 @@ -