@@ -16,16 +16,18 @@ import (
1616
1717 git_model "code.gitea.io/gitea/models/git"
1818 repo_model "code.gitea.io/gitea/models/repo"
19- "code.gitea.io/gitea/models/unit"
2019 "code.gitea.io/gitea/modules/git"
2120 "code.gitea.io/gitea/modules/gitrepo"
2221 "code.gitea.io/gitea/modules/httpcache"
22+ "code.gitea.io/gitea/modules/json"
2323 "code.gitea.io/gitea/modules/lfs"
2424 "code.gitea.io/gitea/modules/log"
2525 "code.gitea.io/gitea/modules/setting"
2626 "code.gitea.io/gitea/modules/storage"
2727 api "code.gitea.io/gitea/modules/structs"
28+ "code.gitea.io/gitea/modules/util"
2829 "code.gitea.io/gitea/modules/web"
30+ "code.gitea.io/gitea/routers/api/v1/utils"
2931 "code.gitea.io/gitea/routers/common"
3032 "code.gitea.io/gitea/services/context"
3133 pull_service "code.gitea.io/gitea/services/pull"
@@ -375,7 +377,7 @@ func GetEditorconfig(ctx *context.APIContext) {
375377 // required: true
376378 // - name: ref
377379 // in: query
378- // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master) "
380+ // description: "The name of the commit/branch/tag. Default to the repository’s default branch. "
379381 // type: string
380382 // required: false
381383 // responses:
@@ -410,11 +412,6 @@ func canWriteFiles(ctx *context.APIContext, branch string) bool {
410412 ! ctx .Repo .Repository .IsArchived
411413}
412414
413- // canReadFiles returns true if repository is readable and user has proper access level.
414- func canReadFiles (r * context.Repository ) bool {
415- return r .Permission .CanRead (unit .TypeCode )
416- }
417-
418415func base64Reader (s string ) (io.ReadSeeker , error ) {
419416 b , err := base64 .StdEncoding .DecodeString (s )
420417 if err != nil {
@@ -894,6 +891,17 @@ func DeleteFile(ctx *context.APIContext) {
894891 }
895892}
896893
894+ func resolveRefCommit (ctx * context.APIContext , ref string , minCommitIDLen ... int ) * utils.RefCommit {
895+ ref = util .IfZero (ref , ctx .Repo .Repository .DefaultBranch )
896+ refCommit , err := utils .ResolveRefCommit (ctx , ctx .Repo .Repository , ref , minCommitIDLen ... )
897+ if errors .Is (err , util .ErrNotExist ) {
898+ ctx .APIErrorNotFound (err )
899+ } else if err != nil {
900+ ctx .APIErrorInternal (err )
901+ }
902+ return refCommit
903+ }
904+
897905// GetContents Get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir
898906func GetContents (ctx * context.APIContext ) {
899907 // swagger:operation GET /repos/{owner}/{repo}/contents/{filepath} repository repoGetContents
@@ -919,7 +927,7 @@ func GetContents(ctx *context.APIContext) {
919927 // required: true
920928 // - name: ref
921929 // in: query
922- // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master) "
930+ // description: "The name of the commit/branch/tag. Default to the repository’s default branch. "
923931 // type: string
924932 // required: false
925933 // responses:
@@ -928,18 +936,13 @@ func GetContents(ctx *context.APIContext) {
928936 // "404":
929937 // "$ref": "#/responses/notFound"
930938
931- if ! canReadFiles (ctx .Repo ) {
932- ctx .APIErrorInternal (repo_model.ErrUserDoesNotHaveAccessToRepo {
933- UserID : ctx .Doer .ID ,
934- RepoName : ctx .Repo .Repository .LowerName ,
935- })
939+ treePath := ctx .PathParam ("*" )
940+ refCommit := resolveRefCommit (ctx , ctx .FormTrim ("ref" ))
941+ if ctx .Written () {
936942 return
937943 }
938944
939- treePath := ctx .PathParam ("*" )
940- ref := ctx .FormTrim ("ref" )
941-
942- if fileList , err := files_service .GetContentsOrList (ctx , ctx .Repo .Repository , treePath , ref ); err != nil {
945+ if fileList , err := files_service .GetContentsOrList (ctx , ctx .Repo .Repository , refCommit , treePath ); err != nil {
943946 if git .IsErrNotExist (err ) {
944947 ctx .APIErrorNotFound ("GetContentsOrList" , err )
945948 return
@@ -970,7 +973,7 @@ func GetContentsList(ctx *context.APIContext) {
970973 // required: true
971974 // - name: ref
972975 // in: query
973- // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master) "
976+ // description: "The name of the commit/branch/tag. Default to the repository’s default branch. "
974977 // type: string
975978 // required: false
976979 // responses:
@@ -982,3 +985,102 @@ func GetContentsList(ctx *context.APIContext) {
982985 // same as GetContents(), this function is here because swagger fails if path is empty in GetContents() interface
983986 GetContents (ctx )
984987}
988+
989+ func GetFileContentsGet (ctx * context.APIContext ) {
990+ // swagger:operation GET /repos/{owner}/{repo}/file-contents repository repoGetFileContents
991+ // ---
992+ // summary: Get the metadata and contents of requested files
993+ // description: See the POST method. This GET method supports to use JSON encoded request body in query parameter.
994+ // produces:
995+ // - application/json
996+ // parameters:
997+ // - name: owner
998+ // in: path
999+ // description: owner of the repo
1000+ // type: string
1001+ // required: true
1002+ // - name: repo
1003+ // in: path
1004+ // description: name of the repo
1005+ // type: string
1006+ // required: true
1007+ // - name: ref
1008+ // in: query
1009+ // description: "The name of the commit/branch/tag. Default to the repository’s default branch."
1010+ // type: string
1011+ // required: false
1012+ // - name: body
1013+ // in: query
1014+ // description: "The JSON encoded body (see the POST request): {\"files\": [\"filename1\", \"filename2\"]}"
1015+ // type: string
1016+ // required: true
1017+ // responses:
1018+ // "200":
1019+ // "$ref": "#/responses/ContentsListResponse"
1020+ // "404":
1021+ // "$ref": "#/responses/notFound"
1022+
1023+ // POST method requires "write" permission, so we also support this "GET" method
1024+ handleGetFileContents (ctx )
1025+ }
1026+
1027+ func GetFileContentsPost (ctx * context.APIContext ) {
1028+ // swagger:operation POST /repos/{owner}/{repo}/file-contents repository repoGetFileContentsPost
1029+ // ---
1030+ // summary: Get the metadata and contents of requested files
1031+ // description: Uses automatic pagination based on default page size and
1032+ // max response size and returns the maximum allowed number of files.
1033+ // Files which could not be retrieved are null. Files which are too large
1034+ // are being returned with `encoding == null`, `content == null` and `size > 0`,
1035+ // they can be requested separately by using the `download_url`.
1036+ // produces:
1037+ // - application/json
1038+ // parameters:
1039+ // - name: owner
1040+ // in: path
1041+ // description: owner of the repo
1042+ // type: string
1043+ // required: true
1044+ // - name: repo
1045+ // in: path
1046+ // description: name of the repo
1047+ // type: string
1048+ // required: true
1049+ // - name: ref
1050+ // in: query
1051+ // description: "The name of the commit/branch/tag. Default to the repository’s default branch."
1052+ // type: string
1053+ // required: false
1054+ // - name: body
1055+ // in: body
1056+ // required: true
1057+ // schema:
1058+ // "$ref": "#/definitions/GetFilesOptions"
1059+ // responses:
1060+ // "200":
1061+ // "$ref": "#/responses/ContentsListResponse"
1062+ // "404":
1063+ // "$ref": "#/responses/notFound"
1064+
1065+ // This is actually a "read" request, but we need to accept a "files" list, then POST method seems easy to use.
1066+ // But the permission system requires that the caller must have "write" permission to use POST method.
1067+ // At the moment there is no other way to get around the permission check, so there is a "GET" workaround method above.
1068+ handleGetFileContents (ctx )
1069+ }
1070+
1071+ func handleGetFileContents (ctx * context.APIContext ) {
1072+ opts , ok := web .GetForm (ctx ).(* api.GetFilesOptions )
1073+ if ! ok {
1074+ err := json .Unmarshal (util .UnsafeStringToBytes (ctx .FormString ("body" )), & opts )
1075+ if err != nil {
1076+ ctx .APIError (http .StatusBadRequest , "invalid body parameter" )
1077+ return
1078+ }
1079+ }
1080+ refCommit := resolveRefCommit (ctx , ctx .FormTrim ("ref" ))
1081+ if ctx .Written () {
1082+ return
1083+ }
1084+ filesResponse := files_service .GetContentsListFromTreePaths (ctx , ctx .Repo .Repository , refCommit , opts .Files )
1085+ ctx .JSON (http .StatusOK , util .SliceNilAsEmpty (filesResponse ))
1086+ }
0 commit comments