| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- <!--
- Copyright (C) 2023 Nicola Murino
- This WebUI uses the KeenThemes Mega Bundle, a proprietary theme:
- https://keenthemes.com/products/templates-mega-bundle
- KeenThemes HTML/CSS/JS components are allowed for use only within the
- SFTPGo product and restricted to be used in a resealable HTML template
- that can compete with KeenThemes products anyhow.
- This WebUI is allowed for use only within the SFTPGo product and
- therefore cannot be used in derivative works/products without an
- explicit grant from the SFTPGo Team ([email protected]).
- -->
- {{- template "base" .}}
- {{- define "page_body"}}
- <div class="d-flex flex-center flex-column flex-column-fluid p-10 pb-lg-20">
- <div class="mb-12">
- <span>
- <img alt="Logo" src="{{.StaticURL}}{{.Branding.LogoPath}}" class="h-80px" />
- </span>
- <span class="text-gray-800 fs-2 fw-semibold ps-5">
- {{.Branding.ShortName}}
- </span>
- </div>
- <div class="card shadow-sm w-lg-600px">
- <div class="card-header bg-light">
- <h3 data-i18n="title.upload_to_share" class="card-title section-title">Upload one or more files to share</h3>
- </div>
- <div class="card-body">
- {{- template "errmsg" ""}}
- <form id="upload_files_form" action="{{.UploadBasePath}}" method="POST" enctype="multipart/form-data">
- <div class="fv-row">
- <div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files">
- <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>
- <div class="ms-4">
- <h3 data-i18n="fs.upload.message" class="fs-5 fw-bold text-gray-900 mb-1">Drop files here or click to upload.</h3>
- </div>
- </div>
- </div>
- </div>
- <div class="d-flex justify-content-end mt-10">
- <button data-i18n="general.submit" type="button" id="upload_files_button" class="btn btn-primary">Submit</button>
- </div>
- </form>
- </div>
- </div>
- </div>
- {{- end}}
- {{- define "extra_js"}}
- <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
- function uploadFiles(files) {
- let has_errors = false;
- let index = 0;
- let success = 0;
- let checkedDirs = [];
- $('#errorMsg').addClass("d-none");
- $('#loading_message').text("");
- KTApp.showPageLoading();
- function uploadFile() {
- if (index >= files.length || has_errors) {
- KTApp.hidePageLoading();
- if (!has_errors) {
- ModalAlert.fire({
- text: $.t('fs.upload.success'),
- icon: "success",
- confirmButtonText: $.t('general.ok'),
- customClass: {
- confirmButton: 'btn btn-primary'
- }
- }).then((result) => {
- if (result.isConfirmed){
- location.reload();
- }
- });
- }
- return;
- }
- let f = files[index];
- 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;
- try {
- lastModified = f.lastModified;
- } catch (e) {
- console.error("unable to get last modified time from file: " + e.message);
- lastModified = "";
- }
- let uploadTxt = f.name;
- if (files.length > 1){
- uploadTxt = $.t('fs.uploading', {
- idx: index + 1,
- total: files.length,
- name: uploadTxt
- });
- }
- $('#loading_message').text(uploadTxt);
- axios.post(uploadPath, f, {
- headers: {
- 'X-SFTPGO-MTIME': lastModified,
- 'X-CSRF-TOKEN': '{{.CSRFToken}}'
- },
- onUploadProgress: function (progressEvent) {
- if (!progressEvent.total){
- return;
- }
- const percentage = Math.round((100 * progressEvent.loaded) / progressEvent.total);
- if (percentage > 0 && percentage < 100){
- $('#loading_message').text(`${uploadTxt} ${percentage}%`);
- }
- },
- validateStatus: function (status) {
- return status == 201;
- }
- }).then(function (response) {
- index++;
- success++;
- uploadFile();
- }).catch(function (error) {
- let errorMessage;
- if (error && error.response) {
- switch (error.response.status) {
- case 403:
- errorMessage = "fs.upload.err_403";
- break;
- case 429:
- errorMessage = "fs.upload.err_429";
- break;
- }
- }
- if (!errorMessage){
- errorMessage = "fs.upload.err_generic";
- }
- index++;
- has_errors = true;
- setI18NData($('#errorTxt'), errorMessage);
- $('#errorMsg').removeClass("d-none");
- uploadFile();
- });
- }
- uploadFile();
- }
- KTUtil.onDOMContentLoaded(function () {
- var lastAddedFile = Date.now();
- function canUpload() {
- // Ugly hack to detect if we are still loading a large file list when the user try to upload files.
- // The Dropzone addedfiles event is fired for directories before the files within them are added to the queue.
- // TODO: investigate if there is a better way.
- if (Date.now() - lastAddedFile < 500) {
- ModalAlert.fire({
- text: $.t('fs.upload_queue_not_ready'),
- icon: "warning",
- confirmButtonText: $.t('general.ok'),
- customClass: {
- confirmButton: "btn btn-primary"
- }
- });
- return false;
- }
- return true;
- }
- var dropzone = new Dropzone("#upload_files", {
- url: "{{.UploadBasePath}}",
- paramName: "filenames",
- createImageThumbnails: false,
- maxFiles: null,
- maxFilesize: null,
- autoQueue: false,
- addRemoveLinks: false,
- autoProcessQueue: false,
- 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> (<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() {
- var dropzone = this;
- $("#upload_files_button").click(function(){
- if (canUpload()){
- uploadFiles(dropzone.getAcceptedFiles());
- }
- });
- }
- });
- dropzone.on("addedfile", file => {
- 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;
- }
- }
- lastAddedFile = Date.now();
- });
- });
- </script>
- {{- end}}
|