mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-08 07:10:56 +03:00
web UI: add support for upload, create dirs, rename, delete
This commit is contained in:
@@ -697,11 +697,53 @@ func (u *User) isFilePatternAllowed(virtualPath string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CanManagePublicKeys return true if this user is allowed to manage public keys
|
// CanManagePublicKeys return true if this user is allowed to manage public keys
|
||||||
// from the web client
|
// from the web client. Used in web client UI
|
||||||
func (u *User) CanManagePublicKeys() bool {
|
func (u *User) CanManagePublicKeys() bool {
|
||||||
return !util.IsStringInSlice(sdk.WebClientPubKeyChangeDisabled, u.Filters.WebClient)
|
return !util.IsStringInSlice(sdk.WebClientPubKeyChangeDisabled, u.Filters.WebClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanAddFilesFromWeb returns true if the client can add files from the web UI.
|
||||||
|
// The specified target is the directory where the files must be uploaded
|
||||||
|
func (u *User) CanAddFilesFromWeb(target string) bool {
|
||||||
|
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.HasPerm(PermUpload, target) || u.HasPerm(PermOverwrite, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanAddDirsFromWeb returns true if the client can add directories from the web UI.
|
||||||
|
// The specified target is the directory where the new directory must be created
|
||||||
|
func (u *User) CanAddDirsFromWeb(target string) bool {
|
||||||
|
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.HasPerm(PermCreateDirs, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanRenameFromWeb returns true if the client can rename objects from the web UI.
|
||||||
|
// The specified src and dest are the source and target directories for the rename.
|
||||||
|
func (u *User) CanRenameFromWeb(src, dest string) bool {
|
||||||
|
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if u.HasPerm(PermRename, src) && u.HasPerm(PermRename, dest) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !u.HasPerm(PermDelete, src) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.HasPerm(PermUpload, dest) || u.HasPerm(PermCreateDirs, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanDeleteFromWeb returns true if the client can delete objects from the web UI.
|
||||||
|
// The specified target is the parent directory for the object to delete
|
||||||
|
func (u *User) CanDeleteFromWeb(target string) bool {
|
||||||
|
if util.IsStringInSlice(sdk.WebClientWriteDisabled, u.Filters.WebClient) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.HasPerm(PermDelete, target)
|
||||||
|
}
|
||||||
|
|
||||||
// GetSignature returns a signature for this admin.
|
// GetSignature returns a signature for this admin.
|
||||||
// It could change after an update
|
// It could change after an update
|
||||||
func (u *User) GetSignature() string {
|
func (u *User) GetSignature() string {
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ const (
|
|||||||
userPwdPath = "/api/v2/user/changepwd"
|
userPwdPath = "/api/v2/user/changepwd"
|
||||||
userPublicKeysPath = "/api/v2/user/publickeys"
|
userPublicKeysPath = "/api/v2/user/publickeys"
|
||||||
userFolderPath = "/api/v2/user/folder"
|
userFolderPath = "/api/v2/user/folder"
|
||||||
|
userDirsPath = "/api/v2/user/dirs"
|
||||||
userFilePath = "/api/v2/user/file"
|
userFilePath = "/api/v2/user/file"
|
||||||
|
userFilesPath = "/api/v2/user/files"
|
||||||
userStreamZipPath = "/api/v2/user/streamzip"
|
userStreamZipPath = "/api/v2/user/streamzip"
|
||||||
healthzPath = "/healthz"
|
healthzPath = "/healthz"
|
||||||
webRootPathDefault = "/"
|
webRootPathDefault = "/"
|
||||||
@@ -87,7 +89,7 @@ const (
|
|||||||
webDefenderHostsPathDefault = "/web/admin/defender/hosts"
|
webDefenderHostsPathDefault = "/web/admin/defender/hosts"
|
||||||
webClientLoginPathDefault = "/web/client/login"
|
webClientLoginPathDefault = "/web/client/login"
|
||||||
webClientFilesPathDefault = "/web/client/files"
|
webClientFilesPathDefault = "/web/client/files"
|
||||||
webClientDirContentsPathDefault = "/web/client/listdir"
|
webClientDirsPathDefault = "/web/client/dirs"
|
||||||
webClientDownloadZipPathDefault = "/web/client/downloadzip"
|
webClientDownloadZipPathDefault = "/web/client/downloadzip"
|
||||||
webClientCredentialsPathDefault = "/web/client/credentials"
|
webClientCredentialsPathDefault = "/web/client/credentials"
|
||||||
webChangeClientPwdPathDefault = "/web/client/changepwd"
|
webChangeClientPwdPathDefault = "/web/client/changepwd"
|
||||||
@@ -136,7 +138,7 @@ var (
|
|||||||
webDefenderHostsPath string
|
webDefenderHostsPath string
|
||||||
webClientLoginPath string
|
webClientLoginPath string
|
||||||
webClientFilesPath string
|
webClientFilesPath string
|
||||||
webClientDirContentsPath string
|
webClientDirsPath string
|
||||||
webClientDownloadZipPath string
|
webClientDownloadZipPath string
|
||||||
webClientCredentialsPath string
|
webClientCredentialsPath string
|
||||||
webChangeClientPwdPath string
|
webChangeClientPwdPath string
|
||||||
@@ -444,7 +446,7 @@ func updateWebClientURLs(baseURL string) {
|
|||||||
webBaseClientPath = path.Join(baseURL, webBasePathClientDefault)
|
webBaseClientPath = path.Join(baseURL, webBasePathClientDefault)
|
||||||
webClientLoginPath = path.Join(baseURL, webClientLoginPathDefault)
|
webClientLoginPath = path.Join(baseURL, webClientLoginPathDefault)
|
||||||
webClientFilesPath = path.Join(baseURL, webClientFilesPathDefault)
|
webClientFilesPath = path.Join(baseURL, webClientFilesPathDefault)
|
||||||
webClientDirContentsPath = path.Join(baseURL, webClientDirContentsPathDefault)
|
webClientDirsPath = path.Join(baseURL, webClientDirsPathDefault)
|
||||||
webClientDownloadZipPath = path.Join(baseURL, webClientDownloadZipPathDefault)
|
webClientDownloadZipPath = path.Join(baseURL, webClientDownloadZipPathDefault)
|
||||||
webClientCredentialsPath = path.Join(baseURL, webClientCredentialsPathDefault)
|
webClientCredentialsPath = path.Join(baseURL, webClientCredentialsPathDefault)
|
||||||
webChangeClientPwdPath = path.Join(baseURL, webChangeClientPwdPathDefault)
|
webChangeClientPwdPath = path.Join(baseURL, webChangeClientPwdPathDefault)
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ const (
|
|||||||
logoutPath = "/api/v2/logout"
|
logoutPath = "/api/v2/logout"
|
||||||
userPwdPath = "/api/v2/user/changepwd"
|
userPwdPath = "/api/v2/user/changepwd"
|
||||||
userPublicKeysPath = "/api/v2/user/publickeys"
|
userPublicKeysPath = "/api/v2/user/publickeys"
|
||||||
userFolderPath = "/api/v2/user/folder"
|
userDirsPath = "/api/v2/user/dirs"
|
||||||
userFilePath = "/api/v2/user/file"
|
userFilesPath = "/api/v2/user/files"
|
||||||
userStreamZipPath = "/api/v2/user/streamzip"
|
userStreamZipPath = "/api/v2/user/streamzip"
|
||||||
healthzPath = "/healthz"
|
healthzPath = "/healthz"
|
||||||
webBasePath = "/web"
|
webBasePath = "/web"
|
||||||
@@ -104,7 +104,7 @@ const (
|
|||||||
webBasePathClient = "/web/client"
|
webBasePathClient = "/web/client"
|
||||||
webClientLoginPath = "/web/client/login"
|
webClientLoginPath = "/web/client/login"
|
||||||
webClientFilesPath = "/web/client/files"
|
webClientFilesPath = "/web/client/files"
|
||||||
webClientDirContentsPath = "/web/client/listdir"
|
webClientDirsPath = "/web/client/dirs"
|
||||||
webClientDownloadZipPath = "/web/client/downloadzip"
|
webClientDownloadZipPath = "/web/client/downloadzip"
|
||||||
webClientCredentialsPath = "/web/client/credentials"
|
webClientCredentialsPath = "/web/client/credentials"
|
||||||
webChangeClientPwdPath = "/web/client/changepwd"
|
webChangeClientPwdPath = "/web/client/changepwd"
|
||||||
@@ -4882,14 +4882,14 @@ func TestWebAPILoginMock(t *testing.T) {
|
|||||||
webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
|
webToken, err := getJWTWebClientTokenFromTestServer(defaultUsername, defaultPassword)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// a web token is not valid for API usage
|
// a web token is not valid for API usage
|
||||||
req, err := http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webToken)
|
setBearerForReq(req, webToken)
|
||||||
rr := executeRequest(req)
|
rr := executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusUnauthorized, rr)
|
checkResponseCode(t, http.StatusUnauthorized, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Your token audience is not valid")
|
assert.Contains(t, rr.Body.String(), "Your token audience is not valid")
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath+"/?path=%2F", nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath+"/?path=%2F", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, apiToken)
|
setBearerForReq(req, apiToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -4977,7 +4977,7 @@ func TestWebClientLoginMock(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath, nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath, nil)
|
||||||
setJWTCookieForReq(req, webToken)
|
setJWTCookieForReq(req, webToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
@@ -4989,13 +4989,13 @@ func TestWebClientLoginMock(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
setBearerForReq(req, apiUserToken)
|
setBearerForReq(req, apiUserToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
assert.Contains(t, rr.Body.String(), "Unable to retrieve your user")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath, nil)
|
||||||
setBearerForReq(req, apiUserToken)
|
setBearerForReq(req, apiUserToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
@@ -5468,7 +5468,7 @@ func TestPreDownloadHook(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5484,7 +5484,7 @@ func TestPreDownloadHook(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "permission denied")
|
assert.Contains(t, rr.Body.String(), "permission denied")
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5530,7 +5530,7 @@ func TestPreUploadHook(t *testing.T) {
|
|||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -5541,7 +5541,7 @@ func TestPreUploadHook(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -5586,7 +5586,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath+"?path="+testDir, nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path="+testDir, nil)
|
||||||
setJWTCookieForReq(req, webToken)
|
setJWTCookieForReq(req, webToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
@@ -5595,7 +5595,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, dirContents, 1)
|
assert.Len(t, dirContents, 1)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath+"?path="+testDir, nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
@@ -5636,7 +5636,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusInternalServerError, rr)
|
checkResponseCode(t, http.StatusInternalServerError, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Unable to get files list")
|
assert.Contains(t, rr.Body.String(), "Unable to get files list")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath+"?path=/", nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil)
|
||||||
setJWTCookieForReq(req, webToken)
|
setJWTCookieForReq(req, webToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
@@ -5645,7 +5645,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, dirContents, len(extensions)+1)
|
assert.Len(t, dirContents, len(extensions)+1)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath+"?path=/", nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=/", nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
@@ -5654,13 +5654,13 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, dirEntries, len(extensions)+1)
|
assert.Len(t, dirEntries, len(extensions)+1)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath+"?path=/missing", nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/missing", nil)
|
||||||
setJWTCookieForReq(req, webToken)
|
setJWTCookieForReq(req, webToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Unable to get directory contents")
|
assert.Contains(t, rr.Body.String(), "Unable to get directory contents")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath+"?path=missing", nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path=missing", nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
@@ -5672,25 +5672,25 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
assert.Equal(t, testFileContents, rr.Body.Bytes())
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path=", nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=", nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusBadRequest, rr)
|
checkResponseCode(t, http.StatusBadRequest, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "Please set the path to a valid file")
|
assert.Contains(t, rr.Body.String(), "Please set the path to a valid file")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path="+testDir, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testDir, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusBadRequest, rr)
|
checkResponseCode(t, http.StatusBadRequest, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "is a directory")
|
assert.Contains(t, rr.Body.String(), "is a directory")
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path=notafile", nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path=notafile", nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
@@ -5703,7 +5703,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusPartialContent, rr)
|
checkResponseCode(t, http.StatusPartialContent, rr)
|
||||||
assert.Equal(t, testFileContents[2:], rr.Body.Bytes())
|
assert.Equal(t, testFileContents[2:], rr.Body.Bytes())
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
req.Header.Set("Range", "bytes=2-")
|
req.Header.Set("Range", "bytes=2-")
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5729,7 +5729,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr)
|
checkResponseCode(t, http.StatusRequestedRangeNotSatisfiable, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
req.Header.Set("Range", "bytes=2b-")
|
req.Header.Set("Range", "bytes=2b-")
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5767,7 +5767,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusPreconditionFailed, rr)
|
checkResponseCode(t, http.StatusPreconditionFailed, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodHead, userFilePath+"?path="+testFileName, nil)
|
req, _ = http.NewRequest(http.MethodHead, userFilesPath+"?path="+testFileName, nil)
|
||||||
req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
|
req.Header.Set("If-Unmodified-Since", time.Now().UTC().Add(-120*time.Second).Format(http.TimeFormat))
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5788,17 +5788,17 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath+"?path=/", nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath+"?path=/", nil)
|
||||||
setJWTCookieForReq(req, webToken)
|
setJWTCookieForReq(req, webToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFilePath+"?path="+testFileName, nil)
|
req, _ = http.NewRequest(http.MethodGet, userFilesPath+"?path="+testFileName, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath+"?path="+testDir, nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
@@ -5826,7 +5826,7 @@ func TestWebGetFiles(t *testing.T) {
|
|||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, _ = http.NewRequest(http.MethodGet, userFolderPath+"?path="+testDir, nil)
|
req, _ = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
@@ -5844,7 +5844,7 @@ func TestWebDirsAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
testDir := "testdir"
|
testDir := "testdir"
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err := http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr := executeRequest(req)
|
rr := executeRequest(req)
|
||||||
@@ -5855,25 +5855,25 @@ func TestWebDirsAPI(t *testing.T) {
|
|||||||
assert.Len(t, contents, 0)
|
assert.Len(t, contents, 0)
|
||||||
|
|
||||||
// rename a missing folder
|
// rename a missing folder
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFolderPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
// delete a missing folder
|
// delete a missing folder
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
// create a dir
|
// create a dir
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusCreated, rr)
|
checkResponseCode(t, http.StatusCreated, rr)
|
||||||
// check the dir was created
|
// check the dir was created
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5885,19 +5885,19 @@ func TestWebDirsAPI(t *testing.T) {
|
|||||||
assert.Equal(t, testDir, contents[0]["name"])
|
assert.Equal(t, testDir, contents[0]["name"])
|
||||||
}
|
}
|
||||||
// rename the dir
|
// rename the dir
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFolderPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
// delete the dir
|
// delete the dir
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFolderPath+"?path="+testDir+"new", nil)
|
req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
// the root dir cannot be created
|
// the root dir cannot be created
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5907,7 +5907,7 @@ func TestWebDirsAPI(t *testing.T) {
|
|||||||
user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// the user has no more the permission to create the directory
|
// the user has no more the permission to create the directory
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5919,19 +5919,19 @@ func TestWebDirsAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// the user is deleted, any API call should fail
|
// the user is deleted, any API call should fail
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFolderPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir+"new", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFolderPath+"?path="+testDir+"new", nil)
|
req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path="+testDir+"new", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5958,7 +5958,7 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr := executeRequest(req)
|
rr := executeRequest(req)
|
||||||
@@ -5967,14 +5967,14 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// set the proper content type
|
// set the proper content type
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusCreated, rr)
|
checkResponseCode(t, http.StatusCreated, rr)
|
||||||
// check we have 2 files
|
// check we have 2 files
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -5986,13 +5986,13 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
// overwrite the existing files
|
// overwrite the existing files
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusCreated, rr)
|
checkResponseCode(t, http.StatusCreated, rr)
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6003,20 +6003,20 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
assert.Len(t, contents, 2)
|
assert.Len(t, contents, 2)
|
||||||
// now create a dir and upload to that dir
|
// now create a dir and upload to that dir
|
||||||
testDir := "tdir"
|
testDir := "tdir"
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusCreated, rr)
|
checkResponseCode(t, http.StatusCreated, rr)
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path="+testDir, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path="+testDir, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusCreated, rr)
|
checkResponseCode(t, http.StatusCreated, rr)
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6025,7 +6025,7 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
err = json.NewDecoder(rr.Body).Decode(&contents)
|
err = json.NewDecoder(rr.Body).Decode(&contents)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, contents, 3)
|
assert.Len(t, contents, 3)
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath+"?path="+testDir, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath+"?path="+testDir, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6035,31 +6035,31 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, contents, 2)
|
assert.Len(t, contents, 2)
|
||||||
// rename a file
|
// rename a file
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFilePath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
// rename a missing file
|
// rename a missing file
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFilePath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
// delete a file
|
// delete a file
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file2.txt", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
// delete a missing file
|
// delete a missing file
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file2.txt", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
// delete a directory
|
// delete a directory
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=tdir", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=tdir", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6070,7 +6070,7 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = os.Symlink(extPath, filepath.Join(user.GetHomeDir(), "file"))
|
err = os.Symlink(extPath, filepath.Join(user.GetHomeDir(), "file"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6083,14 +6083,14 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path=tdir", reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=tdir", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=%2Ftdir%2Ffile1.txt", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=%2Ftdir%2Ffile1.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6103,20 +6103,20 @@ func TestWebFilesAPI(t *testing.T) {
|
|||||||
// the user is deleted, any API call should fail
|
// the user is deleted, any API call should fail
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFilePath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=%2Ftdir%2Ffile3.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file2.txt", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6155,7 +6155,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// zip file are not allowed within sub2
|
// zip file are not allowed within sub2
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath+"?path=sub2", reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6165,7 +6165,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// we have no upload permissions within sub1
|
// we have no upload permissions within sub1
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path=sub1", reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub1", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6173,7 +6173,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
// create a dir and try to overwrite it with a file
|
// create a dir and try to overwrite it with a file
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path=file.zip", nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=file.zip", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6181,7 +6181,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6191,14 +6191,14 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
// try to upload to a missing parent directory
|
// try to upload to a missing parent directory
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path=missingdir", reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=missingdir", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFolderPath+"?path=file.zip", nil)
|
req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=file.zip", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6206,7 +6206,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
// upload will work now
|
// upload will work now
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6215,7 +6215,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
// overwrite the file
|
// overwrite the file
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6226,7 +6226,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6234,7 +6234,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
if runtime.GOOS != osWindows {
|
if runtime.GOOS != osWindows {
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file.zip", reader)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.zip", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6246,7 +6246,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6268,7 +6268,7 @@ func TestWebUploadErrors(t *testing.T) {
|
|||||||
reader = bytes.NewReader(body.Bytes())
|
reader = bytes.NewReader(body.Bytes())
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path=sub2", reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=sub2", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6315,7 +6315,7 @@ func TestWebAPIVFolder(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath+"?path=vdir", reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6332,7 +6332,7 @@ func TestWebAPIVFolder(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath+"?path=vdir", reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath+"?path=vdir", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6375,56 +6375,56 @@ func TestWebAPIWritePermission(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr := executeRequest(req)
|
rr := executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFilePath+"?path=a&target=b", nil)
|
req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=a&target=b", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=a", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=a", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodGet, userFilePath+"?path=a.txt", nil)
|
req, err = http.NewRequest(http.MethodGet, userFilesPath+"?path=a.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusNotFound, rr)
|
checkResponseCode(t, http.StatusNotFound, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodGet, userFolderPath, nil)
|
req, err = http.NewRequest(http.MethodGet, userDirsPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusOK, rr)
|
checkResponseCode(t, http.StatusOK, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodPost, userFolderPath+"?path=dir", nil)
|
req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path=dir", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodPatch, userFolderPath+"?path=dir&target=dir1", nil)
|
req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path=dir&target=dir1", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
checkResponseCode(t, http.StatusForbidden, rr)
|
checkResponseCode(t, http.StatusForbidden, rr)
|
||||||
|
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFolderPath+"?path=dir", nil)
|
req, err = http.NewRequest(http.MethodDelete, userDirsPath+"?path=dir", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6457,7 +6457,7 @@ func TestWebAPICryptFs(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6466,7 +6466,7 @@ func TestWebAPICryptFs(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6503,7 +6503,7 @@ func TestWebUploadSFTP(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6523,7 +6523,7 @@ func TestWebUploadSFTP(t *testing.T) {
|
|||||||
// we are now overquota on overwrite
|
// we are now overquota on overwrite
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6531,7 +6531,7 @@ func TestWebUploadSFTP(t *testing.T) {
|
|||||||
checkResponseCode(t, http.StatusInternalServerError, rr)
|
checkResponseCode(t, http.StatusInternalServerError, rr)
|
||||||
assert.Contains(t, rr.Body.String(), "denying write due to space limit")
|
assert.Contains(t, rr.Body.String(), "denying write due to space limit")
|
||||||
// delete the file
|
// delete the file
|
||||||
req, err = http.NewRequest(http.MethodDelete, userFilePath+"?path=file.txt", nil)
|
req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file.txt", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
rr = executeRequest(req)
|
rr = executeRequest(req)
|
||||||
@@ -6539,7 +6539,7 @@ func TestWebUploadSFTP(t *testing.T) {
|
|||||||
|
|
||||||
_, err = reader.Seek(0, io.SeekStart)
|
_, err = reader.Seek(0, io.SeekStart)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err = http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
@@ -6563,7 +6563,7 @@ func TestWebUploadMultipartFormReadError(t *testing.T) {
|
|||||||
webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
|
webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, nil)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
mpartForm := &multipart.Form{
|
mpartForm := &multipart.Form{
|
||||||
@@ -6735,7 +6735,7 @@ func TestClientUserClose(t *testing.T) {
|
|||||||
err = writer.Close()
|
err = writer.Close()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
reader := bytes.NewReader(body.Bytes())
|
reader := bytes.NewReader(body.Bytes())
|
||||||
req, err := http.NewRequest(http.MethodPost, userFilePath, reader)
|
req, err := http.NewRequest(http.MethodPost, userFilesPath, reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
setBearerForReq(req, webAPIToken)
|
setBearerForReq(req, webAPIToken)
|
||||||
|
|||||||
@@ -1580,7 +1580,7 @@ func TestGetFilesInvalidClaims(t *testing.T) {
|
|||||||
assert.Contains(t, rr.Body.String(), "Invalid token claims")
|
assert.Contains(t, rr.Body.String(), "Invalid token claims")
|
||||||
|
|
||||||
rr = httptest.NewRecorder()
|
rr = httptest.NewRecorder()
|
||||||
req, _ = http.NewRequest(http.MethodGet, webClientDirContentsPath, nil)
|
req, _ = http.NewRequest(http.MethodGet, webClientDirsPath, nil)
|
||||||
req.Header.Set("Cookie", fmt.Sprintf("jwt=%v", token["access_token"]))
|
req.Header.Set("Cookie", fmt.Sprintf("jwt=%v", token["access_token"]))
|
||||||
handleClientGetDirContents(rr, req)
|
handleClientGetDirContents(rr, req)
|
||||||
assert.Equal(t, http.StatusForbidden, rr.Code)
|
assert.Equal(t, http.StatusForbidden, rr.Code)
|
||||||
|
|||||||
@@ -1763,8 +1763,41 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- users API
|
- users API
|
||||||
summary: Read folders contents
|
summary: Read folders contents
|
||||||
description: Returns the contents of the specified folder for the logged in user
|
description: Returns the contents of the specified folder for the logged in user. Please use '/user/dirs' instead
|
||||||
operationId: get_user_folder_contents
|
operationId: get_user_folder_contents
|
||||||
|
deprecated: true
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: path
|
||||||
|
description: Path to the folder to read. It must be URL encoded, for example the path "my dir/àdir" must be sent as "my%20dir%2F%C3%A0dir". If empty or missing the root folder is assumed
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/DirEntry'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/DefaultResponse'
|
||||||
|
/user/dirs:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- users API
|
||||||
|
summary: Read directory contents
|
||||||
|
description: Returns the contents of the specified directory for the logged in user
|
||||||
|
operationId: get_user_dir_contents
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: path
|
name: path
|
||||||
@@ -1795,7 +1828,7 @@ paths:
|
|||||||
- users API
|
- users API
|
||||||
summary: Create a directory
|
summary: Create a directory
|
||||||
description: Create a directory for the logged in user
|
description: Create a directory for the logged in user
|
||||||
operationId: create_user_folder
|
operationId: create_user_dir
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: path
|
name: path
|
||||||
@@ -1827,7 +1860,7 @@ paths:
|
|||||||
- users API
|
- users API
|
||||||
summary: Rename a directory
|
summary: Rename a directory
|
||||||
description: Rename a directory for the logged in user. The rename is allowed for empty directory or for non empty, local directories, with no virtual folders inside
|
description: Rename a directory for the logged in user. The rename is allowed for empty directory or for non empty, local directories, with no virtual folders inside
|
||||||
operationId: rename_user_folder
|
operationId: rename_user_dir
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: path
|
name: path
|
||||||
@@ -1865,7 +1898,7 @@ paths:
|
|||||||
- users API
|
- users API
|
||||||
summary: Delete a directory
|
summary: Delete a directory
|
||||||
description: Delete a directory for the logged in user. Only empty directories can be deleted
|
description: Delete a directory for the logged in user. Only empty directories can be deleted
|
||||||
operationId: delete_user_folder
|
operationId: delete_user_dir
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: path
|
name: path
|
||||||
@@ -1897,8 +1930,48 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- users API
|
- users API
|
||||||
summary: Download a single file
|
summary: Download a single file
|
||||||
description: Returns the file contents as response body
|
description: Returns the file contents as response body. Please use '/user/files' instead
|
||||||
operationId: get_user_file
|
operationId: get_user_file
|
||||||
|
deprecated: true
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: path
|
||||||
|
required: true
|
||||||
|
description: Path to the file to download. It must be URL encoded, for example the path "my dir/àdir/file.txt" must be sent as "my%20dir%2F%C3%A0dir%2Ffile.txt"
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: successful operation
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
'206':
|
||||||
|
description: successful operation
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/responses/Forbidden'
|
||||||
|
'500':
|
||||||
|
$ref: '#/components/responses/InternalServerError'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/DefaultResponse'
|
||||||
|
/user/files:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- users API
|
||||||
|
summary: Download a single file
|
||||||
|
description: Returns the file contents as response body
|
||||||
|
operationId: download_user_file
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: path
|
name: path
|
||||||
|
|||||||
@@ -631,14 +631,18 @@ func (s *httpdServer) initializeRouter() {
|
|||||||
router.Put(userPwdPath, changeUserPassword)
|
router.Put(userPwdPath, changeUserPassword)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).Get(userPublicKeysPath, getUserPublicKeys)
|
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).Get(userPublicKeysPath, getUserPublicKeys)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).Put(userPublicKeysPath, setUserPublicKeys)
|
router.With(checkHTTPUserPerm(sdk.WebClientPubKeyChangeDisabled)).Put(userPublicKeysPath, setUserPublicKeys)
|
||||||
router.Get(userFolderPath, readUserFolder)
|
// compatibility layer to remove in v2.3
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userFolderPath, createUserDir)
|
router.With(compressor.Handler).Get(userFolderPath, readUserFolder)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userFolderPath, renameUserDir)
|
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userFolderPath, deleteUserDir)
|
|
||||||
router.Get(userFilePath, getUserFile)
|
router.Get(userFilePath, getUserFile)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userFilePath, uploadUserFiles)
|
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userFilePath, renameUserFile)
|
router.With(compressor.Handler).Get(userDirsPath, readUserFolder)
|
||||||
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userFilePath, deleteUserFile)
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userDirsPath, createUserDir)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userDirsPath, renameUserDir)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userDirsPath, deleteUserDir)
|
||||||
|
router.Get(userFilesPath, getUserFile)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Post(userFilesPath, uploadUserFiles)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Patch(userFilesPath, renameUserFile)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled)).Delete(userFilesPath, deleteUserFile)
|
||||||
router.Post(userStreamZipPath, getUserFilesAsZipStream)
|
router.Post(userStreamZipPath, getUserFilesAsZipStream)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -677,7 +681,19 @@ func (s *httpdServer) initializeRouter() {
|
|||||||
|
|
||||||
router.Get(webClientLogoutPath, handleWebClientLogout)
|
router.Get(webClientLogoutPath, handleWebClientLogout)
|
||||||
router.With(s.refreshCookie).Get(webClientFilesPath, handleClientGetFiles)
|
router.With(s.refreshCookie).Get(webClientFilesPath, handleClientGetFiles)
|
||||||
router.With(compressor.Handler, s.refreshCookie).Get(webClientDirContentsPath, handleClientGetDirContents)
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Post(webClientFilesPath, uploadUserFiles)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Patch(webClientFilesPath, renameUserFile)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Delete(webClientFilesPath, deleteUserFile)
|
||||||
|
router.With(compressor.Handler, s.refreshCookie).Get(webClientDirsPath, handleClientGetDirContents)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Post(webClientDirsPath, createUserDir)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Patch(webClientDirsPath, renameUserDir)
|
||||||
|
router.With(checkHTTPUserPerm(sdk.WebClientWriteDisabled), verifyCSRFHeader).
|
||||||
|
Delete(webClientDirsPath, deleteUserDir)
|
||||||
router.With(s.refreshCookie).Get(webClientDownloadZipPath, handleWebClientDownloadZip)
|
router.With(s.refreshCookie).Get(webClientDownloadZipPath, handleWebClientDownloadZip)
|
||||||
router.With(s.refreshCookie).Get(webClientCredentialsPath, handleClientGetCredentials)
|
router.With(s.refreshCookie).Get(webClientCredentialsPath, handleClientGetCredentials)
|
||||||
router.Post(webChangeClientPwdPath, handleWebClientChangePwdPost)
|
router.Post(webChangeClientPwdPath, handleWebClientChangePwdPost)
|
||||||
|
|||||||
@@ -73,11 +73,15 @@ type dirMapping struct {
|
|||||||
|
|
||||||
type filesPage struct {
|
type filesPage struct {
|
||||||
baseClientPage
|
baseClientPage
|
||||||
CurrentDir string
|
CurrentDir string
|
||||||
ReadDirURL string
|
DirsURL string
|
||||||
DownloadURL string
|
DownloadURL string
|
||||||
Error string
|
CanAddFiles bool
|
||||||
Paths []dirMapping
|
CanCreateDirs bool
|
||||||
|
CanRename bool
|
||||||
|
CanDelete bool
|
||||||
|
Error string
|
||||||
|
Paths []dirMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientMessagePage struct {
|
type clientMessagePage struct {
|
||||||
@@ -207,13 +211,17 @@ func renderClientNotFoundPage(w http.ResponseWriter, r *http.Request, err error)
|
|||||||
renderClientMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
|
renderClientMessagePage(w, r, page404Title, page404Body, http.StatusNotFound, err, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderFilesPage(w http.ResponseWriter, r *http.Request, dirName, error string) {
|
func renderFilesPage(w http.ResponseWriter, r *http.Request, dirName, error string, user dataprovider.User) {
|
||||||
data := filesPage{
|
data := filesPage{
|
||||||
baseClientPage: getBaseClientPageData(pageClientFilesTitle, webClientFilesPath, r),
|
baseClientPage: getBaseClientPageData(pageClientFilesTitle, webClientFilesPath, r),
|
||||||
Error: error,
|
Error: error,
|
||||||
CurrentDir: url.QueryEscape(dirName),
|
CurrentDir: url.QueryEscape(dirName),
|
||||||
DownloadURL: webClientDownloadZipPath,
|
DownloadURL: webClientDownloadZipPath,
|
||||||
ReadDirURL: webClientDirContentsPath,
|
DirsURL: webClientDirsPath,
|
||||||
|
CanAddFiles: user.CanAddFilesFromWeb(dirName),
|
||||||
|
CanCreateDirs: user.CanAddDirsFromWeb(dirName),
|
||||||
|
CanRename: user.CanRenameFromWeb(dirName, dirName),
|
||||||
|
CanDelete: user.CanDeleteFromWeb(dirName),
|
||||||
}
|
}
|
||||||
paths := []dirMapping{}
|
paths := []dirMapping{}
|
||||||
if dirName != "/" {
|
if dirName != "/" {
|
||||||
@@ -359,6 +367,7 @@ func handleClientGetDirContents(w http.ResponseWriter, r *http.Request) {
|
|||||||
res["size"] = util.ByteCountIEC(info.Size())
|
res["size"] = util.ByteCountIEC(info.Size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
res["type_name"] = fmt.Sprintf("%v_%v", res["type"], info.Name())
|
||||||
res["name"] = info.Name()
|
res["name"] = info.Name()
|
||||||
res["last_modified"] = getFileObjectModTime(info.ModTime())
|
res["last_modified"] = getFileObjectModTime(info.ModTime())
|
||||||
res["url"] = getFileObjectURL(name, info.Name())
|
res["url"] = getFileObjectURL(name, info.Name())
|
||||||
@@ -406,11 +415,11 @@ func handleClientGetFiles(w http.ResponseWriter, r *http.Request) {
|
|||||||
info, err = connection.Stat(name, 0)
|
info, err = connection.Stat(name, 0)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renderFilesPage(w, r, path.Dir(name), fmt.Sprintf("unable to stat file %#v: %v", name, err))
|
renderFilesPage(w, r, path.Dir(name), fmt.Sprintf("unable to stat file %#v: %v", name, err), user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
renderFilesPage(w, r, name, "")
|
renderFilesPage(w, r, name, "", user)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if status, err := downloadFile(w, r, connection, name, info); err != nil && status != 0 {
|
if status, err := downloadFile(w, r, connection, name, info); err != nil && status != 0 {
|
||||||
@@ -419,7 +428,7 @@ func handleClientGetFiles(w http.ResponseWriter, r *http.Request) {
|
|||||||
renderClientMessagePage(w, r, http.StatusText(status), "", status, err, "")
|
renderClientMessagePage(w, r, http.StatusText(status), "", status, err, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderFilesPage(w, r, path.Dir(name), err.Error())
|
renderFilesPage(w, r, path.Dir(name), err.Error(), user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
Confirmation required
|
Confirmation required
|
||||||
</h5>
|
</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Do you want to delete the selected admin?</div>
|
<div class="modal-body">Do you want to delete the selected admin?</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
|
|
||||||
<title>SFTPGo - {{template "title" .}}</title>
|
<title>SFTPGo Admin - {{template "title" .}}</title>
|
||||||
|
|
||||||
<link rel="shortcut icon" href="{{.StaticURL}}/favicon.ico" />
|
<link rel="shortcut icon" href="{{.StaticURL}}/favicon.ico" />
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalLabel">Ready to Leave?</h5>
|
<h5 class="modal-title" id="modalLabel">Ready to Leave?</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
|
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
Confirmation required
|
Confirmation required
|
||||||
</h5>
|
</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Do you want to close the selected connection?</div>
|
<div class="modal-body">Do you want to close the selected connection?</div>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
Confirmation required
|
Confirmation required
|
||||||
</h5>
|
</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Do you want to remoce the selected blocklist entry?</div>
|
<div class="modal-body">Do you want to remoce the selected blocklist entry?</div>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
Confirmation required
|
Confirmation required
|
||||||
</h5>
|
</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Do you want to delete the selected virtual folder and any users mapping?</div>
|
<div class="modal-body">Do you want to delete the selected virtual folder and any users mapping?</div>
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h1 class="h4 text-gray-900 mb-4">SFTPGo - {{.Version}}</h1>
|
<h1 class="h4 text-gray-900 mb-4">SFTPGo Admin - {{.Version}}</h1>
|
||||||
</div>
|
</div>
|
||||||
{{if .Error}}
|
{{if .Error}}
|
||||||
<div class="card mb-4 border-left-warning">
|
<div class="card mb-4 border-left-warning">
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
Confirmation required
|
Confirmation required
|
||||||
</h5>
|
</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Do you want to delete the selected user?</div>
|
<div class="modal-body">Do you want to delete the selected user?</div>
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalLabel">Ready to Leave?</h5>
|
<h5 class="modal-title" id="modalLabel">Ready to Leave?</h5>
|
||||||
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
|
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
|
||||||
@@ -209,6 +209,10 @@
|
|||||||
return '%' + c.charCodeAt(0).toString(16);
|
return '%' + c.charCodeAt(0).toString(16);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function replaceSlash(str){
|
||||||
|
return str.replace(/\//g,'\u2215');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Page level plugins -->
|
<!-- Page level plugins -->
|
||||||
|
|||||||
@@ -48,6 +48,118 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{define "dialog"}}
|
||||||
|
<div class="modal fade" id="createDirModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="deleteModalLabel">
|
||||||
|
Create a new directory
|
||||||
|
</h5>
|
||||||
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id="create_dir_form" action="" method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="directory_name" class="col-form-label">Name</label>
|
||||||
|
<input type="text" class="form-control" id="directory_name" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="uploadFilesModal" tabindex="-1" role="dialog" aria-labelledby="uploadFilesModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="uploadFilesModalLabel">
|
||||||
|
Upload one or more files
|
||||||
|
</h5>
|
||||||
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id="upload_files_form" action="" method="POST" enctype="multipart/form-data">
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="file" class="form-control-file" id="files_name" name="filename" required multiple>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="renameModal" tabindex="-1" role="dialog" aria-labelledby="renameModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="renameModalLabel">
|
||||||
|
Rename the selected item
|
||||||
|
</h5>
|
||||||
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id="rename_form" action="" method="POST">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="rename_old_name" class="col-form-label">Old name</label>
|
||||||
|
<input type="text" class="form-control" id="rename_old_name" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="rename_new_name" class="col-form-label">New name</label>
|
||||||
|
<input type="text" class="form-control" id="rename_new_name" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="deleteModalLabel">
|
||||||
|
Confirmation required
|
||||||
|
</h5>
|
||||||
|
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">Do you want to delete the selected item?</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" type="button" data-dismiss="modal">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<a class="btn btn-warning" href="#" onclick="deleteAction()">
|
||||||
|
Delete
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{define "extra_js"}}
|
{{define "extra_js"}}
|
||||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||||
@@ -159,7 +271,180 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getNameFromTypeName(typeName) {
|
||||||
|
return typeName.split('_').slice(1).join('_');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTypeFromTypeName(typeName) {
|
||||||
|
return typeName.split('_')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteAction() {
|
||||||
|
var table = $('#dataTable').DataTable();
|
||||||
|
table.button('delete:name').enable(false);
|
||||||
|
var selected = table.column(0).checkboxes.selected()[0];
|
||||||
|
var itemType = getTypeFromTypeName(selected);
|
||||||
|
var itemName = getNameFromTypeName(selected);
|
||||||
|
var path;
|
||||||
|
if (itemType == "1"){
|
||||||
|
path = '{{.DirsURL}}';
|
||||||
|
} else {
|
||||||
|
path = '{{.FilesURL}}';
|
||||||
|
}
|
||||||
|
path+='?path={{.CurrentDir}}'+fixedEncodeURIComponent("/"+itemName);
|
||||||
|
$('#deleteModal').modal('hide');
|
||||||
|
$.ajax({
|
||||||
|
url: path,
|
||||||
|
type: 'DELETE',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
|
||||||
|
timeout: 15000,
|
||||||
|
success: function (result) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
error: function ($xhr, textStatus, errorThrown) {
|
||||||
|
var txt = "Unable to delete the selected item";
|
||||||
|
if ($xhr) {
|
||||||
|
var json = $xhr.responseJSON;
|
||||||
|
if (json) {
|
||||||
|
if (json.message) {
|
||||||
|
txt = json.message;
|
||||||
|
}
|
||||||
|
if (json.error) {
|
||||||
|
txt += ": " + json.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#errorTxt').text(txt);
|
||||||
|
$('#errorMsg').show();
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#errorMsg').hide();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
$("#create_dir_form").submit(function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
$('#createDirModal').modal('hide');
|
||||||
|
var dirName = replaceSlash($("#directory_name").val());
|
||||||
|
var path = '{{.DirsURL}}?path={{.CurrentDir}}' + fixedEncodeURIComponent("/"+dirName);
|
||||||
|
$.ajax({
|
||||||
|
url: path,
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
|
||||||
|
timeout: 15000,
|
||||||
|
success: function (result) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
error: function ($xhr, textStatus, errorThrown) {
|
||||||
|
var txt = "Unable to create the requested directory";
|
||||||
|
if ($xhr) {
|
||||||
|
var json = $xhr.responseJSON;
|
||||||
|
if (json) {
|
||||||
|
if (json.message) {
|
||||||
|
txt = json.message;
|
||||||
|
}
|
||||||
|
if (json.error) {
|
||||||
|
txt += ": " + json.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#errorTxt').text(txt);
|
||||||
|
$('#errorMsg').show();
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#errorMsg').hide();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#upload_files_form").submit(function (event){
|
||||||
|
event.preventDefault();
|
||||||
|
$('uploadFilesModal').modal('hide');
|
||||||
|
var path = '{{.FilesURL}}?path={{.CurrentDir}}';
|
||||||
|
$.ajax({
|
||||||
|
url: path,
|
||||||
|
type: 'POST',
|
||||||
|
data: new FormData(this),
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
|
||||||
|
timeout: 15000,
|
||||||
|
success: function (result) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
error: function ($xhr, textStatus, errorThrown) {
|
||||||
|
var txt = "Error uploading files";
|
||||||
|
if ($xhr) {
|
||||||
|
var json = $xhr.responseJSON;
|
||||||
|
if (json) {
|
||||||
|
if (json.message) {
|
||||||
|
txt = json.message;
|
||||||
|
}
|
||||||
|
if (json.error) {
|
||||||
|
txt += ": " + json.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#errorTxt').text(txt);
|
||||||
|
$('#errorMsg').show();
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#errorMsg').hide();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#rename_form").submit(function (event){
|
||||||
|
event.preventDefault();
|
||||||
|
var table = $('#dataTable').DataTable();
|
||||||
|
table.button('rename:name').enable(false);
|
||||||
|
var selected = table.column(0).checkboxes.selected()[0];
|
||||||
|
var itemType = getTypeFromTypeName(selected);
|
||||||
|
var itemName = getNameFromTypeName(selected);
|
||||||
|
var targetName = replaceSlash($("#rename_new_name").val());
|
||||||
|
var path;
|
||||||
|
if (itemType == "1"){
|
||||||
|
path = '{{.DirsURL}}';
|
||||||
|
} else {
|
||||||
|
path = '{{.FilesURL}}';
|
||||||
|
}
|
||||||
|
path+='?path={{.CurrentDir}}'+fixedEncodeURIComponent("/"+itemName)+'&target={{.CurrentDir}}'+fixedEncodeURIComponent("/"+targetName);
|
||||||
|
$('renameModal').modal('hide');
|
||||||
|
$.ajax({
|
||||||
|
url: path,
|
||||||
|
type: 'PATCH',
|
||||||
|
dataType: 'json',
|
||||||
|
headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' },
|
||||||
|
timeout: 15000,
|
||||||
|
success: function (result) {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
error: function ($xhr, textStatus, errorThrown) {
|
||||||
|
var txt = "Error renaming item";
|
||||||
|
if ($xhr) {
|
||||||
|
var json = $xhr.responseJSON;
|
||||||
|
if (json) {
|
||||||
|
if (json.message) {
|
||||||
|
txt = json.message;
|
||||||
|
}
|
||||||
|
if (json.error) {
|
||||||
|
txt += ": " + json.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#errorTxt').text(txt);
|
||||||
|
$('#errorMsg').show();
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#errorMsg').hide();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$.fn.dataTable.ext.buttons.refresh = {
|
$.fn.dataTable.ext.buttons.refresh = {
|
||||||
text: '<i class="fas fa-sync-alt"></i>',
|
text: '<i class="fas fa-sync-alt"></i>',
|
||||||
name: 'refresh',
|
name: 'refresh',
|
||||||
@@ -177,7 +462,7 @@
|
|||||||
var filesArray = [];
|
var filesArray = [];
|
||||||
var selected = dt.column(0).checkboxes.selected();
|
var selected = dt.column(0).checkboxes.selected();
|
||||||
for (i = 0; i < selected.length; i++) {
|
for (i = 0; i < selected.length; i++) {
|
||||||
filesArray.push(selected[i]);
|
filesArray.push(getNameFromTypeName(selected[i]));
|
||||||
}
|
}
|
||||||
var files = fixedEncodeURIComponent(JSON.stringify(filesArray));
|
var files = fixedEncodeURIComponent(JSON.stringify(filesArray));
|
||||||
var downloadURL = '{{.DownloadURL}}';
|
var downloadURL = '{{.DownloadURL}}';
|
||||||
@@ -187,9 +472,54 @@
|
|||||||
enabled: false
|
enabled: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$.fn.dataTable.ext.buttons.addFiles = {
|
||||||
|
text: '<i class="fas fa-file-upload"></i>',
|
||||||
|
name: 'addFiles',
|
||||||
|
titleAttr: "Upload files",
|
||||||
|
action: function (e, dt, node, config) {
|
||||||
|
$('#uploadFilesModal').modal('show');
|
||||||
|
},
|
||||||
|
enabled: true
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.dataTable.ext.buttons.addDirectory = {
|
||||||
|
text: '<i class="fas fa-folder-plus"></i>',
|
||||||
|
name: 'addDirectory',
|
||||||
|
titleAttr: "Add directory",
|
||||||
|
action: function (e, dt, node, config) {
|
||||||
|
$("#directory_name").val("");
|
||||||
|
$('#createDirModal').modal('show');
|
||||||
|
},
|
||||||
|
enabled: true
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.dataTable.ext.buttons.rename = {
|
||||||
|
text: '<i class="fas fa-edit"></i>',
|
||||||
|
name: 'rename',
|
||||||
|
titleAttr: "Rename",
|
||||||
|
action: function (e, dt, node, config) {
|
||||||
|
var selected = table.column(0).checkboxes.selected()[0];
|
||||||
|
var itemName = getNameFromTypeName(selected);
|
||||||
|
$("#rename_old_name").val(itemName);
|
||||||
|
$("#rename_new_name").val("");
|
||||||
|
$('#renameModal').modal('show');
|
||||||
|
},
|
||||||
|
enabled: false
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.dataTable.ext.buttons.delete = {
|
||||||
|
text: '<i class="fas fa-trash"></i>',
|
||||||
|
name: 'delete',
|
||||||
|
titleAttr: "Delete",
|
||||||
|
action: function (e, dt, node, config) {
|
||||||
|
$('#deleteModal').modal('show');
|
||||||
|
},
|
||||||
|
enabled: false
|
||||||
|
};
|
||||||
|
|
||||||
var table = $('#dataTable').DataTable({
|
var table = $('#dataTable').DataTable({
|
||||||
"ajax": {
|
"ajax": {
|
||||||
"url": "{{.ReadDirURL}}?path={{.CurrentDir}}",
|
"url": "{{.DirsURL}}?path={{.CurrentDir}}",
|
||||||
"dataSrc": "",
|
"dataSrc": "",
|
||||||
"error": function ($xhr, textStatus, errorThrown) {
|
"error": function ($xhr, textStatus, errorThrown) {
|
||||||
$(".dataTables_processing").hide();
|
$(".dataTables_processing").hide();
|
||||||
@@ -214,7 +544,7 @@
|
|||||||
"deferRender": true,
|
"deferRender": true,
|
||||||
"processing": true,
|
"processing": true,
|
||||||
"columns": [
|
"columns": [
|
||||||
{ "data": "name" },
|
{ "data": "type_name" },
|
||||||
{ "data": "type" },
|
{ "data": "type" },
|
||||||
{
|
{
|
||||||
"data": "name",
|
"data": "name",
|
||||||
@@ -250,6 +580,12 @@
|
|||||||
selectedText = `${selectedItems} items selected`;
|
selectedText = `${selectedItems} items selected`;
|
||||||
}
|
}
|
||||||
table.button('download:name').enable(selectedItems > 0);
|
table.button('download:name').enable(selectedItems > 0);
|
||||||
|
{{if .CanRename}}
|
||||||
|
table.button('rename:name').enable(selectedItems == 1);
|
||||||
|
{{end}}
|
||||||
|
{{if .CanDelete}}
|
||||||
|
table.button('delete:name').enable(selectedItems == 1);
|
||||||
|
{{end}}
|
||||||
$('#dataTable_info').find('span').remove();
|
$('#dataTable_info').find('span').remove();
|
||||||
$("#dataTable_info").append('<span class="selected-info"><span class="selected-item">' + selectedText + '</span></span>');
|
$("#dataTable_info").append('<span class="selected-info"><span class="selected-item">' + selectedText + '</span></span>');
|
||||||
}
|
}
|
||||||
@@ -279,6 +615,18 @@
|
|||||||
table.button().add(0, 'refresh');
|
table.button().add(0, 'refresh');
|
||||||
table.button().add(0, 'pageLength');
|
table.button().add(0, 'pageLength');
|
||||||
table.button().add(0, 'download');
|
table.button().add(0, 'download');
|
||||||
|
{{if .CanDelete}}
|
||||||
|
table.button().add(0, 'delete');
|
||||||
|
{{end}}
|
||||||
|
{{if .CanRename}}
|
||||||
|
table.button().add(0, 'rename');
|
||||||
|
{{end}}
|
||||||
|
{{if .CanCreateDirs}}
|
||||||
|
table.button().add(0, 'addDirectory');
|
||||||
|
{{end}}
|
||||||
|
{{if .CanAddFiles}}
|
||||||
|
table.button().add(0, 'addFiles');
|
||||||
|
{{end}}
|
||||||
table.buttons().container().appendTo('#dataTable_wrapper .col-md-6:eq(0)');
|
table.buttons().container().appendTo('#dataTable_wrapper .col-md-6:eq(0)');
|
||||||
},
|
},
|
||||||
"orderFixed": [1, 'asc'],
|
"orderFixed": [1, 'asc'],
|
||||||
|
|||||||
Reference in New Issue
Block a user