Skip to content

Commit bc103e6

Browse files
kasbahAbdulrhmnGhanem
authored andcommitted
Add a JSON file upload endpoint
1 parent dbccb05 commit bc103e6

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

routers/web/repo/editor.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,157 @@ func UploadFilePost(ctx *context.Context) {
725725
}
726726
}
727727

728+
// UploadFilePostJson JSON response for uploading file
729+
func UploadFilePostJson(ctx *context.Context) {
730+
// `renderCommitRights` is a poorly named; it's not responsible directly for rendering anything,
731+
// it returns a boolean
732+
form := web.GetForm(ctx).(*forms.UploadRepoFileForm)
733+
canCommit := renderCommitRights(ctx)
734+
oldBranchName := ctx.Repo.BranchName
735+
branchName := oldBranchName
736+
737+
if form.CommitChoice == frmCommitChoiceNewBranch {
738+
branchName = form.NewBranchName
739+
}
740+
741+
form.TreePath = cleanUploadFileName(form.TreePath)
742+
743+
treeNames, _ := getParentTreeFields(form.TreePath)
744+
if len(treeNames) == 0 {
745+
// We must at least have one element for user to input.
746+
treeNames = []string{""}
747+
}
748+
response := make(map[string]string)
749+
750+
if ctx.HasError() {
751+
response["message"] = "Failed to commit the files"
752+
ctx.JSON(http.StatusUnprocessableEntity, response)
753+
log.Error("failed to commit files")
754+
return
755+
}
756+
757+
if oldBranchName != branchName {
758+
if _, err := ctx.Repo.GitRepo.GetBranch(ctx.Repo.BranchName); err == nil {
759+
response["message"] = "Branch already exists"
760+
ctx.JSON(http.StatusConflict, response)
761+
return
762+
}
763+
} else if !canCommit {
764+
response["message"] = "Can't commit to protected branch"
765+
ctx.JSON(http.StatusUnauthorized, response)
766+
return
767+
}
768+
769+
var newTreePath string
770+
for _, part := range treeNames {
771+
newTreePath = path.Join(newTreePath, part)
772+
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(newTreePath)
773+
if err != nil {
774+
if git.IsErrNotExist(err) {
775+
// Means there is no item with that name, so we're good
776+
break
777+
}
778+
response["message"] = "Something went wrong!"
779+
ctx.JSON(http.StatusInternalServerError, response)
780+
return
781+
}
782+
783+
// User can only upload files to a directory.
784+
if !entry.IsDir() {
785+
ctx.Data["Err_TreePath"] = true
786+
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), tplUploadFile, &form)
787+
response["message"] = "A file with the same name of the new directory already exists."
788+
ctx.JSON(http.StatusConflict, response)
789+
return
790+
}
791+
}
792+
793+
message := strings.TrimSpace(form.CommitSummary)
794+
if len(message) == 0 {
795+
message = ctx.Tr("repo.editor.upload_files_to_dir", form.TreePath)
796+
}
797+
798+
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
799+
if len(form.CommitMessage) > 0 {
800+
message += "\n\n" + form.CommitMessage
801+
}
802+
803+
if err := files_service.UploadRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.UploadRepoFileOptions{
804+
LastCommitID: ctx.Repo.CommitID,
805+
OldBranch: oldBranchName,
806+
NewBranch: branchName,
807+
TreePath: form.TreePath,
808+
Message: message,
809+
Files: form.Files,
810+
}); err != nil {
811+
if models.IsErrLFSFileLocked(err) {
812+
response["message"] = ctx.Tr("repo.editor.upload_file_is_locked")
813+
ctx.JSON(http.StatusUnauthorized, response)
814+
} else if models.IsErrFilenameInvalid(err) {
815+
response["message"] = ctx.Tr("repo.editor.filename_is_invalid")
816+
ctx.JSON(http.StatusUnprocessableEntity, response)
817+
} else if models.IsErrFilePathInvalid(err) {
818+
fileErr := err.(models.ErrFilePathInvalid)
819+
switch fileErr.Type {
820+
case git.EntryModeSymlink:
821+
response["message"] = ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path)
822+
ctx.JSON(http.StatusConflict, response)
823+
case git.EntryModeTree:
824+
response["message"] = ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path)
825+
ctx.JSON(http.StatusConflict, response)
826+
case git.EntryModeBlob:
827+
response["message"] = ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path)
828+
ctx.JSON(http.StatusConflict, response)
829+
default:
830+
response["message"] = "Something went wrong"
831+
ctx.JSON(http.StatusInternalServerError, response)
832+
}
833+
} else if models.IsErrRepoFileAlreadyExists(err) {
834+
response["message"] = ctx.Tr("repo.editor.file_already_exists", form.TreePath)
835+
ctx.JSON(http.StatusConflict, response)
836+
} else if git.IsErrBranchNotExist(err) {
837+
branchErr := err.(git.ErrBranchNotExist)
838+
response["message"] = ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name)
839+
ctx.JSON(http.StatusNotFound, response)
840+
} else if models.IsErrBranchAlreadyExists(err) {
841+
// For when a user specifies a new branch that already exists
842+
branchErr := err.(models.ErrBranchAlreadyExists)
843+
response["message"] = ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName)
844+
ctx.JSON(http.StatusConflict, response)
845+
} else if git.IsErrPushOutOfDate(err) {
846+
response["message"] = ctx.Tr(
847+
"repo.editor.file_changed_while_editing",
848+
ctx.Repo.RepoLink+"/compare/"+ctx.Repo.CommitID+"..."+form.NewBranchName,
849+
)
850+
ctx.JSON(http.StatusConflict, response)
851+
} else if git.IsErrPushRejected(err) {
852+
errPushRej := err.(*git.ErrPushRejected)
853+
if len(errPushRej.Message) == 0 {
854+
response["message"] = ctx.Tr("repo.editor.push_rejected_no_message")
855+
ctx.JSON(http.StatusConflict, response)
856+
} else {
857+
response["response"] = ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message))
858+
ctx.JSON(http.StatusConflict, response)
859+
}
860+
} else {
861+
// os.ErrNotExist - upload file missing in the intervening time?!
862+
log.Error(
863+
"Error during upload to repo: %-v to filepath: %s on %s from %s: %v",
864+
ctx.Repo.Repository,
865+
form.TreePath,
866+
oldBranchName,
867+
form.NewBranchName,
868+
err,
869+
)
870+
response["message"] = ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err)
871+
ctx.JSON(http.StatusInternalServerError, response)
872+
}
873+
return
874+
}
875+
response["message"] = "Committed files successfully."
876+
ctx.JSON(http.StatusCreated, response)
877+
}
878+
728879
func cleanUploadFileName(name string) string {
729880
// Rebase the filename
730881
name = strings.Trim(path.Clean("/"+name), "/")

routers/web/web.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,8 @@ func RegisterRoutes(m *web.Route) {
894894
Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
895895
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick).
896896
Post(bindIgnErr(forms.CherryPickForm{}), repo.CherryPickPost)
897+
// Same as `/_upload/*` but returns JSON
898+
m.Post("/upload/*", repo.MustBeAbleToUpload, bindIgnErr(forms.UploadRepoFileForm{}), repo.UploadFilePostJson)
897899
}, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable)
898900
m.Group("", func() {
899901
m.Post("/upload-file", repo.UploadFileToServer)

0 commit comments

Comments
 (0)