shareupload.html 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <!--
  2. Copyright (C) 2023 Nicola Murino
  3. This WebUI uses the KeenThemes Mega Bundle, a proprietary theme:
  4. https://keenthemes.com/products/templates-mega-bundle
  5. KeenThemes HTML/CSS/JS components are allowed for use only within the
  6. SFTPGo product and restricted to be used in a resealable HTML template
  7. that can compete with KeenThemes products anyhow.
  8. This WebUI is allowed for use only within the SFTPGo product and
  9. therefore cannot be used in derivative works/products without an
  10. explicit grant from the SFTPGo Team ([email protected]).
  11. -->
  12. {{- template "base" .}}
  13. {{- define "page_body"}}
  14. <div class="d-flex flex-center flex-column flex-column-fluid p-10 pb-lg-20">
  15. <div class="mb-12">
  16. <span>
  17. <img alt="Logo" src="{{.StaticURL}}{{.Branding.LogoPath}}" class="h-80px" />
  18. </span>
  19. <span class="text-gray-800 fs-2 fw-semibold ps-5">
  20. {{.Branding.ShortName}}
  21. </span>
  22. </div>
  23. <div class="card shadow-sm w-lg-600px">
  24. <div class="card-header bg-light">
  25. <h3 data-i18n="title.upload_to_share" class="card-title section-title">Upload one or more files to share</h3>
  26. </div>
  27. <div class="card-body">
  28. {{- template "errmsg" ""}}
  29. <form id="upload_files_form" action="{{.UploadBasePath}}" method="POST" enctype="multipart/form-data">
  30. <div class="fv-row">
  31. <div class="dropzone" id="upload_files">
  32. <div class="dz-message needsclick align-items-center">
  33. <i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>
  34. <div class="ms-4">
  35. <h3 data-i18n="fs.upload.message" class="fs-5 fw-bold text-gray-900 mb-1">Drop files here or click to upload.</h3>
  36. </div>
  37. </div>
  38. </div>
  39. </div>
  40. <div class="d-flex justify-content-end mt-10">
  41. <button data-i18n="general.submit" type="button" id="upload_files_button" class="btn btn-primary">Submit</button>
  42. </div>
  43. </form>
  44. </div>
  45. </div>
  46. </div>
  47. {{- end}}
  48. {{- define "extra_js"}}
  49. <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
  50. function uploadFiles(files) {
  51. let has_errors = false;
  52. let index = 0;
  53. let success = 0;
  54. $('#errorMsg').addClass("d-none");
  55. $('#loading_message').text("");
  56. KTApp.showPageLoading();
  57. function uploadFile() {
  58. if (index >= files.length || has_errors) {
  59. KTApp.hidePageLoading();
  60. if (!has_errors) {
  61. ModalAlert.fire({
  62. text: $.t('fs.upload.success'),
  63. icon: "success",
  64. confirmButtonText: $.t('general.ok'),
  65. customClass: {
  66. confirmButton: 'btn btn-primary'
  67. }
  68. }).then((result) => {
  69. if (result.isConfirmed){
  70. location.reload();
  71. }
  72. });
  73. }
  74. return;
  75. }
  76. let f = files[index];
  77. let uploadPath = '{{.UploadBasePath}}/'+encodeURIComponent(f.name);
  78. let lastModified;
  79. try {
  80. lastModified = f.lastModified;
  81. } catch (e) {
  82. console.error("unable to get last modified time from file: " + e.message);
  83. lastModified = "";
  84. }
  85. let uploadTxt = f.name;
  86. if (files.length > 1){
  87. uploadTxt = $.t('fs.uploading', {
  88. idx: index + 1,
  89. total: files.length,
  90. name: uploadTxt
  91. });
  92. }
  93. $('#loading_message').text(uploadTxt);
  94. axios.post(uploadPath, f, {
  95. headers: {
  96. 'X-SFTPGO-MTIME': lastModified,
  97. 'X-CSRF-TOKEN': '{{.CSRFToken}}'
  98. },
  99. onUploadProgress: function (progressEvent) {
  100. if (!progressEvent.total){
  101. return;
  102. }
  103. const percentage = Math.round((100 * progressEvent.loaded) / progressEvent.total);
  104. if (percentage > 0 && percentage < 100){
  105. $('#loading_message').text(`${uploadTxt} ${percentage}%`);
  106. }
  107. },
  108. validateStatus: function (status) {
  109. return status == 201;
  110. }
  111. }).then(function (response) {
  112. index++;
  113. success++;
  114. uploadFile();
  115. }).catch(function (error) {
  116. let errorMessage;
  117. if (error && error.response) {
  118. switch (error.response.status) {
  119. case 403:
  120. errorMessage = "fs.upload.err_403";
  121. break;
  122. case 429:
  123. errorMessage = "fs.upload.err_429";
  124. break;
  125. }
  126. }
  127. if (!errorMessage){
  128. errorMessage = "fs.upload.err_generic";
  129. }
  130. index++;
  131. has_errors = true;
  132. setI18NData($('#errorTxt'), errorMessage);
  133. $('#errorMsg').removeClass("d-none");
  134. uploadFile();
  135. });
  136. }
  137. uploadFile();
  138. }
  139. KTUtil.onDOMContentLoaded(function () {
  140. var dropzone = new Dropzone("#upload_files", {
  141. url: "{{.UploadBasePath}}",
  142. paramName: "filenames",
  143. maxFiles: 200,
  144. maxFilesize: null,
  145. autoQueue: false,
  146. addRemoveLinks: true,
  147. autoProcessQueue: false,
  148. filesizeBase: 1000,
  149. init: function() {
  150. var dropzone = this;
  151. $("#upload_files_button").click(function(){
  152. uploadFiles(dropzone.getAcceptedFiles());
  153. });
  154. }
  155. });
  156. dropzone.on("addedfile", file => {
  157. file.previewElement.querySelector(".dz-progress").style.display = 'none';
  158. });
  159. });
  160. </script>
  161. {{- end}}