shares: add an upload form for shares with write scope

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2022-02-15 19:19:25 +01:00
parent ebbbf81e65
commit f1832d4478
8 changed files with 253 additions and 36 deletions

View File

@@ -93,16 +93,24 @@
<div class="modal-body">
<div id="readShare">
<p>You can download the shared contents, as single zip file, using this <a id="readLink" href="#" target="_blank">link</a>.</p>
<p>If the share consists of a single folder you can browse and download single files using this <a id="readBrowseLink" href="#" target="_blank">link</a>.</p>
<p>If the share consists of a single directory you can browse and download files using this <a id="readBrowseLink" href="#" target="_blank">page</a>.</p>
<p>If the share consists of a single file you can download it uncompressed using this <a id="readUncompressedLink" href="#" target="_blank">link</a>.</p>
</div>
<div id="writeShare">
<p>You can upload one or more files to the shared directory by sending a multipart/form-data request to this <a id="writeLink" href="#" target="_blank">link</a>. The form field name for the file(s) is <b><code>filenames</code></b>.</p>
<p>For example:</p>
<p><code>curl -F filenames=@file1.txt -F filenames=@file2.txt "share link"</code></p>
<p>You can upload files one by one by adding the path encoded file name to the share <a id="writeLinkSingle" href="#" target="_blank">link</a> and sending the file as POST body. The optional <b><code>X-SFTPGO-MTIME</code></b> header allows to set the file modification time as milliseconds since epoch.</p>
<p>For example:</p>
<p><code>curl --data-binary @file.txt -H "Content-Type: application/octet-stream" -H "X-SFTPGO-MTIME: 1638882991234" "share link/file.txt"</code></p>
<p>You can upload one or more files to the shared directory using this <a id="writePageLink" href="#" target="_blank">page</a></p>
<p>
<a data-toggle="collapse" href="#collapseWriteShareAdvanced" aria-expanded="false" aria-controls="collapseWriteShareAdvanced">
Advanced options
</a>
</p>
<div class="collapse" id="collapseWriteShareAdvanced">
<div class="card card-body">
<p>You can upload one or more files to the shared directory by sending a multipart/form-data request to this <a id="writeLink" href="#" target="_blank">link</a>. The form field name for the file(s) is <b><code>filenames</code></b>.</p>
<p>Example: <code>curl -F filenames=@file1.txt -F filenames=@file2.txt "share link"</code></p>
<p>Or you can upload files one by one by adding the path encoded file name to the share <a id="writeLinkSingle" href="#" target="_blank">link</a> and sending the file as POST body. The optional <b><code>X-SFTPGO-MTIME</code></b> header allows to set the file modification time as milliseconds since epoch.</p>
<p>Example: <code>curl --data-binary @file.txt -H "Content-Type: application/octet-stream" -H "X-SFTPGO-MTIME: 1638882991234" "share link/file.txt"</code></p>
</div>
</div>
</div>
<div id="expiredShare">
This share is no longer accessible because it has expired
@@ -226,6 +234,8 @@
$('#expiredShare').hide();
$('#writeShare').show();
$('#readShare').hide();
$('#writePageLink').attr("href", shareURL+"/upload");
$('#writePageLink').attr("title", shareURL+"/upload");
$('#writeLink').attr("href", shareURL);
$('#writeLink').attr("title", shareURL);
$('#writeLinkSingle').attr("href", shareURL);

View File

@@ -0,0 +1,144 @@
{{template "base" .}}
{{define "title"}}{{.Title}}{{end}}
{{define "page_body"}}
<div class="row justify-content-center">
<div class="col-xl-5 col-lg-6 col-md-8">
<div class="card shadow-lg my-5">
<div class="card-header py-3">
<h6 id="default_title" class="m-0 font-weight-bold text-primary">Upload one or more files to share "{{.Share.Name}}", user "{{.Share.Username}}"</h6>
<h6 id="success_title" class="m-0 font-weight-bold text-primary" style="display: none;">Upload completed to share "{{.Share.Name}}", user "{{.Share.Username}}"</h6>
</div>
<div class="card-body">
<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
<div id="errorTxt" class="card-body text-form-error"></div>
</div>
<div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
<div id="successTxt" class="card-body">
<p>File/s uploaded successfully</p>
<p>If you want to upload other files click <a href="javascript:refreshPage();">here</a></p>
</div>
</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="filenames" required multiple>
</div>
<button type="submit" class="btn btn-primary float-right mt-3 px-5">Submit</button>
</form>
</div>
</div>
</div>
</div>
{{end}}
{{define "dialog"}}
<div class="modal fade" id="spinnerModal" tabindex="-1" role="dialog" data-keyboard="false" data-backdrop="static">
<div class="modal-dialog modal-dialog-centered justify-content-center" role="document">
<span style="color: #333333;" class="fa fa-spinner fa-spin fa-3x"></span>
</div>
</div>
{{end}}
{{define "extra_js"}}
<script type="text/javascript">
var spinnerDone = false;
function refreshPage() {
location.reload();
}
$(document).ready(function () {
$('#spinnerModal').on('shown.bs.modal', function () {
if (spinnerDone){
$('#spinnerModal').modal('hide');
}
});
$("#upload_files_form").submit(function (event){
event.preventDefault();
var files = $("#files_name")[0].files;
var has_errors = false;
var index = 0;
var success = 0;
spinnerDone = false;
$('#spinnerModal').modal('show');
function uploadFile() {
if (index >= files.length || has_errors){
$('#spinnerModal').modal('hide');
spinnerDone = true;
if (!has_errors){
$('#errorMsg').hide();
$('#upload_files_form').hide();
$('#default_title').hide();
$('#success_title').show();
$('#successMsg').show();
}
return;
}
async function saveFile() {
var errorMessage = "Error uploading files";
let response;
try {
var f = files[index];
var uploadPath = '{{.UploadBasePath}}/'+fixedEncodeURIComponent(f.name);
var lastModified;
try {
lastModified = f.lastModified;
} catch (e) {
console.log("unable to get last modified time from file: "+e.message);
lastModified = "";
}
response = await fetch(uploadPath, {
method: 'POST',
headers: {
'X-SFTPGO-MTIME': lastModified
},
credentials: 'same-origin',
redirect: 'error',
body: f
});
} catch (e){
throw Error(errorMessage+": " +e.message);
}
if (response.status == 201){
index++;
success++;
uploadFile();
} else {
let jsonResponse;
try {
jsonResponse = await response.json();
} catch(e){
throw Error(errorMessage);
}
if (jsonResponse.message) {
errorMessage = jsonResponse.message;
}
if (jsonResponse.error) {
errorMessage += ": " + jsonResponse.error;
}
throw Error(errorMessage);
}
}
saveFile().catch(function(error){
index++;
has_errors = true;
$('#errorTxt').text(error.message);
$('#errorMsg').show();
setTimeout(function () {
$('#errorMsg').hide();
}, 10000);
uploadFile();
});
}
uploadFile();
});
});
</script>
{{end}}