Contents API should return 404 on not exist (#10323)

* Return 404 on not exist

* swagger update and use git.IsErrNotExist

* Handle delete too

* Handle delete too x2

* Fix pr 10323 (#3)

* fix TESTS

* leafe a note for fututre

* placate golangci-lint

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update integrations/api_repo_file_delete_test.go

Co-Authored-By: 6543 <6543@obermui.de>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
tokarchuk/v1.17
zeripath 5 years ago committed by GitHub
parent 7c8e116987
commit 2e85ad665a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      integrations/api_repo_file_delete_test.go
  2. 10
      integrations/api_repo_get_contents_list_test.go
  3. 10
      integrations/api_repo_get_contents_test.go
  4. 32
      routers/api/v1/repo/file.go
  5. 15
      templates/swagger/v1_json.tmpl

@ -11,8 +11,6 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -109,18 +107,10 @@ func TestAPIDeleteFile(t *testing.T) {
treePath = fmt.Sprintf("delete/file%d.txt", fileID) treePath = fmt.Sprintf("delete/file%d.txt", fileID)
createFile(user2, repo1, treePath) createFile(user2, repo1, treePath)
deleteFileOptions = getDeleteFileOptions() deleteFileOptions = getDeleteFileOptions()
correctSHA := deleteFileOptions.SHA
deleteFileOptions.SHA = "badsha" deleteFileOptions.SHA = "badsha"
url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2) url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo1.Name, treePath, token2)
req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions) req = NewRequestWithJSON(t, "DELETE", url, &deleteFileOptions)
resp = session.MakeRequest(t, req, http.StatusInternalServerError) resp = session.MakeRequest(t, req, http.StatusBadRequest)
expectedAPIError := context.APIError{
Message: "sha does not match [given: " + deleteFileOptions.SHA + ", expected: " + correctSHA + "]",
URL: setting.API.SwaggerURL,
}
var apiError context.APIError
DecodeJSON(t, resp, &apiError)
assert.Equal(t, expectedAPIError, apiError)
// Test creating a file in repo16 by user4 who does not have write access // Test creating a file in repo16 by user4 who does not have write access
fileID++ fileID++

@ -11,7 +11,6 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
repo_module "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -139,14 +138,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
// Test file contents a file with a bad ref // Test file contents a file with a bad ref
ref = "badref" ref = "badref"
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = session.MakeRequest(t, req, http.StatusInternalServerError) resp = session.MakeRequest(t, req, http.StatusNotFound)
expectedAPIError := context.APIError{
Message: "object does not exist [id: " + ref + ", rel_path: ]",
URL: setting.API.SwaggerURL,
}
var apiError context.APIError
DecodeJSON(t, resp, &apiError)
assert.Equal(t, expectedAPIError, apiError)
// Test accessing private ref with user token that does not have access - should fail // Test accessing private ref with user token that does not have access - should fail
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4) req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)

@ -10,7 +10,6 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
repo_module "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -141,14 +140,7 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
// Test file contents a file with a bad ref // Test file contents a file with a bad ref
ref = "badref" ref = "badref"
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref) req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = session.MakeRequest(t, req, http.StatusInternalServerError) resp = session.MakeRequest(t, req, http.StatusNotFound)
expectedAPIError := context.APIError{
Message: "object does not exist [id: " + ref + ", rel_path: ]",
URL: setting.API.SwaggerURL,
}
var apiError context.APIError
DecodeJSON(t, resp, &apiError)
assert.Equal(t, expectedAPIError, apiError)
// Test accessing private ref with user token that does not have access - should fail // Test accessing private ref with user token that does not have access - should fail
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4) req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, repo16.Name, treePath, token4)

@ -362,9 +362,15 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/FileDeleteResponse" // "$ref": "#/responses/FileDeleteResponse"
// "400":
// "$ref": "#/responses/error"
// "403":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
if !CanWriteFiles(ctx.Repo) { if !CanWriteFiles(ctx.Repo) {
ctx.Error(http.StatusInternalServerError, "DeleteFile", models.ErrUserDoesNotHaveAccessToRepo{ ctx.Error(http.StatusForbidden, "DeleteFile", models.ErrUserDoesNotHaveAccessToRepo{
UserID: ctx.User.ID, UserID: ctx.User.ID,
RepoName: ctx.Repo.Repository.LowerName, RepoName: ctx.Repo.Repository.LowerName,
}) })
@ -402,9 +408,23 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) {
} }
if fileResponse, err := repofiles.DeleteRepoFile(ctx.Repo.Repository, ctx.User, opts); err != nil { if fileResponse, err := repofiles.DeleteRepoFile(ctx.Repo.Repository, ctx.User, opts); err != nil {
if git.IsErrBranchNotExist(err) || models.IsErrRepoFileDoesNotExist(err) || git.IsErrNotExist(err) {
ctx.Error(http.StatusNotFound, "DeleteFile", err)
return
} else if models.IsErrBranchAlreadyExists(err) ||
models.IsErrFilenameInvalid(err) ||
models.IsErrSHADoesNotMatch(err) ||
models.IsErrCommitIDDoesNotMatch(err) ||
models.IsErrSHAOrCommitIDNotProvided(err) {
ctx.Error(http.StatusBadRequest, "DeleteFile", err)
return
} else if models.IsErrUserCannotCommit(err) {
ctx.Error(http.StatusForbidden, "DeleteFile", err)
return
}
ctx.Error(http.StatusInternalServerError, "DeleteFile", err) ctx.Error(http.StatusInternalServerError, "DeleteFile", err)
} else { } else {
ctx.JSON(http.StatusOK, fileResponse) ctx.JSON(http.StatusOK, fileResponse) // FIXME on APIv2: return http.StatusNoContent
} }
} }
@ -439,6 +459,8 @@ func GetContents(ctx *context.APIContext) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/ContentsResponse" // "$ref": "#/responses/ContentsResponse"
// "404":
// "$ref": "#/responses/notFound"
if !CanReadFiles(ctx.Repo) { if !CanReadFiles(ctx.Repo) {
ctx.Error(http.StatusInternalServerError, "GetContentsOrList", models.ErrUserDoesNotHaveAccessToRepo{ ctx.Error(http.StatusInternalServerError, "GetContentsOrList", models.ErrUserDoesNotHaveAccessToRepo{
@ -452,6 +474,10 @@ func GetContents(ctx *context.APIContext) {
ref := ctx.QueryTrim("ref") ref := ctx.QueryTrim("ref")
if fileList, err := repofiles.GetContentsOrList(ctx.Repo.Repository, treePath, ref); err != nil { if fileList, err := repofiles.GetContentsOrList(ctx.Repo.Repository, treePath, ref); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetContentsOrList", err)
return
}
ctx.Error(http.StatusInternalServerError, "GetContentsOrList", err) ctx.Error(http.StatusInternalServerError, "GetContentsOrList", err)
} else { } else {
ctx.JSON(http.StatusOK, fileList) ctx.JSON(http.StatusOK, fileList)
@ -484,6 +510,8 @@ func GetContentsList(ctx *context.APIContext) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/ContentsListResponse" // "$ref": "#/responses/ContentsListResponse"
// "404":
// "$ref": "#/responses/notFound"
// same as GetContents(), this function is here because swagger fails if path is empty in GetContents() interface // same as GetContents(), this function is here because swagger fails if path is empty in GetContents() interface
GetContents(ctx) GetContents(ctx)

@ -2638,6 +2638,9 @@
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/ContentsListResponse" "$ref": "#/responses/ContentsListResponse"
},
"404": {
"$ref": "#/responses/notFound"
} }
} }
} }
@ -2684,6 +2687,9 @@
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/ContentsResponse" "$ref": "#/responses/ContentsResponse"
},
"404": {
"$ref": "#/responses/notFound"
} }
} }
}, },
@ -2831,6 +2837,15 @@
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/FileDeleteResponse" "$ref": "#/responses/FileDeleteResponse"
},
"400": {
"$ref": "#/responses/error"
},
"403": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/error"
} }
} }
} }

Loading…
Cancel
Save