]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blame - frontend/js/app.js
Use accessTokens instead of username/password
[perso/Immae/Projets/Nodejs/Surfer.git] / frontend / js / app.js
CommitLineData
6eb72d64
JZ
1(function () {
2'use strict';
3
4a27fce7
JZ
4function getProfile(accessToken, callback) {
5 callback = callback || function (error) { if (error) console.error(error); };
6
7 superagent.get('/api/profile').query({ access_token: accessToken }).end(function (error, result) {
8 app.busy = false;
9
10 if (error && !error.response) return callback(error);
11 if (result.statusCode !== 200) {
12 delete localStorage.accessToken;
13 return callback('Invalid access token');
14 }
15
16 localStorage.accessToken = accessToken;
17 app.session.username = result.body.username;
18 app.session.valid = true;
19
20 callback();
21 });
22}
23
6eb72d64
JZ
24function login(username, password) {
25 username = username || app.loginData.username;
26 password = password || app.loginData.password;
27
28 app.busy = true;
29
4a27fce7 30 superagent.post('/api/login').query({ username: username, password: password }).end(function (error, result) {
6eb72d64
JZ
31 app.busy = false;
32
33 if (error) return console.error(error);
34 if (result.statusCode === 401) return console.error('Invalid credentials');
35
4a27fce7
JZ
36 getProfile(result.body.accessToken, function (error) {
37 if (error) return console.error(error);
d3312ed1 38
4a27fce7
JZ
39 loadDirectory(window.location.hash.slice(1));
40 });
6eb72d64
JZ
41 });
42}
43
44function logout() {
4a27fce7
JZ
45 superagent.post('/api/logout').query({ access_token: localStorage.accessToken }).end(function (error) {
46 if (error) console.error(error);
47
48 app.session.valid = false;
6eb72d64 49
4a27fce7
JZ
50 delete localStorage.accessToken;
51 });
6eb72d64
JZ
52}
53
d3312ed1
JZ
54function sanitize(filePath) {
55 filePath = '/' + filePath;
56 return filePath.replace(/\/+/g, '/');
57}
58
537bfb04
JZ
59function encode(filePath) {
60 return filePath.split('/').map(encodeURIComponent).join('/');
61}
62
04bc2989
JZ
63function decode(filePath) {
64 return filePath.split('/').map(decodeURIComponent).join('/');
65}
66
a26d1f9b
JZ
67var mimeTypes = {
68 images: [ '.png', '.jpg', '.jpeg', '.tiff', '.gif' ],
69 text: [ '.txt', '.md' ],
70 pdf: [ '.pdf' ],
71 html: [ '.html', '.htm', '.php' ],
72 video: [ '.mp4', '.mpg', '.mpeg', '.ogg', '.mkv' ]
73};
74
75function getPreviewUrl(entry, basePath) {
76 var path = '/_admin/img/';
77
78 if (entry.isDirectory) return path + 'directory.png';
79 if (mimeTypes.images.some(function (e) { return entry.filePath.endsWith(e); })) return sanitize(basePath + '/' + entry.filePath);
80 if (mimeTypes.text.some(function (e) { return entry.filePath.endsWith(e); })) return path +'text.png';
81 if (mimeTypes.pdf.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'pdf.png';
82 if (mimeTypes.html.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'html.png';
83 if (mimeTypes.video.some(function (e) { return entry.filePath.endsWith(e); })) return path + 'video.png';
84
85 return path + 'unknown.png';
86}
87
537bfb04
JZ
88function refresh() {
89 loadDirectory(app.path);
90}
91
d3312ed1
JZ
92function loadDirectory(filePath) {
93 app.busy = true;
94
95 filePath = filePath ? sanitize(filePath) : '/';
96
4a27fce7 97 superagent.get('/api/files/' + encode(filePath)).query({ access_token: localStorage.accessToken }).end(function (error, result) {
d3312ed1
JZ
98 app.busy = false;
99
9209abec 100 if (result && result.statusCode === 401) return logout();
d3312ed1 101 if (error) return console.error(error);
d3312ed1 102
04bc2989 103 result.body.entries.sort(function (a, b) { return a.isDirectory && b.isFile ? -1 : 1; });
a26d1f9b
JZ
104 app.entries = result.body.entries.map(function (entry) {
105 entry.previewUrl = getPreviewUrl(entry, filePath);
106 return entry;
107 });
d3312ed1 108 app.path = filePath;
51723cdf
J
109 app.pathParts = decode(filePath).split('/').filter(function (e) { return !!e; }).map(function (e, i, a) {
110 return {
111 name: e,
112 link: '#' + sanitize('/' + a.slice(0, i).join('/') + '/' + e)
113 };
114 });
04bc2989
JZ
115
116 // update in case this was triggered from code
117 window.location.hash = app.path;
3e98fb0c
JZ
118
119 Vue.nextTick(function () {
120 $(function () {
121 $('[data-toggle="tooltip"]').tooltip();
122 });
123 });
d3312ed1
JZ
124 });
125}
126
127function open(entry) {
5f43935e 128 var path = sanitize(app.path + '/' + entry.filePath);
d3312ed1 129
04bc2989
JZ
130 if (entry.isDirectory) {
131 window.location.hash = path;
132 return;
133 }
d3312ed1 134
5f43935e 135 window.open(encode(path));
d3312ed1
JZ
136}
137
138function up() {
5f43935e 139 window.location.hash = sanitize(app.path.split('/').slice(0, -1).filter(function (p) { return !!p; }).join('/'));
d3312ed1
JZ
140}
141
b094fada
JZ
142function uploadFiles(files) {
143 if (!files || !files.length) return;
144
145 app.uploadStatus = {
146 busy: true,
147 count: files.length,
148 done: 0,
149 percentDone: 0
150 };
151
152 function uploadFile(file) {
153 var path = encode(sanitize(app.path + '/' + file.name));
154
155 var formData = new FormData();
156 formData.append('file', file);
157
4a27fce7 158 superagent.post('/api/files' + path).query({ access_token: localStorage.accessToken }).send(formData).end(function (error, result) {
b094fada
JZ
159 if (result && result.statusCode === 401) return logout();
160 if (result && result.statusCode !== 201) console.error('Error uploading file: ', result.statusCode);
161 if (error) console.error(error);
162
163 app.uploadStatus.done += 1;
164 app.uploadStatus.percentDone = Math.round(app.uploadStatus.done / app.uploadStatus.count * 100);
165
166 if (app.uploadStatus.done >= app.uploadStatus.count) {
167 app.uploadStatus = {
168 busy: false,
169 count: 0,
170 done: 0,
171 percentDone: 100
172 };
173
174 refresh();
175 }
176 });
177 }
178
179 for(var i = 0; i < app.uploadStatus.count; ++i) {
180 uploadFile(files[i]);
181 }
182}
183
537bfb04 184function upload() {
403359cf 185 $(app.$els.upload).on('change', function () {
537bfb04 186
403359cf
JZ
187 // detach event handler
188 $(app.$els.upload).off('change');
189
b094fada 190 uploadFiles(app.$els.upload.files || []);
537bfb04
JZ
191 });
192
e41fd8d8
JZ
193 // reset the form first to make the change handler retrigger even on the same file selected
194 $('#fileUploadForm')[0].reset();
195
537bfb04
JZ
196 app.$els.upload.click();
197}
198
9138d7d4
JZ
199function delAsk(entry) {
200 $('#modalDelete').modal('show');
201 app.deleteData = entry;
202}
203
204function del(entry) {
205 app.busy = true;
206
207 var path = encode(sanitize(app.path + '/' + entry.filePath));
208
4a27fce7 209 superagent.del('/api/files' + path).query({ access_token: localStorage.accessToken, recursive: true }).end(function (error, result) {
9138d7d4
JZ
210 app.busy = false;
211
9209abec
JZ
212 if (result && result.statusCode === 401) return logout();
213 if (result && result.statusCode !== 200) return console.error('Error deleting file: ', result.statusCode);
9138d7d4 214 if (error) return console.error(error);
9138d7d4
JZ
215
216 refresh();
217
218 $('#modalDelete').modal('hide');
219 });
220}
221
e628921a
JZ
222function renameAsk(entry) {
223 app.renameData.entry = entry;
224 app.renameData.error = null;
225 app.renameData.newFilePath = entry.filePath;
226
227 $('#modalRename').modal('show');
228}
229
230function rename(data) {
231 app.busy = true;
232
233 var path = encode(sanitize(app.path + '/' + data.entry.filePath));
234 var newFilePath = sanitize(app.path + '/' + data.newFilePath);
235
4a27fce7 236 superagent.put('/api/files' + path).query({ access_token: localStorage.accessToken }).send({ newFilePath: newFilePath }).end(function (error, result) {
e628921a
JZ
237 app.busy = false;
238
239 if (result && result.statusCode === 401) return logout();
240 if (result && result.statusCode !== 200) return console.error('Error renaming file: ', result.statusCode);
241 if (error) return console.error(error);
242
243 refresh();
244
245 $('#modalRename').modal('hide');
246 });
247}
248
403359cf
JZ
249function createDirectoryAsk() {
250 $('#modalcreateDirectory').modal('show');
251 app.createDirectoryData = '';
9209abec 252 app.createDirectoryError = null;
403359cf
JZ
253}
254
255function createDirectory(name) {
256 app.busy = true;
9209abec 257 app.createDirectoryError = null;
403359cf
JZ
258
259 var path = encode(sanitize(app.path + '/' + name));
260
4a27fce7 261 superagent.post('/api/files' + path).query({ access_token: localStorage.accessToken, directory: true }).end(function (error, result) {
403359cf
JZ
262 app.busy = false;
263
9209abec
JZ
264 if (result && result.statusCode === 401) return logout();
265 if (result && result.statusCode === 403) {
266 app.createDirectoryError = 'Name not allowed';
267 return;
268 }
269 if (result && result.statusCode === 409) {
270 app.createDirectoryError = 'Directory already exists';
271 return;
272 }
273 if (result && result.statusCode !== 201) return console.error('Error creating directory: ', result.statusCode);
403359cf 274 if (error) return console.error(error);
403359cf
JZ
275
276 app.createDirectoryData = '';
277 refresh();
278
279 $('#modalcreateDirectory').modal('hide');
280 });
281}
282
b094fada
JZ
283function dragOver(event) {
284 event.preventDefault();
285}
286
287function drop(event) {
288 event.preventDefault();
289 uploadFiles(event.dataTransfer.files || []);
290}
291
235212c4
JZ
292Vue.filter('prettyDate', function (value) {
293 var d = new Date(value);
294 return d.toDateString();
295});
296
8fce52f8
JZ
297Vue.filter('prettyFileSize', function (value) {
298 return filesize(value);
299});
300
6eb72d64
JZ
301var app = new Vue({
302 el: '#app',
303 data: {
304 busy: true,
fea6789c
JZ
305 uploadStatus: {
306 busy: false,
307 count: 0,
308 done: 0,
309 percentDone: 50
310 },
d3312ed1
JZ
311 path: '/',
312 pathParts: [],
6eb72d64
JZ
313 session: {
314 valid: false
315 },
d3312ed1 316 loginData: {},
9138d7d4 317 deleteData: {},
e628921a
JZ
318 renameData: {
319 entry: {},
320 error: null,
321 newFilePath: ''
322 },
403359cf 323 createDirectoryData: '',
9209abec 324 createDirectoryError: null,
d3312ed1 325 entries: []
6eb72d64
JZ
326 },
327 methods: {
328 login: login,
d3312ed1
JZ
329 logout: logout,
330 loadDirectory: loadDirectory,
331 open: open,
537bfb04 332 up: up,
9138d7d4
JZ
333 upload: upload,
334 delAsk: delAsk,
403359cf 335 del: del,
e628921a
JZ
336 renameAsk: renameAsk,
337 rename: rename,
403359cf 338 createDirectoryAsk: createDirectoryAsk,
b094fada
JZ
339 createDirectory: createDirectory,
340 drop: drop,
341 dragOver: dragOver
6eb72d64
JZ
342 }
343});
344
9209abec
JZ
345window.app = app;
346
4a27fce7 347getProfile(localStorage.accessToken);
6eb72d64 348
04bc2989
JZ
349$(window).on('hashchange', function () {
350 loadDirectory(window.location.hash.slice(1));
351});
352
9209abec
JZ
353// setup all the dialog focus handling
354['modalcreateDirectory'].forEach(function (id) {
355 $('#' + id).on('shown.bs.modal', function () {
356 $(this).find("[autofocus]:first").focus();
357 });
358});
359
6eb72d64 360})();