share.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <!--
  2. Copyright (C) 2023 Nicola Murino
  3. This WebUI uses the KeenThemes Bootstrap Templates:
  4. https://keenthemes.com/bootstrap-templates
  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="card shadow-sm">
  15. <div class="card-header bg-light">
  16. <h3 {{if .IsAdd}}data-i18n="title.add_share"{{else}}data-i18n="title.update_share"{{end}} class="card-title section-title"></h3>
  17. </div>
  18. <div class="card-body">
  19. {{- template "errmsg" .Error}}
  20. <form id="share_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">
  21. <div class="form-group row">
  22. <label for="name" data-i18n="general.name" class="col-md-3 col-form-label">Name</label>
  23. <div class="col-md-9">
  24. <input id="name" type="text" placeholder="" name="name" value="{{.Share.Name}}" maxlength="255" autocomplete="off"
  25. required {{if not .IsAdd}}class="form-control-plaintext readonly-input" readonly{{else}}class="form-control"{{end}} />
  26. </div>
  27. </div>
  28. <div class="form-group row mt-10">
  29. <label for="scope" data-i18n="share.scope" class="col-md-3 col-form-label">Scope</label>
  30. <div class="col-md-9">
  31. <select id="scope" name="scope" class="form-select" data-control="i18n-select2" data-hide-search="true" aria-describedby="scopeHelp">
  32. <option data-i18n="share.scope_read" value="1" {{if eq .Share.Scope 1 }}selected{{end}}>Read</option>
  33. <option data-i18n="share.scope_write" value="2" {{if eq .Share.Scope 2 }}selected{{end}}>Write</option>
  34. <option data-i18n="share.scope_read_write" value="3" {{if eq .Share.Scope 3 }}selected{{end}}>Read/Write</option>
  35. </select>
  36. <div id="scopeHelp" data-i18n="share.scope_help" class="form-text">
  37. For scope "Write" and "Read/Write" you have to define one path and it must be a directory
  38. </div>
  39. </div>
  40. </div>
  41. <div class="card mt-10">
  42. <div class="card-header bg-light">
  43. <h3 data-i18n="general.paths" class="card-title section-title-inner">Paths</h3>
  44. </div>
  45. <div class="card-body">
  46. <div id="paths">
  47. <div class="form-group">
  48. <div data-repeater-list="paths">
  49. {{- range $idx, $val := .Share.Paths}}
  50. <div data-repeater-item>
  51. <div class="form-group row">
  52. <div class="col-md-9 mt-3 mt-md-8">
  53. <input data-i18n="[placeholder]share.path_help" type="text" class="form-control"
  54. name="path" value="{{$val}}" />
  55. </div>
  56. <div class="col-md-3 mt-3 mt-md-8">
  57. <a href="#" data-repeater-delete
  58. class="btn btn-light-danger">
  59. <i class="ki-duotone ki-trash fs-5">
  60. <span class="path1"></span>
  61. <span class="path2"></span>
  62. <span class="path3"></span>
  63. <span class="path4"></span>
  64. <span class="path5"></span>
  65. </i>
  66. <span data-i18n="general.delete">Delete</span>
  67. </a>
  68. </div>
  69. </div>
  70. </div>
  71. {{- else}}
  72. <div data-repeater-item>
  73. <div class="form-group row">
  74. <div class="col-md-9 mt-3 mt-md-8">
  75. <input data-i18n="[placeholder]share.path_help" type="text" class="form-control"
  76. name="path" value="" />
  77. </div>
  78. <div class="col-md-3 mt-3 mt-md-8">
  79. <a href="#" data-repeater-delete
  80. class="btn btn-light-danger">
  81. <i class="ki-duotone ki-trash fs-5">
  82. <span class="path1"></span>
  83. <span class="path2"></span>
  84. <span class="path3"></span>
  85. <span class="path4"></span>
  86. <span class="path5"></span>
  87. </i>
  88. <span data-i18n="general.delete">Delete</span>
  89. </a>
  90. </div>
  91. </div>
  92. </div>
  93. {{- end}}
  94. </div>
  95. </div>
  96. <div class="form-group mt-5">
  97. <a href="#" data-repeater-create class="btn btn-light-primary">
  98. <i class="ki-duotone ki-plus fs-3"></i>
  99. <span data-i18n="general.add">Add</span>
  100. </a>
  101. </div>
  102. </div>
  103. </div>
  104. </div>
  105. <div class="form-group row mt-10">
  106. <label for="password" data-i18n="login.password" class="col-md-3 col-form-label">Password</label>
  107. <div class="col-md-9">
  108. <input id="password" type="password" class="form-control" name="password" autocomplete="new-password"
  109. placeholder="" spellcheck="false" value="{{.Share.Password}}" aria-describedby="passwordHelp" />
  110. <div id="passwordHelp" data-i18n="share.password_help" class="form-text">
  111. If set the share will be password-protected
  112. </div>
  113. </div>
  114. </div>
  115. <div class="form-group row mt-10">
  116. <label for="id_expiration" data-i18n="general.expiration" class="col-md-3 col-form-label">Expiration</label>
  117. <div class="col-md-9 d-flex">
  118. <input data-i18n="[placeholder]general.expiration_help" id="id_expiration" class="form-control" placeholder="Pick an expiration date" />
  119. <button class="btn btn-icon btn-light-danger ms-2 d-none" id="id_expiration_clear">
  120. <i class="ki-solid ki-cross fs-1"></i>
  121. </button>
  122. </div>
  123. </div>
  124. <div class="form-group row mt-10">
  125. <label for="max_tokens" data-i18n="share.max_tokens" class="col-md-3 col-form-label">Max tokens</label>
  126. <div class="col-md-9">
  127. <input id="max_tokens" type="number" min="0" class="form-control" name="max_tokens" value="{{.Share.MaxTokens}}" aria-describedby="max_tokens_help" />
  128. <div id="max_tokens_help" data-i18n="share.max_tokens_help" class="form-text">
  129. Maximum number of times this share can be accessed. 0 means no limit
  130. </div>
  131. </div>
  132. </div>
  133. <div class="form-group row mt-10">
  134. <label for="allowed_ip" data-i18n="general.allowed_ip_mask" class="col-md-3 col-form-label">Allowed IP/Mask</label>
  135. <div class="col-md-9">
  136. <textarea id="allowed_ip" class="form-control" name="allowed_ip" rows="3" aria-describedby="allowed_ip_help"
  137. placeholder="">{{.Share.GetAllowedFromAsString}}</textarea>
  138. <div id="allowed_ip_help" data-i18n="general.ip_mask_help" class="form-text">
  139. Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
  140. </div>
  141. </div>
  142. </div>
  143. <div class="form-group row mt-10">
  144. <label for="description" data-i18n="general.description" class="col-md-3 col-form-label">Description</label>
  145. <div class="col-md-9">
  146. <textarea id="description" class="form-control" name="description" rows="3"
  147. placeholder="">{{.Share.Description}}</textarea>
  148. </div>
  149. </div>
  150. <div class="d-flex justify-content-end mt-12">
  151. <input type="hidden" name="expiration_date" id="hidden_start_datetime" value="">
  152. <input type="hidden" name="_form_token" value="{{.CSRFToken}}">
  153. <button type="submit" id="form_submit" class="btn btn-primary px-10">
  154. <span data-i18n="general.submit" class="indicator-label">
  155. Submit
  156. </span>
  157. <span data-i18n="general.wait" class="indicator-progress">
  158. Please wait...
  159. <span class="spinner-border spinner-border-sm align-middle ms-2"></span>
  160. </span>
  161. </button>
  162. </div>
  163. </form>
  164. </div>
  165. </div>
  166. {{- end}}
  167. {{- define "extra_js"}}
  168. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/formrepeater/formrepeater.bundle.js"></script>
  169. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/flatpickr/l10n/it.js"></script>
  170. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/flatpickr/l10n/de.js"></script>
  171. <script {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}} src="{{.StaticURL}}/assets/plugins/custom/flatpickr/l10n/fr.js"></script>
  172. <script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
  173. $(document).on("i18nshow", function(){
  174. initRepeater('#paths');
  175. initRepeaterItems();
  176. const picker = $('#id_expiration').flatpickr({
  177. enableTime: false,
  178. time_24hr: true,
  179. formatDate: (date, format, locale) => {
  180. return $.t('general.datetime', {
  181. val: new Date(date),
  182. formatParams: {
  183. val: { year: 'numeric', month: 'numeric', day: 'numeric' },
  184. }
  185. });
  186. },
  187. defaultHour: 23,
  188. defaultMinute: 59,
  189. locale: i18next.resolvedLanguage,
  190. onChange: function(selectedDates, dateStr, instance) {
  191. if (selectedDates.length > 0){
  192. $('#id_expiration_clear').removeClass("d-none");
  193. } else {
  194. $('#id_expiration_clear').addClass("d-none");
  195. }
  196. }
  197. });
  198. //{{ if gt .Share.ExpiresAt 0 }}
  199. let input_dt = moment('{{.Share.ExpiresAt }}', 'x').format('YYYY-MM-DD');
  200. picker.setDate(input_dt, true);
  201. //{{ end }}
  202. $('#id_expiration_clear').on("click", function(e){
  203. e.preventDefault();
  204. picker.clear();
  205. });
  206. $("#share_form").submit(function (event) {
  207. $('#hidden_start_datetime').val("");
  208. let dt = picker.selectedDates;
  209. if (dt.length > 0) {
  210. let d = dt[0];
  211. if (d) {
  212. let dateString = moment.utc(d).format('YYYY-MM-DD HH:mm:ss');
  213. $('#hidden_start_datetime').val(dateString);
  214. }
  215. }
  216. let submitButton = document.querySelector('#form_submit');
  217. submitButton.setAttribute('data-kt-indicator', 'on');
  218. submitButton.disabled = true;
  219. });
  220. });
  221. </script>
  222. {{- end}}