2016-08-11 05:48:08 -07:00
// Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
2016-08-30 05:07:50 -07:00
"fmt"
2016-08-11 05:48:08 -07:00
"io/ioutil"
2016-08-30 05:07:50 -07:00
"net/http"
2016-08-11 05:48:08 -07:00
"path"
"strings"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
2019-03-27 17:33:00 +08:00
"code.gitea.io/gitea/modules/git"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/log"
2019-04-17 10:06:35 -06:00
"code.gitea.io/gitea/modules/repofiles"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/setting"
2016-12-06 18:58:31 +01:00
"code.gitea.io/gitea/modules/templates"
2019-04-17 01:07:13 +01:00
"code.gitea.io/gitea/modules/util"
2016-08-11 05:48:08 -07:00
)
const (
2016-11-24 15:04:31 +08:00
tplEditFile base . TplName = "repo/editor/edit"
tplEditDiffPreview base . TplName = "repo/editor/diff_preview"
tplDeleteFile base . TplName = "repo/editor/delete"
tplUploadFile base . TplName = "repo/editor/upload"
2017-05-02 03:49:55 +03:00
frmCommitChoiceDirect string = "direct"
frmCommitChoiceNewBranch string = "commit-to-new-branch"
2016-08-11 05:48:08 -07:00
)
2017-05-02 03:49:55 +03:00
func renderCommitRights ( ctx * context . Context ) bool {
2017-09-14 16:16:22 +08:00
canCommit , err := ctx . Repo . CanCommitToBranch ( ctx . User )
2017-05-02 03:49:55 +03:00
if err != nil {
2019-04-02 08:48:31 +01:00
log . Error ( "CanCommitToBranch: %v" , err )
2017-05-02 03:49:55 +03:00
}
ctx . Data [ "CanCommitToBranch" ] = canCommit
return canCommit
}
2017-06-22 23:30:47 +08:00
// getParentTreeFields returns list of parent tree names and corresponding tree paths
// based on given tree path.
func getParentTreeFields ( treePath string ) ( treeNames [ ] string , treePaths [ ] string ) {
if len ( treePath ) == 0 {
return treeNames , treePaths
}
treeNames = strings . Split ( treePath , "/" )
treePaths = make ( [ ] string , len ( treeNames ) )
for i := range treeNames {
treePaths [ i ] = strings . Join ( treeNames [ : i + 1 ] , "/" )
}
return treeNames , treePaths
}
2016-08-11 05:48:08 -07:00
func editFile ( ctx * context . Context , isNewFile bool ) {
ctx . Data [ "PageIsEdit" ] = true
ctx . Data [ "IsNewFile" ] = isNewFile
ctx . Data [ "RequireHighlightJS" ] = true
2016-08-14 23:02:14 -07:00
ctx . Data [ "RequireSimpleMDE" ] = true
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2016-08-11 05:48:08 -07:00
2019-02-12 13:07:31 +00:00
treePath := cleanUploadFileName ( ctx . Repo . TreePath )
if treePath != ctx . Repo . TreePath {
if isNewFile {
2019-04-17 01:07:13 +01:00
ctx . Redirect ( path . Join ( ctx . Repo . RepoLink , "_new" , util . PathEscapeSegments ( ctx . Repo . BranchName ) , util . PathEscapeSegments ( treePath ) ) )
2019-02-12 13:07:31 +00:00
} else {
2019-04-17 01:07:13 +01:00
ctx . Redirect ( path . Join ( ctx . Repo . RepoLink , "_edit" , util . PathEscapeSegments ( ctx . Repo . BranchName ) , util . PathEscapeSegments ( treePath ) ) )
2019-02-12 13:07:31 +00:00
}
return
}
2017-06-22 23:30:47 +08:00
treeNames , treePaths := getParentTreeFields ( ctx . Repo . TreePath )
2016-08-11 05:48:08 -07:00
if ! isNewFile {
2016-08-24 21:35:03 -07:00
entry , err := ctx . Repo . Commit . GetTreeEntryByPath ( ctx . Repo . TreePath )
2016-08-14 23:02:14 -07:00
if err != nil {
2016-08-30 05:07:50 -07:00
ctx . NotFoundOrServerError ( "GetTreeEntryByPath" , git . IsErrNotExist , err )
2016-08-11 05:48:08 -07:00
return
}
2016-08-14 23:02:14 -07:00
// No way to edit a directory online.
if entry . IsDir ( ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "entry.IsDir" , nil )
2016-08-11 05:48:08 -07:00
return
}
blob := entry . Blob ( )
2017-11-29 02:50:39 +01:00
if blob . Size ( ) >= setting . UI . MaxDisplayFileSize {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "blob.Size" , err )
2017-11-29 02:50:39 +01:00
return
}
2019-04-19 14:17:27 +02:00
dataRc , err := blob . DataAsync ( )
2016-08-11 05:48:08 -07:00
if err != nil {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "blob.Data" , err )
2016-08-11 05:48:08 -07:00
return
}
2019-04-19 14:17:27 +02:00
defer dataRc . Close ( )
2016-08-11 05:48:08 -07:00
ctx . Data [ "FileSize" ] = blob . Size ( )
ctx . Data [ "FileName" ] = blob . Name ( )
buf := make ( [ ] byte , 1024 )
n , _ := dataRc . Read ( buf )
2016-08-31 13:59:23 -07:00
buf = buf [ : n ]
2016-08-11 05:48:08 -07:00
2016-08-14 23:02:14 -07:00
// Only text file are editable online.
2016-08-30 02:08:38 -07:00
if ! base . IsTextFile ( buf ) {
2018-01-10 22:34:17 +01:00
ctx . NotFound ( "base.IsTextFile" , nil )
2016-08-11 05:48:08 -07:00
return
}
d , _ := ioutil . ReadAll ( dataRc )
buf = append ( buf , d ... )
2016-12-06 18:58:31 +01:00
if content , err := templates . ToUTF8WithErr ( buf ) ; err != nil {
2019-06-12 21:41:28 +02:00
log . Error ( "ToUTF8WithErr: %v" , err )
2016-08-11 05:48:08 -07:00
ctx . Data [ "FileContent" ] = string ( buf )
} else {
ctx . Data [ "FileContent" ] = content
}
} else {
2016-08-14 23:02:14 -07:00
treeNames = append ( treeNames , "" ) // Append empty string to allow user name the new file.
2016-08-11 05:48:08 -07:00
}
ctx . Data [ "TreeNames" ] = treeNames
2017-06-22 23:30:47 +08:00
ctx . Data [ "TreePaths" ] = treePaths
2017-10-29 19:04:25 -07:00
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/" + ctx . Repo . BranchNameSubURL ( )
2016-08-14 23:02:14 -07:00
ctx . Data [ "commit_summary" ] = ""
ctx . Data [ "commit_message" ] = ""
2017-05-02 03:49:55 +03:00
if canCommit {
ctx . Data [ "commit_choice" ] = frmCommitChoiceDirect
} else {
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
}
2016-08-14 23:02:14 -07:00
ctx . Data [ "new_branch_name" ] = ""
2019-04-17 10:06:35 -06:00
ctx . Data [ "last_commit" ] = ctx . Repo . CommitID
2016-08-12 02:29:29 -07:00
ctx . Data [ "MarkdownFileExts" ] = strings . Join ( setting . Markdown . FileExtensions , "," )
ctx . Data [ "LineWrapExtensions" ] = strings . Join ( setting . Repository . Editor . LineWrapExtensions , "," )
ctx . Data [ "PreviewableFileModes" ] = strings . Join ( setting . Repository . Editor . PreviewableFileModes , "," )
2016-11-27 18:14:25 +08:00
ctx . Data [ "EditorconfigURLPrefix" ] = fmt . Sprintf ( "%s/api/v1/repos/%s/editorconfig/" , setting . AppSubURL , ctx . Repo . Repository . FullName ( ) )
2016-08-11 05:48:08 -07:00
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplEditFile )
2016-08-11 05:48:08 -07:00
}
2016-11-24 15:04:31 +08:00
// EditFile render edit file page
2016-08-14 23:02:14 -07:00
func EditFile ( ctx * context . Context ) {
editFile ( ctx , false )
2016-08-11 05:48:08 -07:00
}
2016-11-24 15:04:31 +08:00
// NewFile render create file page
2016-08-14 23:02:14 -07:00
func NewFile ( ctx * context . Context ) {
editFile ( ctx , true )
2016-08-11 05:48:08 -07:00
}
func editFilePost ( ctx * context . Context , form auth . EditRepoFileForm , isNewFile bool ) {
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2019-04-17 10:06:35 -06:00
treeNames , treePaths := getParentTreeFields ( form . TreePath )
branchName := ctx . Repo . BranchName
2017-05-02 03:49:55 +03:00
if form . CommitChoice == frmCommitChoiceNewBranch {
2016-08-11 05:48:08 -07:00
branchName = form . NewBranchName
}
2019-04-17 10:06:35 -06:00
ctx . Data [ "PageIsEdit" ] = true
ctx . Data [ "IsNewFile" ] = isNewFile
ctx . Data [ "RequireHighlightJS" ] = true
ctx . Data [ "RequireSimpleMDE" ] = true
2016-08-24 21:35:03 -07:00
ctx . Data [ "TreePath" ] = form . TreePath
2016-08-11 05:48:08 -07:00
ctx . Data [ "TreeNames" ] = treeNames
2017-06-22 23:30:47 +08:00
ctx . Data [ "TreePaths" ] = treePaths
2019-04-17 10:06:35 -06:00
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/branch/" + ctx . Repo . BranchName
2016-08-28 01:41:44 -07:00
ctx . Data [ "FileContent" ] = form . Content
2016-08-14 23:02:14 -07:00
ctx . Data [ "commit_summary" ] = form . CommitSummary
ctx . Data [ "commit_message" ] = form . CommitMessage
2016-08-28 01:41:44 -07:00
ctx . Data [ "commit_choice" ] = form . CommitChoice
2019-04-17 10:06:35 -06:00
ctx . Data [ "new_branch_name" ] = form . NewBranchName
ctx . Data [ "last_commit" ] = ctx . Repo . CommitID
2016-08-12 02:29:29 -07:00
ctx . Data [ "MarkdownFileExts" ] = strings . Join ( setting . Markdown . FileExtensions , "," )
ctx . Data [ "LineWrapExtensions" ] = strings . Join ( setting . Repository . Editor . LineWrapExtensions , "," )
ctx . Data [ "PreviewableFileModes" ] = strings . Join ( setting . Repository . Editor . PreviewableFileModes , "," )
2016-08-11 05:48:08 -07:00
if ctx . HasError ( ) {
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplEditFile )
2016-08-11 05:48:08 -07:00
return
}
2019-04-17 10:06:35 -06:00
// Cannot commit to a an existing branch if user doesn't have rights
if branchName == ctx . Repo . BranchName && ! canCommit {
2017-05-02 03:49:55 +03:00
ctx . Data [ "Err_NewBranchName" ] = true
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.cannot_commit_to_protected_branch" , branchName ) , tplEditFile , & form )
return
2016-08-11 05:48:08 -07:00
}
2019-04-17 10:06:35 -06:00
// CommitSummary is optional in the web form, if empty, give it a default message based on add or update
// `message` will be both the summary and message combined
2016-08-28 01:41:44 -07:00
message := strings . TrimSpace ( form . CommitSummary )
if len ( message ) == 0 {
2016-08-11 05:48:08 -07:00
if isNewFile {
2016-08-24 21:35:03 -07:00
message = ctx . Tr ( "repo.editor.add" , form . TreePath )
2016-08-11 05:48:08 -07:00
} else {
2016-08-24 21:35:03 -07:00
message = ctx . Tr ( "repo.editor.update" , form . TreePath )
2016-08-11 05:48:08 -07:00
}
}
2016-08-14 23:02:14 -07:00
form . CommitMessage = strings . TrimSpace ( form . CommitMessage )
if len ( form . CommitMessage ) > 0 {
message += "\n\n" + form . CommitMessage
2016-08-11 05:48:08 -07:00
}
2019-04-17 10:06:35 -06:00
if _ , err := repofiles . CreateOrUpdateRepoFile ( ctx . Repo . Repository , ctx . User , & repofiles . UpdateRepoFileOptions {
LastCommitID : form . LastCommit ,
OldBranch : ctx . Repo . BranchName ,
2016-08-14 23:02:14 -07:00
NewBranch : branchName ,
2019-04-17 10:06:35 -06:00
FromTreePath : ctx . Repo . TreePath ,
TreePath : form . TreePath ,
2016-08-14 23:02:14 -07:00
Message : message ,
2016-08-28 05:32:10 -07:00
Content : strings . Replace ( form . Content , "\r" , "" , - 1 ) ,
2016-08-14 23:02:14 -07:00
IsNewFile : isNewFile ,
} ) ; err != nil {
2019-04-17 10:06:35 -06:00
// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile
if git . IsErrNotExist ( err ) {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_editing_no_longer_exists" , ctx . Repo . TreePath ) , tplEditFile , & form )
} else if models . IsErrFilenameInvalid ( err ) {
ctx . Data [ "Err_TreePath" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.filename_is_invalid" , form . TreePath ) , tplEditFile , & form )
} else if models . IsErrFilePathInvalid ( err ) {
ctx . Data [ "Err_TreePath" ] = true
if fileErr , ok := err . ( models . ErrFilePathInvalid ) ; ok {
switch fileErr . Type {
case git . EntryModeSymlink :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_is_a_symlink" , fileErr . Path ) , tplEditFile , & form )
case git . EntryModeTree :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.filename_is_a_directory" , fileErr . Path ) , tplEditFile , & form )
case git . EntryModeBlob :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.directory_is_a_file" , fileErr . Path ) , tplEditFile , & form )
default :
ctx . Error ( 500 , err . Error ( ) )
}
} else {
ctx . Error ( 500 , err . Error ( ) )
}
} else if models . IsErrRepoFileAlreadyExists ( err ) {
ctx . Data [ "Err_TreePath" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_already_exists" , form . TreePath ) , tplEditFile , & form )
2019-04-19 14:17:27 +02:00
} else if git . IsErrBranchNotExist ( err ) {
2019-04-17 10:06:35 -06:00
// For when a user adds/updates a file to a branch that no longer exists
2019-04-19 14:17:27 +02:00
if branchErr , ok := err . ( git . ErrBranchNotExist ) ; ok {
2019-04-17 10:06:35 -06:00
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.branch_does_not_exist" , branchErr . Name ) , tplEditFile , & form )
} else {
ctx . Error ( 500 , err . Error ( ) )
}
} else if models . IsErrBranchAlreadyExists ( err ) {
// For when a user specifies a new branch that already exists
ctx . Data [ "Err_NewBranchName" ] = true
if branchErr , ok := err . ( models . ErrBranchAlreadyExists ) ; ok {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.branch_already_exists" , branchErr . BranchName ) , tplEditFile , & form )
} else {
ctx . Error ( 500 , err . Error ( ) )
}
} else if models . IsErrCommitIDDoesNotMatch ( err ) {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_changed_while_editing" , ctx . Repo . RepoLink + "/compare/" + form . LastCommit + "..." + ctx . Repo . CommitID ) , tplEditFile , & form )
} else {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.fail_to_update_file" , form . TreePath , err ) , tplEditFile , & form )
}
} else {
ctx . Redirect ( ctx . Repo . RepoLink + "/src/branch/" + util . PathEscapeSegments ( branchName ) + "/" + util . PathEscapeSegments ( form . TreePath ) )
2016-08-11 05:48:08 -07:00
}
2016-08-14 23:02:14 -07:00
}
2016-08-11 05:48:08 -07:00
2016-11-24 15:04:31 +08:00
// EditFilePost response for editing file
2016-08-14 23:02:14 -07:00
func EditFilePost ( ctx * context . Context , form auth . EditRepoFileForm ) {
editFilePost ( ctx , form , false )
}
2016-11-24 15:04:31 +08:00
// NewFilePost response for creating file
2016-08-14 23:02:14 -07:00
func NewFilePost ( ctx * context . Context , form auth . EditRepoFileForm ) {
editFilePost ( ctx , form , true )
2016-08-11 05:48:08 -07:00
}
2016-11-24 15:04:31 +08:00
// DiffPreviewPost render preview diff page
2016-08-11 05:48:08 -07:00
func DiffPreviewPost ( ctx * context . Context , form auth . EditPreviewDiffForm ) {
2019-02-12 13:07:31 +00:00
treePath := cleanUploadFileName ( ctx . Repo . TreePath )
if len ( treePath ) == 0 {
ctx . Error ( 500 , "file name to diff is invalid" )
return
}
2016-08-11 05:48:08 -07:00
2016-08-28 01:41:44 -07:00
entry , err := ctx . Repo . Commit . GetTreeEntryByPath ( treePath )
2016-08-14 23:02:14 -07:00
if err != nil {
2016-08-28 04:31:42 -07:00
ctx . Error ( 500 , "GetTreeEntryByPath: " + err . Error ( ) )
2016-08-14 23:02:14 -07:00
return
2016-08-28 04:31:42 -07:00
} else if entry . IsDir ( ) {
2016-08-14 23:02:14 -07:00
ctx . Error ( 422 )
2016-08-11 05:48:08 -07:00
return
}
2019-04-17 10:06:35 -06:00
diff , err := repofiles . GetDiffPreview ( ctx . Repo . Repository , ctx . Repo . BranchName , treePath , form . Content )
2016-08-11 05:48:08 -07:00
if err != nil {
2016-08-14 23:02:14 -07:00
ctx . Error ( 500 , "GetDiffPreview: " + err . Error ( ) )
2016-08-11 05:48:08 -07:00
return
}
if diff . NumFiles ( ) == 0 {
2016-08-14 23:02:14 -07:00
ctx . PlainText ( 200 , [ ] byte ( ctx . Tr ( "repo.editor.no_changes_to_show" ) ) )
2016-08-11 05:48:08 -07:00
return
}
ctx . Data [ "File" ] = diff . Files [ 0 ]
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplEditDiffPreview )
2016-08-28 01:41:44 -07:00
}
2016-11-24 15:04:31 +08:00
// DeleteFile render delete file page
2016-08-28 01:41:44 -07:00
func DeleteFile ( ctx * context . Context ) {
ctx . Data [ "PageIsDelete" ] = true
2017-10-29 19:04:25 -07:00
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/" + ctx . Repo . BranchNameSubURL ( )
2019-02-12 13:07:31 +00:00
treePath := cleanUploadFileName ( ctx . Repo . TreePath )
if treePath != ctx . Repo . TreePath {
2019-04-17 01:07:13 +01:00
ctx . Redirect ( path . Join ( ctx . Repo . RepoLink , "_delete" , util . PathEscapeSegments ( ctx . Repo . BranchName ) , util . PathEscapeSegments ( treePath ) ) )
2019-02-12 13:07:31 +00:00
return
}
ctx . Data [ "TreePath" ] = treePath
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2016-08-28 01:41:44 -07:00
ctx . Data [ "commit_summary" ] = ""
ctx . Data [ "commit_message" ] = ""
2019-04-17 10:06:35 -06:00
ctx . Data [ "last_commit" ] = ctx . Repo . CommitID
2017-05-02 03:49:55 +03:00
if canCommit {
ctx . Data [ "commit_choice" ] = frmCommitChoiceDirect
} else {
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
}
2016-08-28 01:41:44 -07:00
ctx . Data [ "new_branch_name" ] = ""
2017-05-02 03:49:55 +03:00
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplDeleteFile )
2016-08-11 05:48:08 -07:00
}
2016-08-14 23:38:35 -07:00
2016-11-24 15:04:31 +08:00
// DeleteFilePost response for deleting file
2016-08-14 23:38:35 -07:00
func DeleteFilePost ( ctx * context . Context , form auth . DeleteRepoFileForm ) {
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2019-04-17 10:06:35 -06:00
branchName := ctx . Repo . BranchName
2017-05-02 03:49:55 +03:00
if form . CommitChoice == frmCommitChoiceNewBranch {
2016-08-28 01:41:44 -07:00
branchName = form . NewBranchName
}
2019-04-17 10:06:35 -06:00
ctx . Data [ "PageIsDelete" ] = true
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/" + ctx . Repo . BranchNameSubURL ( )
ctx . Data [ "TreePath" ] = ctx . Repo . TreePath
2016-08-28 01:41:44 -07:00
ctx . Data [ "commit_summary" ] = form . CommitSummary
ctx . Data [ "commit_message" ] = form . CommitMessage
ctx . Data [ "commit_choice" ] = form . CommitChoice
2019-04-17 10:06:35 -06:00
ctx . Data [ "new_branch_name" ] = form . NewBranchName
ctx . Data [ "last_commit" ] = ctx . Repo . CommitID
2016-08-14 23:38:35 -07:00
if ctx . HasError ( ) {
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplDeleteFile )
2016-08-14 23:38:35 -07:00
return
}
2019-04-17 10:06:35 -06:00
if branchName != ctx . Repo . BranchName && ! canCommit {
2017-05-02 03:49:55 +03:00
ctx . Data [ "Err_NewBranchName" ] = true
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.cannot_commit_to_protected_branch" , branchName ) , tplDeleteFile , & form )
return
2016-08-28 01:41:44 -07:00
}
message := strings . TrimSpace ( form . CommitSummary )
if len ( message ) == 0 {
2016-08-30 05:07:50 -07:00
message = ctx . Tr ( "repo.editor.delete" , ctx . Repo . TreePath )
2016-08-28 01:41:44 -07:00
}
form . CommitMessage = strings . TrimSpace ( form . CommitMessage )
if len ( form . CommitMessage ) > 0 {
message += "\n\n" + form . CommitMessage
}
2019-04-17 10:06:35 -06:00
if _ , err := repofiles . DeleteRepoFile ( ctx . Repo . Repository , ctx . User , & repofiles . DeleteRepoFileOptions {
LastCommitID : form . LastCommit ,
OldBranch : ctx . Repo . BranchName ,
2016-08-28 01:41:44 -07:00
NewBranch : branchName ,
2016-08-30 05:07:50 -07:00
TreePath : ctx . Repo . TreePath ,
2016-08-28 01:41:44 -07:00
Message : message ,
2016-08-16 23:06:38 -07:00
} ) ; err != nil {
2019-04-17 10:06:35 -06:00
// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
if git . IsErrNotExist ( err ) || models . IsErrRepoFileDoesNotExist ( err ) {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_deleting_no_longer_exists" , ctx . Repo . TreePath ) , tplEditFile , & form )
} else if models . IsErrFilenameInvalid ( err ) {
ctx . Data [ "Err_TreePath" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.filename_is_invalid" , ctx . Repo . TreePath ) , tplEditFile , & form )
} else if models . IsErrFilePathInvalid ( err ) {
ctx . Data [ "Err_TreePath" ] = true
if fileErr , ok := err . ( models . ErrFilePathInvalid ) ; ok {
switch fileErr . Type {
case git . EntryModeSymlink :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_is_a_symlink" , fileErr . Path ) , tplEditFile , & form )
case git . EntryModeTree :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.filename_is_a_directory" , fileErr . Path ) , tplEditFile , & form )
case git . EntryModeBlob :
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.directory_is_a_file" , fileErr . Path ) , tplEditFile , & form )
default :
ctx . ServerError ( "DeleteRepoFile" , err )
}
} else {
ctx . ServerError ( "DeleteRepoFile" , err )
}
2019-04-19 14:17:27 +02:00
} else if git . IsErrBranchNotExist ( err ) {
2019-04-17 10:06:35 -06:00
// For when a user deletes a file to a branch that no longer exists
2019-04-19 14:17:27 +02:00
if branchErr , ok := err . ( git . ErrBranchNotExist ) ; ok {
2019-04-17 10:06:35 -06:00
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.branch_does_not_exist" , branchErr . Name ) , tplEditFile , & form )
} else {
ctx . Error ( 500 , err . Error ( ) )
}
} else if models . IsErrBranchAlreadyExists ( err ) {
// For when a user specifies a new branch that already exists
if branchErr , ok := err . ( models . ErrBranchAlreadyExists ) ; ok {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.branch_already_exists" , branchErr . BranchName ) , tplEditFile , & form )
} else {
ctx . Error ( 500 , err . Error ( ) )
}
} else if models . IsErrCommitIDDoesNotMatch ( err ) {
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.file_changed_while_editing" , ctx . Repo . RepoLink + "/compare/" + form . LastCommit + "..." + ctx . Repo . CommitID ) , tplEditFile , & form )
} else {
ctx . ServerError ( "DeleteRepoFile" , err )
}
} else {
ctx . Flash . Success ( ctx . Tr ( "repo.editor.file_delete_success" , ctx . Repo . TreePath ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/src/branch/" + util . PathEscapeSegments ( branchName ) )
2016-08-14 23:38:35 -07:00
}
}
2016-08-30 05:07:50 -07:00
func renderUploadSettings ( ctx * context . Context ) {
ctx . Data [ "RequireDropzone" ] = true
ctx . Data [ "UploadAllowedTypes" ] = strings . Join ( setting . Repository . Upload . AllowedTypes , "," )
ctx . Data [ "UploadMaxSize" ] = setting . Repository . Upload . FileMaxSize
ctx . Data [ "UploadMaxFiles" ] = setting . Repository . Upload . MaxFiles
}
2016-11-24 15:04:31 +08:00
// UploadFile render upload file page
2016-08-30 05:07:50 -07:00
func UploadFile ( ctx * context . Context ) {
ctx . Data [ "PageIsUpload" ] = true
renderUploadSettings ( ctx )
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2019-02-12 13:07:31 +00:00
treePath := cleanUploadFileName ( ctx . Repo . TreePath )
if treePath != ctx . Repo . TreePath {
2019-04-17 01:07:13 +01:00
ctx . Redirect ( path . Join ( ctx . Repo . RepoLink , "_upload" , util . PathEscapeSegments ( ctx . Repo . BranchName ) , util . PathEscapeSegments ( treePath ) ) )
2019-02-12 13:07:31 +00:00
return
}
ctx . Repo . TreePath = treePath
2016-08-30 05:07:50 -07:00
2017-06-22 23:30:47 +08:00
treeNames , treePaths := getParentTreeFields ( ctx . Repo . TreePath )
if len ( treeNames ) == 0 {
// We must at least have one element for user to input.
treeNames = [ ] string { "" }
2016-08-30 05:07:50 -07:00
}
ctx . Data [ "TreeNames" ] = treeNames
2017-06-22 23:30:47 +08:00
ctx . Data [ "TreePaths" ] = treePaths
2017-10-29 19:04:25 -07:00
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/" + ctx . Repo . BranchNameSubURL ( )
2016-08-30 05:07:50 -07:00
ctx . Data [ "commit_summary" ] = ""
ctx . Data [ "commit_message" ] = ""
2017-05-02 03:49:55 +03:00
if canCommit {
ctx . Data [ "commit_choice" ] = frmCommitChoiceDirect
} else {
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
}
2016-08-30 05:07:50 -07:00
ctx . Data [ "new_branch_name" ] = ""
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplUploadFile )
2016-08-30 05:07:50 -07:00
}
2016-11-24 15:04:31 +08:00
// UploadFilePost response for uploading file
2016-08-30 05:07:50 -07:00
func UploadFilePost ( ctx * context . Context , form auth . UploadRepoFileForm ) {
ctx . Data [ "PageIsUpload" ] = true
renderUploadSettings ( ctx )
2017-05-02 03:49:55 +03:00
canCommit := renderCommitRights ( ctx )
2016-08-30 05:07:50 -07:00
oldBranchName := ctx . Repo . BranchName
branchName := oldBranchName
2017-05-02 03:49:55 +03:00
if form . CommitChoice == frmCommitChoiceNewBranch {
2016-08-30 05:07:50 -07:00
branchName = form . NewBranchName
}
2019-01-04 16:08:26 +00:00
form . TreePath = cleanUploadFileName ( form . TreePath )
2017-06-22 23:30:47 +08:00
treeNames , treePaths := getParentTreeFields ( form . TreePath )
if len ( treeNames ) == 0 {
// We must at least have one element for user to input.
treeNames = [ ] string { "" }
2016-08-30 05:07:50 -07:00
}
ctx . Data [ "TreePath" ] = form . TreePath
ctx . Data [ "TreeNames" ] = treeNames
2017-06-22 23:30:47 +08:00
ctx . Data [ "TreePaths" ] = treePaths
2017-10-29 19:04:25 -07:00
ctx . Data [ "BranchLink" ] = ctx . Repo . RepoLink + "/src/branch/" + branchName
2016-08-30 05:07:50 -07:00
ctx . Data [ "commit_summary" ] = form . CommitSummary
ctx . Data [ "commit_message" ] = form . CommitMessage
ctx . Data [ "commit_choice" ] = form . CommitChoice
ctx . Data [ "new_branch_name" ] = branchName
if ctx . HasError ( ) {
2016-11-24 15:04:31 +08:00
ctx . HTML ( 200 , tplUploadFile )
2016-08-30 05:07:50 -07:00
return
}
if oldBranchName != branchName {
if _ , err := ctx . Repo . Repository . GetBranch ( branchName ) ; err == nil {
ctx . Data [ "Err_NewBranchName" ] = true
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.branch_already_exists" , branchName ) , tplUploadFile , & form )
2016-08-30 05:07:50 -07:00
return
}
2017-05-02 03:49:55 +03:00
} else if ! canCommit {
ctx . Data [ "Err_NewBranchName" ] = true
ctx . Data [ "commit_choice" ] = frmCommitChoiceNewBranch
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.cannot_commit_to_protected_branch" , branchName ) , tplUploadFile , & form )
return
2016-08-30 05:07:50 -07:00
}
var newTreePath string
for _ , part := range treeNames {
newTreePath = path . Join ( newTreePath , part )
entry , err := ctx . Repo . Commit . GetTreeEntryByPath ( newTreePath )
if err != nil {
if git . IsErrNotExist ( err ) {
// Means there is no item with that name, so we're good
break
}
2018-01-10 22:34:17 +01:00
ctx . ServerError ( "Repo.Commit.GetTreeEntryByPath" , err )
2016-08-30 05:07:50 -07:00
return
}
// User can only upload files to a directory.
if ! entry . IsDir ( ) {
ctx . Data [ "Err_TreePath" ] = true
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.directory_is_a_file" , part ) , tplUploadFile , & form )
2016-08-30 05:07:50 -07:00
return
}
}
message := strings . TrimSpace ( form . CommitSummary )
if len ( message ) == 0 {
message = ctx . Tr ( "repo.editor.upload_files_to_dir" , form . TreePath )
}
form . CommitMessage = strings . TrimSpace ( form . CommitMessage )
if len ( form . CommitMessage ) > 0 {
message += "\n\n" + form . CommitMessage
}
2019-04-17 10:06:35 -06:00
if err := repofiles . UploadRepoFiles ( ctx . Repo . Repository , ctx . User , & repofiles . UploadRepoFileOptions {
2016-08-30 05:07:50 -07:00
LastCommitID : ctx . Repo . CommitID ,
OldBranch : oldBranchName ,
NewBranch : branchName ,
TreePath : form . TreePath ,
Message : message ,
Files : form . Files ,
} ) ; err != nil {
ctx . Data [ "Err_TreePath" ] = true
2016-11-24 15:04:31 +08:00
ctx . RenderWithErr ( ctx . Tr ( "repo.editor.unable_to_upload_files" , form . TreePath , err ) , tplUploadFile , & form )
2016-08-30 05:07:50 -07:00
return
}
2019-04-17 01:07:13 +01:00
ctx . Redirect ( ctx . Repo . RepoLink + "/src/branch/" + util . PathEscapeSegments ( branchName ) + "/" + util . PathEscapeSegments ( form . TreePath ) )
2016-08-30 05:07:50 -07:00
}
2018-12-21 10:32:11 +08:00
func cleanUploadFileName ( name string ) string {
2019-02-12 13:07:31 +00:00
// Rebase the filename
name = strings . Trim ( path . Clean ( "/" + name ) , " /" )
// Git disallows any filenames to have a .git directory in them.
for _ , part := range strings . Split ( name , "/" ) {
if strings . ToLower ( part ) == ".git" {
return ""
}
2018-12-21 10:32:11 +08:00
}
return name
}
2016-11-24 15:04:31 +08:00
// UploadFileToServer upload file to server file dir not git
2016-08-30 05:07:50 -07:00
func UploadFileToServer ( ctx * context . Context ) {
file , header , err := ctx . Req . FormFile ( "file" )
if err != nil {
ctx . Error ( 500 , fmt . Sprintf ( "FormFile: %v" , err ) )
return
}
defer file . Close ( )
buf := make ( [ ] byte , 1024 )
n , _ := file . Read ( buf )
if n > 0 {
buf = buf [ : n ]
}
fileType := http . DetectContentType ( buf )
if len ( setting . Repository . Upload . AllowedTypes ) > 0 {
allowed := false
for _ , t := range setting . Repository . Upload . AllowedTypes {
t := strings . Trim ( t , " " )
if t == "*/*" || t == fileType {
allowed = true
break
}
}
if ! allowed {
ctx . Error ( 400 , ErrFileTypeForbidden . Error ( ) )
return
}
}
2018-12-21 10:32:11 +08:00
name := cleanUploadFileName ( header . Filename )
if len ( name ) == 0 {
ctx . Error ( 500 , "Upload file name is invalid" )
return
}
upload , err := models . NewUpload ( name , buf , file )
2016-08-30 05:07:50 -07:00
if err != nil {
ctx . Error ( 500 , fmt . Sprintf ( "NewUpload: %v" , err ) )
return
}
log . Trace ( "New file uploaded: %s" , upload . UUID )
ctx . JSON ( 200 , map [ string ] string {
"uuid" : upload . UUID ,
} )
}
2016-11-24 15:04:31 +08:00
// RemoveUploadFileFromServer remove file from server file dir
2016-08-30 05:07:50 -07:00
func RemoveUploadFileFromServer ( ctx * context . Context , form auth . RemoveUploadFileForm ) {
if len ( form . File ) == 0 {
ctx . Status ( 204 )
return
}
if err := models . DeleteUploadByUUID ( form . File ) ; err != nil {
ctx . Error ( 500 , fmt . Sprintf ( "DeleteUploadByUUID: %v" , err ) )
return
}
log . Trace ( "Upload file removed: %s" , form . File )
ctx . Status ( 204 )
}