WebClient: improve file uploads

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2024-03-31 20:42:28 +02:00
parent cb3bc3f604
commit fc023748c1
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
17 changed files with 127 additions and 26 deletions

View file

@ -357,6 +357,13 @@ func (s *httpdServer) uploadFileToShare(w http.ResponseWriter, r *http.Request)
return return
} }
defer common.Connections.Remove(connection.GetID()) defer common.Connections.Remove(connection.GetID())
if getBoolQueryParam(r, "mkdir_parents") {
if err = connection.CheckParentDirs(path.Dir(filePath)); err != nil {
sendAPIResponse(w, r, err, "Error checking parent directories", getMappedStatusCode(err))
return
}
}
if err := doUploadFile(w, r, connection, filePath); err != nil { if err := doUploadFile(w, r, connection, filePath); err != nil {
dataprovider.UpdateShareLastUse(&share, -1) //nolint:errcheck dataprovider.UpdateShareLastUse(&share, -1) //nolint:errcheck
} }

View file

@ -360,7 +360,7 @@
"err_403": "$t(fs.upload.err_generic). $t(fs.err_403)", "err_403": "$t(fs.upload.err_generic). $t(fs.err_403)",
"err_429": "$t(fs.upload.err_generic). $t(fs.err_429)", "err_429": "$t(fs.upload.err_generic). $t(fs.err_429)",
"err_dir_overwrite": "$t(fs.upload.err_generic). There are directories with the same name as the files: {{- val}}", "err_dir_overwrite": "$t(fs.upload.err_generic). There are directories with the same name as the files: {{- val}}",
"overwrite_text": "File conflict detected. Do you want to overwrite the following files?" "overwrite_text": "Conflict detected. Do you want to overwrite the following files/directories?"
}, },
"quota_usage": { "quota_usage": {
"title": "Quota usage", "title": "Quota usage",

View file

@ -360,7 +360,7 @@
"err_403": "$t(fs.upload.err_generic). $t(fs.err_403)", "err_403": "$t(fs.upload.err_generic). $t(fs.err_403)",
"err_429": "$t(fs.upload.err_generic). $t(fs.err_429)", "err_429": "$t(fs.upload.err_generic). $t(fs.err_429)",
"err_dir_overwrite": "$t(fs.upload.err_generic). Ci sono cartelle con lo stesso nome dei file: {{- val}}", "err_dir_overwrite": "$t(fs.upload.err_generic). Ci sono cartelle con lo stesso nome dei file: {{- val}}",
"overwrite_text": "Rilevato conflitto di file. Vuoi sovrascrivere i seguenti file?" "overwrite_text": "Rilevato conflitto. Vuoi sovrascrivere i seguenti file/cartelle?"
}, },
"quota_usage": { "quota_usage": {
"title": "Utilizzo quota", "title": "Utilizzo quota",

View file

@ -341,6 +341,13 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
.shortcut { .shortcut {
font-family: monospace; color: #666; font-family: monospace; color: #666;
} }
.overflow-auto {
overflow: auto;
}
.visibility-auto {
content-visibility: auto;
}
</style> </style>
{{- end}} {{- end}}

View file

@ -227,6 +227,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -127,6 +127,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -132,6 +132,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -132,6 +132,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -183,6 +183,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -164,6 +164,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -150,6 +150,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -263,6 +263,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: handleResponseData, dataSrc: handleResponseData,
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -151,6 +151,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -279,6 +279,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -159,7 +159,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div id="upload_files_empty_container" class="d-none mt-10"> <div id="upload_files_empty_container" class="d-none mt-10">
<form id="upload_files_empty_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data"> <form id="upload_files_empty_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data">
<div class="fv-row"> <div class="fv-row">
<div class="dropzone" id="upload_files_empty"> <div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files_empty">
<div class="dz-message needsclick align-items-center"> <div class="dz-message needsclick align-items-center">
<i class="ki-duotone ki-file-up fs-3x text-primary"> <i class="ki-duotone ki-file-up fs-3x text-primary">
<span class="path1"></span> <span class="path1"></span>
@ -235,6 +235,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
//{{- end}} //{{- end}}
//{{- end}} //{{- end}}
const dzPreviewTemplate = `<div class="d-flex align-items-center mb-2">
<span class="bullet bullet-dot bg-primary me-2"></span>
<div class="text-break text-wrap text-left"><span class="fs-5 fw-semibold" data-dz-name></span>&nbsp;(<span class="fs-5 fw-semibold" data-custom-size></span>)</div>
</div>
<div class="dz-error-message d-none" data-dz-errormessage></div>
<div class="dz-progress d-none"><span class="dz-upload" data-dz-uploadprogress></span></div>
`;
//{{- if not .ShareUploadBaseURL}} //{{- if not .ShareUploadBaseURL}}
const supportedEditExtensions = ["csv", "bat", "dyalog", "apl", "asc", "pgp", "sig", "asn", "asn1", "b", "bf", const supportedEditExtensions = ["csv", "bat", "dyalog", "apl", "asc", "pgp", "sig", "asn", "asn1", "b", "bf",
"c", "h", "ino", "cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx", "cob", "cpy", "cbl", "cs", "clj", "c", "h", "ino", "cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx", "cob", "cpy", "cbl", "cs", "clj",
@ -556,6 +564,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;
@ -1979,6 +1988,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
let has_errors = false; let has_errors = false;
let index = 0; let index = 0;
let success = 0; let success = 0;
let checkedDirs = [];
$('#errorMsg').addClass("d-none"); $('#errorMsg').addClass("d-none");
$('#loading_message').text(""); $('#loading_message').text("");
KTApp.showPageLoading(); KTApp.showPageLoading();
@ -1996,10 +2006,20 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
let f = files[index]; let f = files[index];
let uploadPath; let uploadPath;
let name = f.name;
let mkdirParents = "false";
if (f.fullPath){
name = f.fullPath;
let dirName = name.substr(0, name.lastIndexOf("/"));
if (!checkedDirs.includes(dirName)){
mkdirParents = "true";
checkedDirs.push(dirName);
}
}
//{{- if .ShareUploadBaseURL}} //{{- if .ShareUploadBaseURL}}
uploadPath = '{{.ShareUploadBaseURL}}' + encodeURIComponent("/" + f.name); uploadPath = '{{.ShareUploadBaseURL}}' + encodeURIComponent("/" + name)+"?mkdir_parents="+mkdirParents;
//{{- else}} //{{- else}}
uploadPath = '{{.FileURL}}?path={{.CurrentDir}}' + encodeURIComponent("/" + f.name); uploadPath = '{{.FileURL}}?path={{.CurrentDir}}' + encodeURIComponent("/" + name)+"&mkdir_parents="+mkdirParents;
//{{- end}} //{{- end}}
let lastModified; let lastModified;
try { try {
@ -2064,9 +2084,27 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}); });
} }
let filesArray = [];
let dirsArray = [];
if (files.length > 0){
for (let i = 0; i < files.length; i++){
if (files[i].fullPath){
let dirName = files[i].fullPath.split('/')[0];
if (!dirsArray.includes(dirName)){
dirsArray.push(dirName);
}
if (!filesArray.includes(dirName)){
filesArray.push(dirName);
}
} else {
filesArray.push(files[i].name);
}
}
}
CheckExist.fire({ CheckExist.fire({
operation: "upload", operation: "upload",
files: files, files: filesArray,
path: "{{.CurrentDir}}" path: "{{.CurrentDir}}"
}).then((result)=> { }).then((result)=> {
if (result.error) { if (result.error) {
@ -2079,7 +2117,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
let existingFiles = []; let existingFiles = [];
let existingDirs = []; let existingDirs = [];
$.each(result.data, function (key, item) { $.each(result.data, function (key, item) {
if (item.type === "1") { if (item.type === "1" && !dirsArray.includes(item.name)) {
existingDirs.push(item.name); existingDirs.push(item.name);
} else { } else {
existingFiles.push(item.name); existingFiles.push(item.name);
@ -2122,15 +2160,9 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
var promiseResolve; var promiseResolve;
function doCheck(operation, files, target) { function doCheck(operation, files, target) {
let filesArray = [];
if (files && files.length > 0){
for (let i = 0; i < files.length; i++){
filesArray.push(files[i].name);
}
}
let path = '{{.CheckExistURL}}?op='+encodeURIComponent(operation)+"&path="+target; let path = '{{.CheckExistURL}}?op='+encodeURIComponent(operation)+"&path="+target;
axios.post(path, { axios.post(path, {
files: filesArray files: files
}, { }, {
headers: { headers: {
timeout: 15000, timeout: 15000,
@ -2176,12 +2208,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
var dropzone = new Dropzone("#upload_files", { var dropzone = new Dropzone("#upload_files", {
url: "{{.FilesURL}}?path={{.CurrentDir}}", url: "{{.FilesURL}}?path={{.CurrentDir}}",
paramName: "filenames", paramName: "filenames",
maxFiles: 250, createImageThumbnails: false,
maxFiles: null,
maxFilesize: null, maxFilesize: null,
autoQueue: false, autoQueue: false,
addRemoveLinks: true, addRemoveLinks: false,
autoProcessQueue: false, autoProcessQueue: false,
filesizeBase: 1000, filesizeBase: 1000,
previewTemplate: dzPreviewTemplate,
init: function() { init: function() {
var dropzone = this; var dropzone = this;
$("#upload_files_button").click(function(){ $("#upload_files_button").click(function(){
@ -2191,18 +2225,27 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}); });
dropzone.on("addedfile", file => { dropzone.on("addedfile", file => {
file.previewElement.querySelector(".dz-progress").style.display = 'none'; for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
node.textContent = fileSizeIEC(file.size);
}
if (file.fullPath){
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
node.textContent = file.fullPath;
}
}
}); });
var dropzoneEmpty = new Dropzone("#upload_files_empty", { var dropzoneEmpty = new Dropzone("#upload_files_empty", {
url: "{{.FilesURL}}?path={{.CurrentDir}}", url: "{{.FilesURL}}?path={{.CurrentDir}}",
paramName: "filenames", paramName: "filenames",
maxFiles: 250, createImageThumbnails: false,
maxFiles: null,
maxFilesize: null, maxFilesize: null,
autoQueue: false, autoQueue: false,
addRemoveLinks: true, addRemoveLinks: false,
autoProcessQueue: false, autoProcessQueue: false,
filesizeBase: 1000, filesizeBase: 1000,
previewTemplate: dzPreviewTemplate,
init: function() { init: function() {
var dropzoneEmpty = this; var dropzoneEmpty = this;
$("#upload_files_empty_button").click(function(){ $("#upload_files_empty_button").click(function(){
@ -2212,7 +2255,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}); });
dropzoneEmpty.on("addedfile", file => { dropzoneEmpty.on("addedfile", file => {
file.previewElement.querySelector(".dz-progress").style.display = 'none'; for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
node.textContent = fileSizeIEC(file.size);
}
if (file.fullPath){
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
node.textContent = file.fullPath;
}
}
}); });
$('#modal_video_player').on('hide.bs.modal', function () { $('#modal_video_player').on('hide.bs.modal', function () {
@ -2406,7 +2456,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-body"> <div class="modal-body">
<form id="upload_files_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data"> <form id="upload_files_form" action="{{.FilesURL}}?path={{.CurrentDir}}" method="POST" enctype="multipart/form-data">
<div class="fv-row"> <div class="fv-row">
<div class="dropzone" id="upload_files"> <div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files">
<div class="dz-message needsclick align-items-center"> <div class="dz-message needsclick align-items-center">
<i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i> <i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>
<div class="ms-4"> <div class="ms-4">

View file

@ -265,6 +265,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
dataSrc: "", dataSrc: "",
error: function ($xhr, textStatus, errorThrown) { error: function ($xhr, textStatus, errorThrown) {
$(".dataTables_processing").hide(); $(".dataTables_processing").hide();
$('#loader').addClass("d-none");
let txt = ""; let txt = "";
if ($xhr) { if ($xhr) {
let json = $xhr.responseJSON; let json = $xhr.responseJSON;

View file

@ -33,7 +33,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- template "errmsg" ""}} {{- template "errmsg" ""}}
<form id="upload_files_form" action="{{.UploadBasePath}}" method="POST" enctype="multipart/form-data"> <form id="upload_files_form" action="{{.UploadBasePath}}" method="POST" enctype="multipart/form-data">
<div class="fv-row"> <div class="fv-row">
<div class="dropzone" id="upload_files"> <div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files">
<div class="dz-message needsclick align-items-center"> <div class="dz-message needsclick align-items-center">
<i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i> <i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>
<div class="ms-4"> <div class="ms-4">
@ -58,6 +58,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
let has_errors = false; let has_errors = false;
let index = 0; let index = 0;
let success = 0; let success = 0;
let checkedDirs = [];
$('#errorMsg').addClass("d-none"); $('#errorMsg').addClass("d-none");
$('#loading_message').text(""); $('#loading_message').text("");
KTApp.showPageLoading(); KTApp.showPageLoading();
@ -83,7 +84,17 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
} }
let f = files[index]; let f = files[index];
let uploadPath = '{{.UploadBasePath}}/'+encodeURIComponent(f.name); let name = f.name;
let mkdirParents = "false";
if (f.fullPath){
name = f.fullPath;
let dirName = name.substr(0, name.lastIndexOf("/"));
if (!checkedDirs.includes(dirName)){
mkdirParents = "true";
checkedDirs.push(dirName);
}
}
let uploadPath = '{{.UploadBasePath}}/'+encodeURIComponent(name)+"?mkdir_parents="+mkdirParents;
let lastModified; let lastModified;
try { try {
lastModified = f.lastModified; lastModified = f.lastModified;
@ -154,12 +165,20 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
var dropzone = new Dropzone("#upload_files", { var dropzone = new Dropzone("#upload_files", {
url: "{{.UploadBasePath}}", url: "{{.UploadBasePath}}",
paramName: "filenames", paramName: "filenames",
maxFiles: 200, createImageThumbnails: false,
maxFiles: null,
maxFilesize: null, maxFilesize: null,
autoQueue: false, autoQueue: false,
addRemoveLinks: true, addRemoveLinks: false,
autoProcessQueue: false, autoProcessQueue: false,
filesizeBase: 1000, filesizeBase: 1000,
previewTemplate: `<div class="d-flex align-items-center mb-2">
<span class="bullet bullet-dot bg-primary me-2"></span>
<div class="text-break text-wrap text-left"><span class="fs-5 fw-semibold" data-dz-name></span>&nbsp;(<span class="fs-5 fw-semibold" data-custom-size></span>)</div>
</div>
<div class="dz-error-message d-none" data-dz-errormessage></div>
<div class="dz-progress d-none"><span class="dz-upload" data-dz-uploadprogress></span></div>
`,
init: function() { init: function() {
var dropzone = this; var dropzone = this;
$("#upload_files_button").click(function(){ $("#upload_files_button").click(function(){
@ -169,7 +188,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}); });
dropzone.on("addedfile", file => { dropzone.on("addedfile", file => {
file.previewElement.querySelector(".dz-progress").style.display = 'none'; for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
node.textContent = fileSizeIEC(file.size);
}
if (file.fullPath){
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
node.textContent = file.fullPath;
}
}
}); });
}); });