Browse Source

Swagger info corrections (#9441)

* use numbers and not http.Status___ enum

* fix test

* add many missing swagger responses

* code format

* Deletion Sould return 204 ...

* error handling improvements

* if special error type ... then add it to swagger too

* one smal nit

* invalidTopicsError is []string

* valid swagger specification 2.0
 - if you add responses swagger can tell you if you do it right ๐Ÿ‘

* use ctx.InternalServerError

* Revert "use numbers and not http.Status___ enum"

This reverts commit b1ff386e24.

* use http.Status* enum everywhere
lunny/display_deleted_branch2
6543 3 years ago
committed by Lauris BH
parent
commit
2848c5eb8f
  1. 7
      modules/context/api.go
  2. 14
      routers/api/v1/admin/org.go
  3. 5
      routers/api/v1/admin/repo.go
  4. 47
      routers/api/v1/admin/user.go
  5. 57
      routers/api/v1/api.go
  6. 14
      routers/api/v1/misc/markdown.go
  7. 4
      routers/api/v1/misc/swagger.go
  8. 4
      routers/api/v1/misc/version.go
  9. 15
      routers/api/v1/org/hook.go
  10. 44
      routers/api/v1/org/member.go
  11. 29
      routers/api/v1/org/org.go
  12. 103
      routers/api/v1/org/team.go
  13. 2
      routers/api/v1/repo/blob.go
  14. 20
      routers/api/v1/repo/branch.go
  15. 45
      routers/api/v1/repo/collaborators.go
  16. 7
      routers/api/v1/repo/commits.go
  17. 10
      routers/api/v1/repo/file.go
  18. 26
      routers/api/v1/repo/fork.go
  19. 26
      routers/api/v1/repo/git_hook.go
  20. 8
      routers/api/v1/repo/git_ref.go
  21. 23
      routers/api/v1/repo/hook.go
  22. 88
      routers/api/v1/repo/issue.go
  23. 65
      routers/api/v1/repo/issue_comment.go
  24. 67
      routers/api/v1/repo/issue_label.go
  25. 75
      routers/api/v1/repo/issue_reaction.go
  26. 39
      routers/api/v1/repo/issue_stopwatch.go
  27. 29
      routers/api/v1/repo/issue_subscription.go
  28. 49
      routers/api/v1/repo/issue_tracked_time.go
  29. 43
      routers/api/v1/repo/key.go
  30. 26
      routers/api/v1/repo/label.go
  31. 26
      routers/api/v1/repo/milestone.go
  32. 112
      routers/api/v1/repo/pull.go
  33. 45
      routers/api/v1/repo/release.go
  34. 37
      routers/api/v1/repo/release_attachment.go
  35. 101
      routers/api/v1/repo/repo.go
  36. 7
      routers/api/v1/repo/star.go
  37. 36
      routers/api/v1/repo/status.go
  38. 7
      routers/api/v1/repo/subscriber.go
  39. 7
      routers/api/v1/repo/tag.go
  40. 48
      routers/api/v1/repo/topic.go
  41. 10
      routers/api/v1/repo/tree.go
  42. 17
      routers/api/v1/user/app.go
  43. 25
      routers/api/v1/user/email.go
  44. 26
      routers/api/v1/user/follower.go
  45. 29
      routers/api/v1/user/gpg_key.go
  46. 25
      routers/api/v1/user/key.go
  47. 17
      routers/api/v1/user/repo.go
  48. 25
      routers/api/v1/user/star.go
  49. 15
      routers/api/v1/user/user.go
  50. 25
      routers/api/v1/user/watch.go
  51. 32
      routers/api/v1/utils/hook.go
  52. 247
      templates/swagger/v1_json.tmpl

7
modules/context/api.go

@ -39,6 +39,13 @@ type APIValidationError struct {
URL string `json:"url"`
}
// APIInvalidTopicsError is error format response to invalid topics
// swagger:response invalidTopicsError
type APIInvalidTopicsError struct {
Topics []string `json:"invalidTopics"`
Message string `json:"message"`
}
//APIEmpty is an empty response
// swagger:response empty
type APIEmpty struct{}

14
routers/api/v1/admin/org.go

@ -6,6 +6,8 @@
package admin
import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
@ -39,6 +41,7 @@ func CreateOrg(ctx *context.APIContext, form api.CreateOrgOption) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -64,14 +67,14 @@ func CreateOrg(ctx *context.APIContext, form api.CreateOrgOption) {
if models.IsErrUserAlreadyExist(err) ||
models.IsErrNameReserved(err) ||
models.IsErrNamePatternNotAllowed(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "CreateOrganization", err)
ctx.Error(http.StatusInternalServerError, "CreateOrganization", err)
}
return
}
ctx.JSON(201, convert.ToOrganization(org))
ctx.JSON(http.StatusCreated, convert.ToOrganization(org))
}
//GetAllOrgs API for getting information of all the organizations
@ -95,6 +98,7 @@ func GetAllOrgs(ctx *context.APIContext) {
// "$ref": "#/responses/OrganizationList"
// "403":
// "$ref": "#/responses/forbidden"
users, _, err := models.SearchUsers(&models.SearchUserOptions{
Type: models.UserTypeOrganization,
OrderBy: models.SearchOrderByAlphabetically,
@ -103,12 +107,12 @@ func GetAllOrgs(ctx *context.APIContext) {
Private: true,
})
if err != nil {
ctx.Error(500, "SearchOrganizations", err)
ctx.Error(http.StatusInternalServerError, "SearchOrganizations", err)
return
}
orgs := make([]*api.Organization, len(users))
for i := range users {
orgs[i] = convert.ToOrganization(users[i])
}
ctx.JSON(200, &orgs)
ctx.JSON(http.StatusOK, &orgs)
}

5
routers/api/v1/admin/repo.go

@ -35,8 +35,13 @@ func CreateRepo(ctx *context.APIContext, form api.CreateRepoOption) {
// "$ref": "#/responses/Repository"
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
// "409":
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
owner := user.GetUserByParams(ctx)
if ctx.Written() {
return

47
routers/api/v1/admin/user.go

@ -7,6 +7,7 @@ package admin
import (
"errors"
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
@ -26,9 +27,9 @@ func parseLoginSource(ctx *context.APIContext, u *models.User, sourceID int64, l
source, err := models.GetLoginSourceByID(sourceID)
if err != nil {
if models.IsErrLoginSourceNotExist(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "GetLoginSourceByID", err)
ctx.Error(http.StatusInternalServerError, "GetLoginSourceByID", err)
}
return
}
@ -57,8 +58,11 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
// "$ref": "#/responses/User"
// "403":
// "$ref": "#/responses/forbidden"
// "400":
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
u := &models.User{
Name: form.Username,
FullName: form.FullName,
@ -78,7 +82,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
}
if !password.IsComplexEnough(form.Password) {
err := errors.New("PasswordComplexity")
ctx.Error(400, "PasswordComplexity", err)
ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
return
}
if err := models.CreateUser(u); err != nil {
@ -86,9 +90,9 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
models.IsErrEmailAlreadyUsed(err) ||
models.IsErrNameReserved(err) ||
models.IsErrNamePatternNotAllowed(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "CreateUser", err)
ctx.Error(http.StatusInternalServerError, "CreateUser", err)
}
return
}
@ -98,7 +102,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
if form.SendNotify {
mailer.SendRegisterNotifyMail(ctx.Locale, u)
}
ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
ctx.JSON(http.StatusCreated, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// EditUser api for modifying a user's information
@ -127,6 +131,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -140,12 +145,12 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
if len(form.Password) > 0 {
if !password.IsComplexEnough(form.Password) {
err := errors.New("PasswordComplexity")
ctx.Error(400, "PasswordComplexity", err)
ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
return
}
var err error
if u.Salt, err = models.GetUserSalt(); err != nil {
ctx.Error(500, "UpdateUser", err)
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
return
}
u.HashPassword(form.Password)
@ -184,15 +189,15 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
if err := models.UpdateUser(u); err != nil {
if models.IsErrEmailAlreadyUsed(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "UpdateUser", err)
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
}
return
}
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// DeleteUser api for deleting a user
@ -215,6 +220,7 @@ func DeleteUser(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -223,15 +229,15 @@ func DeleteUser(ctx *context.APIContext) {
if err := models.DeleteUser(u); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "DeleteUser", err)
ctx.Error(http.StatusInternalServerError, "DeleteUser", err)
}
return
}
log.Trace("Account deleted by admin(%s): %s", ctx.User.Name, u.Name)
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// CreatePublicKey api for creating a public key to a user
@ -260,6 +266,7 @@ func CreatePublicKey(ctx *context.APIContext, form api.CreateKeyOption) {
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -293,6 +300,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -302,15 +310,15 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
if models.IsErrKeyNotExist(err) {
ctx.NotFound()
} else if models.IsErrKeyAccessDenied(err) {
ctx.Error(403, "", "You do not have access to this key")
ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else {
ctx.Error(500, "DeleteUserPublicKey", err)
ctx.Error(http.StatusInternalServerError, "DeleteUserPublicKey", err)
}
return
}
log.Trace("Key deleted by admin(%s): %s", ctx.User.Name, u.Name)
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
//GetAllUsers API for getting information of all the users
@ -325,13 +333,14 @@ func GetAllUsers(ctx *context.APIContext) {
// "$ref": "#/responses/UserList"
// "403":
// "$ref": "#/responses/forbidden"
users, _, err := models.SearchUsers(&models.SearchUserOptions{
Type: models.UserTypeIndividual,
OrderBy: models.SearchOrderByAlphabetically,
PageSize: -1,
})
if err != nil {
ctx.Error(500, "GetAllUsers", err)
ctx.Error(http.StatusInternalServerError, "GetAllUsers", err)
return
}
@ -340,5 +349,5 @@ func GetAllUsers(ctx *context.APIContext) {
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
}
ctx.JSON(200, &results)
ctx.JSON(http.StatusOK, &results)
}

57
routers/api/v1/api.go

@ -59,6 +59,7 @@
package v1
import (
"net/http"
"strings"
"code.gitea.io/gitea/models"
@ -92,14 +93,14 @@ func sudo() macaron.Handler {
if models.IsErrUserNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "GetUserByName", err)
ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
}
return
}
log.Trace("Sudo from (%s) to: %s", ctx.User.Name, user.Name)
ctx.User = user
} else {
ctx.JSON(403, map[string]string{
ctx.JSON(http.StatusForbidden, map[string]string{
"message": "Only administrators allowed to sudo.",
})
return
@ -127,7 +128,7 @@ func repoAssignment() macaron.Handler {
if models.IsErrUserNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "GetUserByName", err)
ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
}
return
}
@ -144,10 +145,10 @@ func repoAssignment() macaron.Handler {
} else if models.IsErrRepoRedirectNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "LookupRepoRedirect", err)
ctx.Error(http.StatusInternalServerError, "LookupRepoRedirect", err)
}
} else {
ctx.Error(500, "GetRepositoryByName", err)
ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err)
}
return
}
@ -157,7 +158,7 @@ func repoAssignment() macaron.Handler {
ctx.Repo.Permission, err = models.GetUserRepoPermission(repo, ctx.User)
if err != nil {
ctx.Error(500, "GetUserRepoPermission", err)
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return
}
@ -182,14 +183,14 @@ func reqToken() macaron.Handler {
ctx.RequireCSRF()
return
}
ctx.Context.Error(401)
ctx.Context.Error(http.StatusUnauthorized)
}
}
func reqBasicAuth() macaron.Handler {
return func(ctx *context.APIContext) {
if !ctx.Context.IsBasicAuth {
ctx.Context.Error(401)
ctx.Context.Error(http.StatusUnauthorized)
return
}
ctx.CheckForOTP()
@ -200,7 +201,7 @@ func reqBasicAuth() macaron.Handler {
func reqSiteAdmin() macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -210,7 +211,7 @@ func reqSiteAdmin() macaron.Handler {
func reqOwner() macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserRepoOwner() && !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -220,7 +221,7 @@ func reqOwner() macaron.Handler {
func reqAdmin() macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -230,7 +231,7 @@ func reqAdmin() macaron.Handler {
func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -240,7 +241,7 @@ func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler {
func reqRepoReader(unitType models.UnitType) macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -250,7 +251,7 @@ func reqRepoReader(unitType models.UnitType) macaron.Handler {
func reqAnyRepoReader() macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsUserRepoReaderAny() && !ctx.IsUserSiteAdmin() {
ctx.Error(403)
ctx.Error(http.StatusForbidden)
return
}
}
@ -269,17 +270,17 @@ func reqOrgOwnership() macaron.Handler {
} else if ctx.Org.Team != nil {
orgID = ctx.Org.Team.OrgID
} else {
ctx.Error(500, "", "reqOrgOwnership: unprepared context")
ctx.Error(http.StatusInternalServerError, "", "reqOrgOwnership: unprepared context")
return
}
isOwner, err := models.IsOrganizationOwner(orgID, ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrganizationOwner", err)
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
return
} else if !isOwner {
if ctx.Org.Organization != nil {
ctx.Error(403, "", "Must be an organization owner")
ctx.Error(http.StatusForbidden, "", "Must be an organization owner")
} else {
ctx.NotFound()
}
@ -295,28 +296,28 @@ func reqTeamMembership() macaron.Handler {
return
}
if ctx.Org.Team == nil {
ctx.Error(500, "", "reqTeamMembership: unprepared context")
ctx.Error(http.StatusInternalServerError, "", "reqTeamMembership: unprepared context")
return
}
var orgID = ctx.Org.Team.OrgID
isOwner, err := models.IsOrganizationOwner(orgID, ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrganizationOwner", err)
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
return
} else if isOwner {
return
}
if isTeamMember, err := models.IsTeamMember(orgID, ctx.Org.Team.ID, ctx.User.ID); err != nil {
ctx.Error(500, "IsTeamMember", err)
ctx.Error(http.StatusInternalServerError, "IsTeamMember", err)
return
} else if !isTeamMember {
isOrgMember, err := models.IsOrganizationMember(orgID, ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrganizationMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
} else if isOrgMember {
ctx.Error(403, "", "Must be a team member")
ctx.Error(http.StatusForbidden, "", "Must be a team member")
} else {
ctx.NotFound()
}
@ -338,16 +339,16 @@ func reqOrgMembership() macaron.Handler {
} else if ctx.Org.Team != nil {
orgID = ctx.Org.Team.OrgID
} else {
ctx.Error(500, "", "reqOrgMembership: unprepared context")
ctx.Error(http.StatusInternalServerError, "", "reqOrgMembership: unprepared context")
return
}
if isMember, err := models.IsOrganizationMember(orgID, ctx.User.ID); err != nil {
ctx.Error(500, "IsOrganizationMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
return
} else if !isMember {
if ctx.Org.Organization != nil {
ctx.Error(403, "", "Must be an organization member")
ctx.Error(http.StatusForbidden, "", "Must be an organization member")
} else {
ctx.NotFound()
}
@ -359,7 +360,7 @@ func reqOrgMembership() macaron.Handler {
func reqGitHook() macaron.Handler {
return func(ctx *context.APIContext) {
if !ctx.User.CanEditGitHook() {
ctx.Error(403, "", "must be allowed to edit Git hooks")
ctx.Error(http.StatusForbidden, "", "must be allowed to edit Git hooks")
return
}
}
@ -386,7 +387,7 @@ func orgAssignment(args ...bool) macaron.Handler {
if models.IsErrOrgNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "GetOrgByName", err)
ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
}
return
}
@ -398,7 +399,7 @@ func orgAssignment(args ...bool) macaron.Handler {
if models.IsErrUserNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "GetTeamById", err)
ctx.Error(http.StatusInternalServerError, "GetTeamById", err)
}
return
}

14
routers/api/v1/misc/markdown.go

@ -36,8 +36,9 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) {
// "$ref": "#/responses/MarkdownRender"
// "422":
// "$ref": "#/responses/validationError"
if ctx.HasAPIError() {
ctx.Error(422, "", ctx.GetErrMsg())
ctx.Error(http.StatusUnprocessableEntity, "", ctx.GetErrMsg())
return
}
@ -65,20 +66,20 @@ func Markdown(ctx *context.APIContext, form api.MarkdownOption) {
if form.Wiki {
_, err := ctx.Write([]byte(markdown.RenderWiki(md, urlPrefix, meta)))
if err != nil {
ctx.Error(http.StatusInternalServerError, "", err)
ctx.InternalServerError(err)
return
}
} else {
_, err := ctx.Write(markdown.Render(md, urlPrefix, meta))
if err != nil {
ctx.Error(http.StatusInternalServerError, "", err)
ctx.InternalServerError(err)
return
}
}
default:
_, err := ctx.Write(markdown.RenderRaw([]byte(form.Text), "", false))
if err != nil {
ctx.Error(http.StatusInternalServerError, "", err)
ctx.InternalServerError(err)
return
}
}
@ -105,14 +106,15 @@ func MarkdownRaw(ctx *context.APIContext) {
// "$ref": "#/responses/MarkdownRender"
// "422":
// "$ref": "#/responses/validationError"
body, err := ctx.Req.Body().Bytes()
if err != nil {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
return
}
_, err = ctx.Write(markdown.RenderRaw(body, "", false))
if err != nil {
ctx.Error(http.StatusInternalServerError, "", err)
ctx.InternalServerError(err)
return
}
}

4
routers/api/v1/misc/swagger.go

@ -5,6 +5,8 @@
package misc
import (
"net/http"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
)
@ -15,5 +17,5 @@ const tplSwagger base.TplName = "swagger/ui"
// Swagger render swagger-ui page with v1 json
func Swagger(ctx *context.Context) {
ctx.Data["APIJSONVersion"] = "v1"
ctx.HTML(200, tplSwagger)
ctx.HTML(http.StatusOK, tplSwagger)
}

4
routers/api/v1/misc/version.go

@ -5,6 +5,8 @@
package misc
import (
"net/http"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
@ -20,5 +22,5 @@ func Version(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/ServerVersion"
ctx.JSON(200, &structs.ServerVersion{Version: setting.AppVer})
ctx.JSON(http.StatusOK, &structs.ServerVersion{Version: setting.AppVer})
}

15
routers/api/v1/org/hook.go

@ -5,6 +5,8 @@
package org
import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
@ -28,17 +30,18 @@ func ListHooks(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/HookList"
org := ctx.Org.Organization
orgHooks, err := models.GetWebhooksByOrgID(org.ID)
if err != nil {
ctx.Error(500, "GetWebhooksByOrgID", err)
ctx.Error(http.StatusInternalServerError, "GetWebhooksByOrgID", err)
return
}
hooks := make([]*api.Hook, len(orgHooks))
for i, hook := range orgHooks {
hooks[i] = convert.ToHook(org.HomeLink(), hook)
}
ctx.JSON(200, hooks)
ctx.JSON(http.StatusOK, hooks)
}
// GetHook get an organization's hook by id
@ -63,13 +66,14 @@ func GetHook(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/Hook"
org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
hook, err := utils.GetOrgHook(ctx, org.ID, hookID)
if err != nil {
return
}
ctx.JSON(200, convert.ToHook(org.HomeLink(), hook))
ctx.JSON(http.StatusOK, convert.ToHook(org.HomeLink(), hook))
}
// CreateHook create a hook for an organization
@ -159,15 +163,16 @@ func DeleteHook(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
if err := models.DeleteWebhookByOrgID(org.ID, hookID); err != nil {
if models.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "DeleteWebhookByOrgID", err)
ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOrgID", err)
}
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}

44
routers/api/v1/org/member.go

@ -6,6 +6,7 @@ package org
import (
"fmt"
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
@ -23,7 +24,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
PublicOnly: publicOnly,
})
if err != nil {
ctx.Error(500, "GetUsersByIDs", err)
ctx.Error(http.StatusInternalServerError, "GetUsersByIDs", err)
return
}
@ -31,7 +32,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
for i, member := range members {
apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, apiMembers)
ctx.JSON(http.StatusOK, apiMembers)
}
// ListMembers list an organization's members
@ -50,11 +51,12 @@ func ListMembers(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/UserList"
publicOnly := true
if ctx.User != nil {
isMember, err := ctx.Org.Organization.IsOrgMember(ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrgMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrgMember", err)
return
}
publicOnly = !isMember
@ -78,6 +80,7 @@ func ListPublicMembers(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/UserList"
listMembers(ctx, true)
}
@ -100,8 +103,11 @@ func IsMember(ctx *context.APIContext) {
// responses:
// "204":
// description: user is a member
// "302":
// description: redirection to /orgs/{org}/public_members/{username}
// "404":
// description: user is not a member
userToCheck := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -109,14 +115,14 @@ func IsMember(ctx *context.APIContext) {
if ctx.User != nil {
userIsMember, err := ctx.Org.Organization.IsOrgMember(ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrgMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrgMember", err)
return
} else if userIsMember {
userToCheckIsMember, err := ctx.Org.Organization.IsOrgMember(userToCheck.ID)
if err != nil {
ctx.Error(500, "IsOrgMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrgMember", err)
} else if userToCheckIsMember {
ctx.Status(204)
ctx.Status(http.StatusNoContent)
} else {
ctx.NotFound()
}
@ -153,12 +159,13 @@ func IsPublicMember(ctx *context.APIContext) {
// description: user is a public member
// "404":
// description: user is not a public member
userToCheck := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if userToCheck.IsPublicMember(ctx.Org.Organization.ID) {
ctx.Status(204)
ctx.Status(http.StatusNoContent)
} else {
ctx.NotFound()
}
@ -185,20 +192,23 @@ func PublicizeMember(ctx *context.APIContext) {
// responses:
// "204":
// description: membership publicized
// "403":
// "$ref": "#/responses/forbidden"
userToPublicize := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if userToPublicize.ID != ctx.User.ID {
ctx.Error(403, "", "Cannot publicize another member")
ctx.Error(http.StatusForbidden, "", "Cannot publicize another member")
return
}
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToPublicize.ID, true)
if err != nil {
ctx.Error(500, "ChangeOrgUserStatus", err)
ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// ConcealMember make a member's membership not public
@ -222,20 +232,23 @@ func ConcealMember(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
userToConceal := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if userToConceal.ID != ctx.User.ID {
ctx.Error(403, "", "Cannot conceal another member")
ctx.Error(http.StatusForbidden, "", "Cannot conceal another member")
return
}
err := models.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToConceal.ID, false)
if err != nil {
ctx.Error(500, "ChangeOrgUserStatus", err)
ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// DeleteMember remove a member from an organization
@ -259,12 +272,13 @@ func DeleteMember(ctx *context.APIContext) {
// responses:
// "204":
// description: member removed
member := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := ctx.Org.Organization.RemoveMember(member.ID); err != nil {
ctx.Error(500, "RemoveMember", err)
ctx.Error(http.StatusInternalServerError, "RemoveMember", err)
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}

29
routers/api/v1/org/org.go

@ -6,6 +6,8 @@
package org
import (
"net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
@ -15,7 +17,7 @@ import (
func listUserOrgs(ctx *context.APIContext, u *models.User, all bool) {
if err := u.GetOrganizations(all); err != nil {
ctx.Error(500, "GetOrganizations", err)
ctx.Error(http.StatusInternalServerError, "GetOrganizations", err)
return
}
@ -23,7 +25,7 @@ func listUserOrgs(ctx *context.APIContext, u *models.User, all bool) {
for i := range u.Orgs {
apiOrgs[i] = convert.ToOrganization(u.Orgs[i])
}
ctx.JSON(200, &apiOrgs)
ctx.JSON(http.StatusOK, &apiOrgs)
}
// ListMyOrgs list all my orgs
@ -36,6 +38,7 @@ func ListMyOrgs(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/OrganizationList"
listUserOrgs(ctx, ctx.User, true)
}
@ -55,6 +58,7 @@ func ListUserOrgs(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/OrganizationList"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -85,7 +89,7 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) {
// "$ref": "#/responses/validationError"
if !ctx.User.CanCreateOrganization() {
ctx.Error(403, "Create organization not allowed", nil)
ctx.Error(http.StatusForbidden, "Create organization not allowed", nil)
return
}
@ -109,14 +113,14 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) {
if models.IsErrUserAlreadyExist(err) ||
models.IsErrNameReserved(err) ||
models.IsErrNamePatternNotAllowed(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "CreateOrganization", err)
ctx.Error(http.StatusInternalServerError, "CreateOrganization", err)
}
return
}
ctx.JSON(201, convert.ToOrganization(org))
ctx.JSON(http.StatusCreated, convert.ToOrganization(org))
}
// Get get an organization
@ -135,11 +139,12 @@ func Get(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/Organization"
if !models.HasOrgVisible(ctx.Org.Organization, ctx.User) {
ctx.NotFound("HasOrgVisible", nil)
return
}
ctx.JSON(200, convert.ToOrganization(ctx.Org.Organization))
ctx.JSON(http.StatusOK, convert.ToOrganization(ctx.Org.Organization))
}
// Edit change an organization's information
@ -165,6 +170,7 @@ func Edit(ctx *context.APIContext, form api.EditOrgOption) {
// responses:
// "200":
// "$ref": "#/responses/Organization"
org := ctx.Org.Organization
org.FullName = form.FullName
org.Description = form.Description
@ -174,11 +180,11 @@ func Edit(ctx *context.APIContext, form api.EditOrgOption) {
org.Visibility = api.VisibilityModes[form.Visibility]
}
if err := models.UpdateUserCols(org, "full_name", "description", "website", "location", "visibility"); err != nil {
ctx.Error(500, "EditOrganization", err)
ctx.Error(http.StatusInternalServerError, "EditOrganization", err)
return
}
ctx.JSON(200, convert.ToOrganization(org))
ctx.JSON(http.StatusOK, convert.ToOrganization(org))
}
//Delete an organization
@ -197,9 +203,10 @@ func Delete(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
if err := models.DeleteOrganization(ctx.Org.Organization); err != nil {
ctx.Error(500, "DeleteOrganization", err)
ctx.Error(http.StatusInternalServerError, "DeleteOrganization", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}

103
routers/api/v1/org/team.go

@ -6,6 +6,7 @@
package org
import (
"net/http"
"strings"
"code.gitea.io/gitea/models"
@ -32,22 +33,23 @@ func ListTeams(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/TeamList"
org := ctx.Org.Organization
if err := org.GetTeams(); err != nil {
ctx.Error(500, "GetTeams", err)
ctx.Error(http.StatusInternalServerError, "GetTeams", err)
return
}
apiTeams := make([]*api.Team, len(org.Teams))
for i := range org.Teams {
if err := org.Teams[i].GetUnits(); err != nil {
ctx.Error(500, "GetUnits", err)
ctx.Error(http.StatusInternalServerError, "GetUnits", err)
return
}
apiTeams[i] = convert.ToTeam(org.Teams[i])
}
ctx.JSON(200, apiTeams)
ctx.JSON(http.StatusOK, apiTeams)
}
// ListUserTeams list all the teams a user belongs to
@ -60,9 +62,10 @@ func ListUserTeams(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/TeamList"
teams, err := models.GetUserTeams(ctx.User.ID)
if err != nil {
ctx.Error(500, "GetUserTeams", err)
ctx.Error(http.StatusInternalServerError, "GetUserTeams", err)
return
}
@ -73,7 +76,7 @@ func ListUserTeams(ctx *context.APIContext) {
if !ok {
org, err := models.GetUserByID(teams[i].OrgID)
if err != nil {
ctx.Error(500, "GetUserByID", err)
ctx.Error(http.StatusInternalServerError, "GetUserByID", err)
return
}
apiOrg = convert.ToOrganization(org)
@ -82,7 +85,7 @@ func ListUserTeams(ctx *context.APIContext) {
apiTeams[i] = convert.ToTeam(teams[i])
apiTeams[i].Organization = apiOrg
}
ctx.JSON(200, apiTeams)
ctx.JSON(http.StatusOK, apiTeams)
}
// GetTeam api for get a team
@ -102,7 +105,8 @@ func GetTeam(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/Team"
ctx.JSON(200, convert.ToTeam(ctx.Org.Team))
ctx.JSON(http.StatusOK, convert.ToTeam(ctx.Org.Team))
}
// CreateTeam api for create a team
@ -127,6 +131,9 @@ func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) {
// responses:
// "201":
// "$ref": "#/responses/Team"
// "422":
// "$ref": "#/responses/validationError"
team := &models.Team{
OrgID: ctx.Org.Organization.ID,
Name: form.Name,
@ -151,14 +158,14 @@ func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) {
if err := models.NewTeam(team); err != nil {
if models.IsErrTeamAlreadyExist(err) {
ctx.Error(422, "", err)
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(500, "NewTeam", err)
ctx.Error(http.StatusInternalServerError, "NewTeam", err)
}
return
}
ctx.JSON(201, convert.ToTeam(team))
ctx.JSON(http.StatusCreated, convert.ToTeam(team))
}
// EditTeam api for edit a team
@ -183,6 +190,7 @@ func EditTeam(ctx *context.APIContext, form api.EditTeamOption) {
// responses:
// "200":
// "$ref": "#/responses/Team"
team := ctx.Org.Team
team.Description = form.Description
unitTypes := models.FindUnitTypes(form.Units...)
@ -218,10 +226,10 @@ func EditTeam(ctx *context.APIContext, form api.EditTeamOption) {
}
if err := models.UpdateTeam(team, isAuthChanged, isIncludeAllChanged); err != nil {
ctx.Error(500, "EditTeam", err)
ctx.Error(http.StatusInternalServerError, "EditTeam", err)
return
}
ctx.JSON(200, convert.ToTeam(team))
ctx.JSON(http.StatusOK, convert.ToTeam(team))
}
// DeleteTeam api for delete a team
@ -239,11 +247,12 @@ func DeleteTeam(ctx *context.APIContext) {
// responses:
// "204":
// description: team deleted
if err := models.DeleteTeam(ctx.Org.Team); err != nil {
ctx.Error(500, "DeleteTeam", err)
ctx.Error(http.StatusInternalServerError, "DeleteTeam", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// GetTeamMembers api for get a team's members
@ -263,9 +272,10 @@ func GetTeamMembers(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/UserList"
isMember, err := models.IsOrganizationMember(ctx.Org.Team.OrgID, ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrganizationMember", err)
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
return
} else if !isMember {
ctx.NotFound()
@ -273,14 +283,14 @@ func GetTeamMembers(ctx *context.APIContext) {
}
team := ctx.Org.Team
if err := team.GetMembers(); err != nil {
ctx.Error(500, "GetTeamMembers", err)
ctx.Error(http.StatusInternalServerError, "GetTeamMembers", err)
return
}
members := make([]*api.User, len(team.Members))
for i, member := range team.Members {
members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
}
ctx.JSON(200, members)
ctx.JSON(http.StatusOK, members)
}
// GetTeamMember api for get a particular member of team
@ -305,6 +315,9 @@ func GetTeamMember(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/User"
// "404":
// "$ref": "#/responses/notFound"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
@ -312,13 +325,13 @@ func GetTeamMember(ctx *context.APIContext) {
teamID := ctx.ParamsInt64("teamid")
isTeamMember, err := models.IsUserInTeams(u.ID, []int64{teamID})
if err != nil {
ctx.Error(500, "IsUserInTeams", err)
ctx.Error(http.StatusInternalServerError, "IsUserInTeams", err)
return
} else if !isTeamMember {
ctx.NotFound()
return
}
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// AddTeamMember api for add a member to a team
@ -343,15 +356,18 @@ func AddTeamMember(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := ctx.Org.Team.AddMember(u.ID); err != nil {
ctx.Error(500, "AddMember", err)
ctx.Error(http.StatusInternalServerError, "AddMember", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// RemoveTeamMember api for remove one member from a team
@ -376,16 +392,19 @@ func RemoveTeamMember(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
u := user.GetUserByParams(ctx)
if ctx.Written() {
return
}
if err := ctx.Org.Team.RemoveMember(u.ID); err != nil {
ctx.Error(500, "RemoveMember", err)
ctx.Error(http.StatusInternalServerError, "RemoveMember", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// GetTeamRepos api for get a team's repos
@ -405,20 +424,21 @@ func GetTeamRepos(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/RepositoryList"
team := ctx.Org.Team
if err := team.GetRepositories(); err != nil {
ctx.Error(500, "GetTeamRepos", err)
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
}
repos := make([]*api.Repository, len(team.Repos))
for i, repo := range team.Repos {
access, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.Error(500, "GetTeamRepos", err)
ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err)
return
}
repos[i] = repo.APIFormat(access)
}
ctx.JSON(200, repos)
ctx.JSON(http.StatusOK, repos)
}
// getRepositoryByParams get repository by a team's organization ID and repo name
@ -428,7 +448,7 @@ func getRepositoryByParams(ctx *context.APIContext) *models.Repository {
if models.IsErrRepoNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(500, "GetRepositoryByName", err)
ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err)
}
return nil
}
@ -462,22 +482,25 @@ func AddTeamRepository(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
repo := getRepositoryByParams(ctx)
if ctx.Written() {
return
}
if access, err := models.AccessLevel(ctx.User, repo); err != nil {
ctx.Error(500, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
return
} else if access < models.AccessModeAdmin {
ctx.Error(403, "", "Must have admin-level access to the repository")
ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository")
return
}
if err := ctx.Org.Team.AddRepository(repo); err != nil {
ctx.Error(500, "AddRepository", err)
ctx.Error(http.StatusInternalServerError, "AddRepository", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// RemoveTeamRepository api for removing a repository from a team
@ -509,22 +532,25 @@ func RemoveTeamRepository(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
repo := getRepositoryByParams(ctx)
if ctx.Written() {
return
}
if access, err := models.AccessLevel(ctx.User, repo); err != nil {
ctx.Error(500, "AccessLevel", err)
ctx.Error(http.StatusInternalServerError, "AccessLevel", err)
return
} else if access < models.AccessModeAdmin {
ctx.Error(403, "", "Must have admin-level access to the repository")
ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository")
return
}
if err := ctx.Org.Team.RemoveRepository(repo.ID); err != nil {
ctx.Error(500, "RemoveRepository", err)
ctx.Error(http.StatusInternalServerError, "RemoveRepository", err)
return
}
ctx.Status(204)
ctx.Status(http.StatusNoContent)
}
// SearchTeam api for searching teams
@ -568,6 +594,7 @@ func SearchTeam(ctx *context.APIContext) {
// type: array
// items:
// "$ref": "#/definitions/Team"
opts := &models.SearchTeamOptions{
UserID: ctx.User.ID,
Keyword: strings.TrimSpace(ctx.Query("q")),
@ -580,7 +607,7 @@ func SearchTeam(ctx *context.APIContext) {
teams, _, err := models.SearchTeam(opts)
if err != nil {
log.Error("SearchTeam failed: %v", err)
ctx.JSON(500, map[string]interface{}{
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"ok": false,
"error": "SearchTeam internal failure",
})
@ -591,7 +618,7 @@ func SearchTeam(ctx *context.APIContext) {
for i := range teams {
if err := teams[i].GetUnits(); err != nil {
log.Error("Team GetUnits failed: %v", err)
ctx.JSON(500, map[string]interface{}{
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"ok": false,
"error": "SearchTeam failed to get units",
})
@ -600,7 +627,7 @@ func SearchTeam(ctx *context.APIContext) {
apiTeams[i] = convert.ToTeam(teams[i])
}
ctx.JSON(200, map[string]interface{}{
ctx.JSON(http.StatusOK, map[string]interface{}{
"ok": true,
"data": apiTeams,
})