mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-19 16:14:39 +00:00
bugfix (dropbox): issue #3: migrate to dropbox api v2
This commit is contained in:
+112
-98
@@ -3,22 +3,17 @@ var http = require('request-promise'),
|
||||
http_stream = require('request'),
|
||||
Path = require('path'),
|
||||
config = require('../../../config'),
|
||||
toString = require('stream-to-string');
|
||||
toString = require('stream-to-string'),
|
||||
Readable = require('stream').Readable;
|
||||
|
||||
|
||||
function query(params, uri, method = 'GET', data){
|
||||
let opts = {
|
||||
headers: {
|
||||
'Authorization': 'Bearer '+params.bearer,
|
||||
},
|
||||
uri: uri,
|
||||
method: method
|
||||
};
|
||||
if(method === 'POST'){
|
||||
opts.form = data;
|
||||
}else if(method === 'PUT'){
|
||||
opts.body = data;
|
||||
opts.headers['Content-Length'] = data.length
|
||||
function query(params, uri, method = 'GET', data, opts = {}){
|
||||
if(!opts.headers) opts.headers = {};
|
||||
opts.headers['Authorization'] = 'Bearer '+params.bearer;
|
||||
opts.uri = uri;
|
||||
opts.method = method;
|
||||
if(data && typeof data === 'object'){
|
||||
opts.body = JSON.stringify(data);
|
||||
opts.headers["Content-Type"] = "application/json";
|
||||
}
|
||||
return http(opts)
|
||||
.then((res) => Promise.resolve(JSON.parse(res)))
|
||||
@@ -30,117 +25,136 @@ function query(params, uri, method = 'GET', data){
|
||||
}
|
||||
})
|
||||
}
|
||||
function query_stream(params, uri, method = 'GET', data){
|
||||
let opts = {
|
||||
headers: {
|
||||
'Authorization': 'Bearer '+params.bearer,
|
||||
},
|
||||
uri: uri,
|
||||
method: method
|
||||
};
|
||||
if(method === 'POST'){
|
||||
opts.form = data;
|
||||
}else if(method === 'PUT'){
|
||||
opts.body = data;
|
||||
opts.headers['Content-Length'] = data.length
|
||||
}
|
||||
function query_stream(params, uri, method = 'GET', data, opts = {}){
|
||||
if(!opts.headers) opts.headers = {};
|
||||
opts.headers['Authorization'] = 'Bearer '+params.bearer;
|
||||
opts.uri = uri;
|
||||
opts.method = method;
|
||||
opts.body = data;
|
||||
return Promise.resolve(http_stream(opts));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
auth: function(params){
|
||||
let url = "https://www.dropbox.com/1/oauth2/authorize?client_id="+config.dropbox.clientID+"&response_type=token&redirect_uri="+config.dropbox.redirectURI+"&state=dropbox"
|
||||
let url = "https://www.dropbox.com/oauth2/authorize?client_id="+config.dropbox.clientID+"&response_type=token&redirect_uri="+config.dropbox.redirectURI+"&state=dropbox"
|
||||
return Promise.resolve(url)
|
||||
},
|
||||
test: function(params){
|
||||
return query(params, "https://api.dropboxapi.com/1/account/info")
|
||||
return query(params, "https://api.dropboxapi.com/2/users/get_current_account", "POST")
|
||||
.then((opts) => Promise.resolve(params))
|
||||
.catch((err) => Promise.reject(err.response.body));
|
||||
.catch((err) => Promise.reject({message: err && err.message || err, code: "NOT_AUTHENTICATED"}))
|
||||
},
|
||||
cat: function(path, params){
|
||||
return query_stream(params, "https://content.dropboxapi.com/1/files/auto/"+path)
|
||||
return query_stream(params, "https://content.dropboxapi.com/2/files/download", "POST", null, {
|
||||
headers: {
|
||||
"Dropbox-API-Arg": JSON.stringify({path: path})
|
||||
}
|
||||
}).then((res) => {
|
||||
// dropbox send silly mimetype like 'application/octet-stream' for pdf files ...
|
||||
// We can't trust them on this, so we get rid of it. In our case, it will be set by the file controller
|
||||
const newRes = res.on('response', function(res) {
|
||||
delete res.headers['content-type'];
|
||||
});
|
||||
return Promise.resolve(newRes);
|
||||
})
|
||||
},
|
||||
ls: function(path, params){
|
||||
return query(params, "https://api.dropboxapi.com/1/metadata/auto/"+path)
|
||||
if(path === '/') path = '';
|
||||
return query(params, "https://api.dropboxapi.com/2/files/list_folder", "POST", {path: path, recursive: false, include_deleted: false, include_media_info: true})
|
||||
.then((res) => {
|
||||
let files = res.contents.map((file) => {
|
||||
let files = res.entries.map((file) => {
|
||||
let tmp = {
|
||||
size: file.bytes,
|
||||
time: new Date(file.modified).getTime(),
|
||||
type: file.is_dir? 'directory' : 'file',
|
||||
name: file.path.split('/').slice(-1)[0]
|
||||
size: file.size,
|
||||
time: new Date(file.client_modified).getTime(),
|
||||
type: file['.tag'] === 'file' ? 'file' : 'directory',
|
||||
name: file.name
|
||||
};
|
||||
if(file.read_only){
|
||||
tmp.can_move = false;
|
||||
tmp.can_delete = false;
|
||||
}
|
||||
return tmp;
|
||||
});
|
||||
if(res.read_only === true){
|
||||
files.push({type: 'metadata', name: './', can_create_file: false, can_create_directory: false});
|
||||
}
|
||||
return Promise.resolve(files);
|
||||
})
|
||||
});
|
||||
},
|
||||
write: function(path, content, params){
|
||||
return process(path, content, params)
|
||||
.then((res) => retryOnError(res, path, content, params, 5))
|
||||
.then((res) => verifyDropbox(res, path, params, 10))
|
||||
|
||||
function process(path, content, params){
|
||||
return query_stream(params, "https://content.dropboxapi.com/1/files_put/auto/"+path, "PUT", content)
|
||||
.then(toString)
|
||||
}
|
||||
function retryOnError(body, path, content, params, n = 5){
|
||||
body = JSON.parse(body);
|
||||
|
||||
if(body && body.error){
|
||||
return sleep(Math.abs(5 - n) * 1000)
|
||||
.then(() => process(path, content, params, n -1))
|
||||
}else{
|
||||
return Promise.resolve(body);
|
||||
}
|
||||
}
|
||||
function verifyDropbox(keep, path, params, n = 10){
|
||||
return sleep(Math.abs(10 - n) * 300)
|
||||
.then(() => query(params, "https://api.dropboxapi.com/1/metadata/auto/"+Path.dirname(path)))
|
||||
.then((res) => {
|
||||
let found = res.contents.find((function(file){
|
||||
return file.path === path? true : false
|
||||
}));
|
||||
if(found){
|
||||
return Promise.resolve(keep)
|
||||
}else{
|
||||
if(n > 0){
|
||||
return verifyDropbox(keep, path, params, n - 1)
|
||||
}else{
|
||||
return Promise.reject({message: 'dropbox didn\' create the file or was taking too long to do so', code: 'DROPBOX_WRITE_ERROR'})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
function sleep(t=1000, arg){
|
||||
return new Promise((done) => {
|
||||
setTimeout(function(){
|
||||
done(arg);
|
||||
}, t)
|
||||
})
|
||||
}
|
||||
return write_file(path, content, params);
|
||||
},
|
||||
rm: function(path, params){
|
||||
return query(params, "https://api.dropboxapi.com/1/fileops/delete", "POST", {root: 'auto', path: path})
|
||||
.then((res) => Promise.resolve('ok'))
|
||||
return query(params, "https://api.dropboxapi.com/2/files/delete_v2", "POST", {path: path})
|
||||
.then((res) => Promise.resolve('ok'));
|
||||
},
|
||||
mv: function(from, to, params){
|
||||
return query(params, "https://api.dropboxapi.com/1/fileops/move", "POST", {root: 'auto', from_path: from, to_path: to})
|
||||
.catch(err => Promise.reject({message: JSON.parse(err).error, code: "DROPBOX_MOVE"}))
|
||||
return query(params, "https://api.dropboxapi.com/2/files/move_v2", "POST", {from_path: from, to_path: to})
|
||||
.then((res) => verifyDropbox(res, to, params, 10))
|
||||
.catch(err => Promise.reject({message: JSON.parse(err).error, code: "DROPBOX_MOVE"}));
|
||||
},
|
||||
mkdir: function(path, params){
|
||||
return query(params, "https://api.dropboxapi.com/1/fileops/create_folder", "POST", {root: 'auto', path: path})
|
||||
.then((res) => Promise.resolve('ok'))
|
||||
path = path.replace(/\/$/, '');
|
||||
return query(params, "https://api.dropboxapi.com/2/files/create_folder_v2", "POST", {path: path, autorename: false})
|
||||
.then((res) => verifyDropbox(res, path, params, 10))
|
||||
.then((res) => Promise.resolve('ok'));
|
||||
},
|
||||
touch: function(path, params){
|
||||
return query(params, "https://content.dropboxapi.com/1/files_put/auto/"+path, "PUT", '')
|
||||
.then((res) => Promise.resolve('ok'));
|
||||
var stream = new Readable(); stream.push(''); stream.push(null);
|
||||
return write_file(path, stream, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function write_file(path, content, params){
|
||||
return process(path, content, params)
|
||||
.then((res) => retryOnError(res, path, content, params, 5))
|
||||
.then((res) => verifyDropbox(res, path, params, 10))
|
||||
|
||||
function process(path, content, params){
|
||||
return query_stream(params, "https://content.dropboxapi.com/2/files/upload", "POST", content, {
|
||||
headers: {
|
||||
"Dropbox-API-Arg": JSON.stringify({
|
||||
path: path,
|
||||
autorename: false,
|
||||
mode: "overwrite"
|
||||
}),
|
||||
"Content-Type": "application/octet-stream"
|
||||
}
|
||||
}).then(toString)
|
||||
}
|
||||
function retryOnError(body, path, content, params, n = 5){
|
||||
body = JSON.parse(body);
|
||||
if(body && body.error){
|
||||
return sleep(Math.abs(5 - n) * 1000)
|
||||
.then(() => process(path, content, params, n -1))
|
||||
}else{
|
||||
return Promise.resolve(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function verifyDropbox(keep, path, params, n = 10){
|
||||
let folder_path = Path.dirname(path).replace(/\/$/, '');
|
||||
if(folder_path === '.'){
|
||||
folder_path = '';
|
||||
}
|
||||
return sleep(Math.abs(10 - n) * 300)
|
||||
.then(() => query(params, "https://api.dropboxapi.com/2/files/list_folder", "POST", {path: folder_path, recursive: false, include_deleted: false, include_media_info: true}))
|
||||
.then((res) => {
|
||||
let found = res.entries.find((function(file){
|
||||
return file.path_display === path? true : false
|
||||
}));
|
||||
if(found){
|
||||
return Promise.resolve(keep)
|
||||
}else{
|
||||
if(n > 0){
|
||||
return verifyDropbox(keep, path, params, n - 1)
|
||||
}else{
|
||||
return Promise.reject({message: 'dropbox didn\' create the file or was taking too long to do so', code: 'DROPBOX_WRITE_ERROR'})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
function sleep(t=1000, arg){
|
||||
return new Promise((done) => {
|
||||
setTimeout(function(){
|
||||
done(arg);
|
||||
}, t)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user