better user data validation for gridftp upload view
[qcg-portal.git] / qcg / templates / qcg / gridftp.html
1 {% extends 'qcg/base.html' %}
2 {% load staticfiles bootstrap3 %}
3
4 {% block extra_css %}
5     <link href="{% static 'qcg/selectize/selectize.bootstrap3.css' %}" rel="stylesheet">
6 {% endblock %}
7
8 {% block extra_js %}
9     <script src="{% static 'qcg/cookie/jquery.cookie.min.js' %}"></script>
10     <script src="{% static 'qcg/globals.js' %}"></script>
11     {% include 'filex/source.js.html' %}
12
13     <script>
14         var filex = filex || {};
15
16         $(function () {
17             'use strict';
18
19             filex.initialLoad();
20
21             var statusTimeout;
22
23             String.prototype.endsWith = function(suffix) {
24                 return this.indexOf(suffix, this.length - suffix.length) !== -1;
25             };
26
27             function status(msg) {
28                 clearTimeout(statusTimeout);
29                 statusTimeout = setTimeout(function() {
30                     $('#status').text('');
31                 }, 3000);
32
33                 $('#status').text(msg);
34             }
35
36             function failModal(msg) {
37                 return function(xhr) {
38                     var $errorModal = $('#error-modal');
39
40                     $errorModal.find('#error-modal-label').text('Błąd serwera');
41                     $errorModal.find('.modal-body').html($('<h4>', {text: msg}));
42
43                     var error = (xhr.responseJSON || {}).error || undefined;
44
45                     if (typeof error === 'string')
46                         $errorModal.find('.modal-body').append($('<pre>', {text: error}));
47
48                     filex.idle();
49                     $errorModal.modal();
50
51                     console.error(arguments);
52                 };
53             }
54
55             function conflictingName(name, modal) {
56                 if (filex.files.some(function(item) { return item.get('name') == name })) {
57                     modal.find('.alert').remove();
58
59                     $('<div>', {
60                         'class': 'alert alert-danger',
61                         html: '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> Plik o podanej już nazwie istnieje!'
62                     }).prependTo(modal.find('.modal-body'));
63
64                     return true;
65                 }
66
67                 return false;
68             }
69
70             filex.files.on('change:checked reset', function() {
71                 var selected = filex.selectedFiles().length;
72
73                 $('#btn-rename').toggleClass('disabled', selected != 1);
74                 $('#btn-delete').toggleClass('disabled', selected == 0);
75                 $('#btn-compress').toggleClass('disabled', selected == 0);
76
77                 if (selected == 1) {
78                     var filename = filex.selectedFiles()[0].get('name'),
79                         is_archive = _.some(['.zip', '.tar.gz', '.tgz', '.tar.bz2', 'tbz'], function(ext) {
80                             return filename.endsWith(ext);
81                         });
82
83                     $('#btn-extract').toggleClass('disabled', !is_archive);
84                 }
85                 else {
86                     $('#btn-extract').addClass('disabled');
87                 }
88             });
89
90             $('#btn-upload').on('click', function() {
91                 var url = '{% url 'gridftp_upload' %}?' + $.param({host: filex.host, path: filex.path.full()});
92
93                 var win = window.open(url, url, 'height=500,width=800');
94                 win.focus();
95             });
96
97             $('#btn-delete').on('click', function() {
98                 var selected = _.groupBy(filex.selectedFiles(), function(item) { return item.get('type') }),
99                     path = filex.path.full() + '/',
100                     dirs = _.map(selected.directory || [], function (item) { return path + item.get('name') }),
101                     files = _.map(selected.file || [], function (item) { return path + item.get('name') }),
102                     data = {
103                         host: filex.host,
104                         dirs: dirs,
105                         files: files
106                     },
107                     $confirmModal = $('#confirm-modal'),
108                     $confirmList = $confirmModal.find('ul').html('');
109
110                 _.each(filex.selectedFiles(), function(item) {
111                     $('<li>', {text: item.get('name')}).appendTo($confirmList);
112                 });
113
114                 $('#btn-confirm').off().on('click', function() {
115                     filex.busy();
116
117                     $.post('{% url 'filex:delete' %}', data, function(response) {
118                         var keys = Object.keys(response.fail);
119
120                         if (keys.length) {
121                             var $errorModal = $('#error-modal'),
122                                 $errorBody = $errorModal.find('.modal-body')
123                                                         .html($('<h4>', {text: 'Wystąpiły problemy podczas usuwania:'})),
124                                 $errorList = $('<dl>', {'class': 'dl-horizontal'}).appendTo($errorBody);
125
126                             $errorModal.find('#error-modal-label').text('Błąd');
127
128                             for (var i in keys) {
129                                 if(keys.hasOwnProperty(i)) {
130                                     $('<dt>', {text: keys[i].replace(path, '')}).appendTo($errorList);
131                                     $('<dd>', {text: response.fail[keys[i]]}).appendTo($errorList);
132                                 }
133                             }
134
135                             $errorModal.modal();
136                             filex.idle();
137                         }
138                         else {
139                             status('Usuwanie zakończone pomyślnie');
140                         }
141
142                         if (response.done.length)
143                             filex.reloadFiles();
144
145                     }, 'json').fail(failModal('Nie udało się usunąć plików'));
146
147                     $confirmModal.modal('hide');
148                 });
149
150                 $confirmModal.modal();
151             });
152
153             $('#mkdir-form').on('submit', function(e) {
154                 var $this = $(this);
155
156                 e.preventDefault();
157
158                 if (conflictingName($this.find('#id_name').val(), $this))
159                     return;
160
161                 filex.busy();
162                 $this.modal('hide');
163
164                 $this.find('#id_host').val(filex.host);
165                 $this.find('#id_path').val(filex.path.full());
166
167                 $.post($this.attr('action'), $this.serialize(), function() {
168                     status('Katalog utworzono pomyślnie');
169                     filex.reloadFiles();
170                 }, 'json').fail(failModal('Nie udało się utworzyć katalogu'));
171             });
172
173             $('#rename-form').on('show.bs.modal', function() {
174                 $(this).find('#id_dst').val(filex.selectedFiles()[0].get('name'));
175             }).on('submit', function(e) {
176                 e.preventDefault();
177
178                 var $this = $(this),
179                     path = filex.path.full() + '/',
180                     newName = $this.find('#id_dst').val(),
181                     data = {
182                         host: filex.host,
183                         src: path + filex.selectedFiles()[0].get('name'),
184                         dst: path + newName
185                     };
186
187                 if (conflictingName(newName, $this))
188                     return;
189
190                 filex.busy();
191                 $this.modal('hide');
192
193                 $.post($this.attr('action'), data, function() {
194                     status('Nazwę zmieniono pomyślnie');
195                     filex.reloadFiles();
196                 }, 'json').fail(failModal('Nie udało się zmienić nazwy'));
197             });
198
199             $('#compress-form').on('submit', function(e) {
200                 e.preventDefault();
201
202                 var $this = $(this),
203                     name = $this.find('#id_archive').val(),
204                     type = $this.find('#id_type').val(),
205                     path = filex.path.full(),
206                     archive = name + (name.endsWith(type) ? '' : type),
207                     data = {
208                         host: filex.host,
209                         path: path,
210                         files: _.map(filex.selectedFiles(), function (item) { return item.get('name') }),
211                         archive: path  + '/' + archive
212                     };
213
214                 if (conflictingName(archive, $this))
215                     return;
216
217                 filex.busy();
218                 $this.modal('hide');
219
220                 $.post($this.attr('action'), data, function() {
221                     status('Archiwum utworzono pomyślnie');
222                     filex.reloadFiles();
223                 }, 'json').fail(failModal('Nie udało się utworzyć archiwum'));
224             });
225
226             $('#btn-extract').on('click', function() {
227                 filex.busy();
228
229                 var data = {
230                     host: filex.host,
231                     path: filex.path.full() + '/' + filex.selectedFiles()[0].get('name'),
232                     dst: filex.path.full()
233                 };
234
235                 $.post('{% url 'filex:extract' %}', data, function() {
236                     status('Archiwum rozpakowano pomyślnie');
237                     filex.reloadFiles();
238                 }, 'json').fail(failModal('Nie udało się rozpakować archiwum'));
239             });
240         })
241     </script>
242 {% endblock extra_js %}
243
244 {% block title %}Zarządzanie plikami GridFTP{% endblock %}
245
246 {% block container %}
247     {% include 'filex/source.html' %}
248
249     <div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal-label" aria-hidden="true">
250         <div class="modal-dialog">
251             <div class="modal-content">
252                 <div class="modal-header">
253                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
254                         <span aria-hidden="true">&times;</span>
255                     </button>
256                     <h4 class="modal-title" id="confirm-modal-label">Usuwanie plików</h4>
257                 </div>
258                 <div class="modal-body">
259                     <h4>Czy na pewno usunąć następujące elementy?</h4>
260                     <ul></ul>
261                 </div>
262                 <div class="modal-footer">
263                     <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
264                     <button id="btn-confirm" type="button" class="btn btn-primary">OK</button>
265                 </div>
266             </div>
267         </div>
268     </div>
269
270     <div id="error-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="error-modal-label" aria-hidden="true">
271         <div class="modal-dialog">
272             <div class="modal-content">
273                 <div class="modal-header">
274                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
275                         <span aria-hidden="true">&times;</span>
276                     </button>
277                     <h4 class="modal-title" id="error-modal-label"></h4>
278                 </div>
279                 <div class="modal-body">
280                 </div>
281                 <div class="modal-footer">
282                     <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
283                 </div>
284             </div>
285         </div>
286     </div>
287
288     <form id="mkdir-form" action="{% url 'filex:mkdir' %}" class="modal fade form-horizontal" tabindex="-1" role="dialog" aria-labelledby="mkdir-modal-label" aria-hidden="true">
289         <div class="modal-dialog">
290             <div class="modal-content">
291                 <div class="modal-header">
292                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
293                         <span aria-hidden="true">&times;</span>
294                     </button>
295                     <h4 class="modal-title" id="mkdir-modal-label">Nowy katalog</h4>
296                 </div>
297                 <div class="modal-body">
298                     {% csrf_token %}
299                     {% bootstrap_form new_dir_form layout='horizontal' %}
300                 </div>
301                 <div class="modal-footer">
302                     <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
303                     <button type="submit" class="btn btn-primary">OK</button>
304                 </div>
305             </div>
306         </div>
307     </form>
308
309     <form id="rename-form" action="{% url 'filex:move' %}" class="modal fade form-horizontal" tabindex="-1" role="dialog" aria-labelledby="rename-modal-label" aria-hidden="true">
310         <div class="modal-dialog">
311             <div class="modal-content">
312                 <div class="modal-header">
313                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
314                         <span aria-hidden="true">&times;</span>
315                     </button>
316                     <h4 class="modal-title" id="rename-modal-label">Zmień nazwę</h4>
317                 </div>
318                 <div class="modal-body">
319                     {% csrf_token %}
320                     {% bootstrap_form rename_form layout='horizontal' %}
321                 </div>
322                 <div class="modal-footer">
323                     <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
324                     <button type="submit" class="btn btn-primary">OK</button>
325                 </div>
326             </div>
327         </div>
328     </form>
329
330     <form id="compress-form" action="{% url 'filex:compress' %}" class="modal fade form-horizontal" tabindex="-1" role="dialog" aria-labelledby="compress-modal-label" aria-hidden="true">
331         <div class="modal-dialog">
332             <div class="modal-content">
333                 <div class="modal-header">
334                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
335                         <span aria-hidden="true">&times;</span>
336                     </button>
337                     <h4 class="modal-title" id="compress-modal-label">Podaj nazwę archiwum</h4>
338                 </div>
339                 <div class="modal-body">
340                     {% csrf_token %}
341                     {% bootstrap_form archive_form layout='horizontal' %}
342                 </div>
343                 <div class="modal-footer">
344                     <button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
345                     <button type="submit" class="btn btn-primary">OK</button>
346                 </div>
347             </div>
348         </div>
349     </form>
350 {% endblock container %}
351
352 {% block footer %}
353     <footer class="navbar navbar-default navbar-fixed-bottom" style="position:fixed">
354         <div class="container">
355             <div class="btn-toolbar" role="toolbar" style="float: left">
356                 <div class="btn-group" role="group">
357                     <button id="btn-upload" class="btn btn-default navbar-btn">Wgraj plik</button>
358                     <button class="btn btn-default navbar-btn" data-toggle="modal" data-target="#mkdir-form">Utwórz katalog</button>
359                 </div>
360                 <div class="btn-group" role="group">
361                     <button id="btn-rename" class="btn btn-default navbar-btn disabled" data-toggle="modal" data-target="#rename-form">Zmień nazwę</button>
362                     <button id="btn-delete" class="btn btn-default navbar-btn disabled">Usuń</button>
363                 </div>
364                 <div class="btn-group" role="group">
365                     <button id="btn-compress" class="btn btn-default navbar-btn disabled" data-toggle="modal" data-target="#compress-form">Spakuj</button>
366                     <button id="btn-extract" class="btn btn-default navbar-btn disabled">Rozpakuj</button>
367                 </div>
368             </div>
369             <p id="status" class="navbar-text"></p>
370         </div>
371     </footer>
372 {% endblock footer %}