Skip to content

Commit

Permalink
Re-implement Dropbox#getItemURL
Browse files Browse the repository at this point in the history
  • Loading branch information
Ragnis committed Jun 2, 2018
1 parent 30a80b2 commit 8ec6a83
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 17 deletions.
2 changes: 1 addition & 1 deletion doc/getting-started/dropbox-and-google-drive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Known issues
* Listing and deleting folders with more than 10000 files will cause problems
* Content-Type is not fully supported due to limitations of the Dropbox API
* Dropbox preserves cases but is not case-sensitive
* ``getItemURL`` is not implemented yet (see issue :issue:`1052`)
* ``getItemURL`` works only for files which exist and are public

Google Drive
------------
Expand Down
6 changes: 3 additions & 3 deletions doc/js-api/base-client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,9 @@ Other functions
:short-name:

.. WARNING::
This method currently only works for remoteStorage
backends. The issues for implementing it for Dropbox and Google
Drive can be found at :issue:`1052` and :issue:`1054`.
This method currently only works for remoteStorage and Dropbox backends.
The issue for implementing it for Google Drive can be found at
:issue:`1054`.

.. autofunction:: BaseClient#scope(path)
:short-name:
59 changes: 46 additions & 13 deletions src/dropbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ var getDropboxPath = function (path) {
return cleanPath(PATH_PREFIX + '/' + path).replace(/\/$/, '');
};

const isPublicPath = path => path.match(/^\/public\/.*[^/]$/);

var compareApiError = function (response, expect) {
return new RegExp('^' + expect.join('\\/') + '(\\/|$)').test(response.error_summary);
};
Expand Down Expand Up @@ -575,26 +577,52 @@ Dropbox.prototype = {
return this._deleteSimple(path);
},

/**
* Retrieve full, absolute URL of an item. Items which are non-public or do
* not exist always resolve to undefined.
*
* @returns {Promise} - resolves to an absolute URL of the item
*
* @protected
*/
getItemURL: function (path) {
if (!isPublicPath(path)) {
return Promise.resolve(undefined);
}

let url = this._itemRefs[path];
if (url !== undefined) {
return Promise.resolve(url);
}

return this._getSharedLink(path).then((link) => {
if (link !== undefined) {
return link;
}
return this._share(path);
});
},

/**
* Calls share, if the provided path resides in a public folder.
*
* @private
*/
_shareIfNeeded: function (path) {
if (path.match(/^\/public\/.*[^/]$/) && this._itemRefs[path] === undefined) {
this.share(path);
if (isPublicPath(path) && this._itemRefs[path] === undefined) {
this._share(path);
}
},

/**
* Gets a publicly-accessible URL for the path from Dropbox and stores it
* in ``_itemRefs``.
* in ``_itemRefs``. Resolves to undefined if the path does not exist.
*
* @return {Promise} a promise for the URL
*
* @private
*/
share: function (path) {
_share: function (path) {
var url = 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings';
var options = {
body: {path: getDropboxPath(path)}
Expand All @@ -617,6 +645,9 @@ Dropbox.prototype = {
if (compareApiError(body, ['shared_link_already_exists'])) {
return this._getSharedLink(path);
}
if (compareApiError(body, ['path', 'not_found'])) {
return Promise.resolve(undefined);
}

return Promise.reject(new Error('API error: ' + body.error_summary));
}
Expand Down Expand Up @@ -980,7 +1011,8 @@ Dropbox.prototype = {
},

/**
* Requests the link for an already-shared file or folder.
* Requests the link for a shared file or folder. Resolves to undefined if
* the requested file or folder has not bee shared.
*
* @param {string} path - path to the file or folder
*
Expand All @@ -1002,7 +1034,8 @@ Dropbox.prototype = {
return Promise.reject(new Error('Invalid response status: ' + response.status));
}

var body;
let body;
let link;

try {
body = JSON.parse(response.responseText);
Expand All @@ -1011,14 +1044,16 @@ Dropbox.prototype = {
}

if (response.status === 409) {
if (compareApiError(body, ['path', 'not_found'])) {
return Promise.resolve(undefined);
}
return Promise.reject(new Error('API error: ' + response.error_summary));
}

if (!body.links.length) {
return Promise.reject(new Error('No links returned'));
if (body.links.length) {
link = body.links[0].url;
}

return Promise.resolve(body.links[0].url);
return Promise.resolve(link);
}, (error) => {
error.message = 'Could not get link to a shared file or folder ("' + path + '"): ' + error.message;
return Promise.reject(error);
Expand Down Expand Up @@ -1066,9 +1101,7 @@ function unHookSync(rs) {
function hookGetItemURL (rs) {
if (rs._origBaseClientGetItemURL) { return; }
rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;
BaseClient.prototype.getItemURL = function (/*path*/) {
throw new Error('getItemURL is not implemented for Dropbox yet');
};
BaseClient.prototype.getItemURL = rs.dropbox.getItemURL.bind(rs.dropbox);
}

/**
Expand Down
39 changes: 39 additions & 0 deletions test/unit/dropbox-suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,45 @@ define(['require', './src/util', './src/dropbox', './src/wireclient',
}
},

{
desc: "#getItemURL returns from cache",
run: function (env, test) {
env.connectedClient._itemRefs['/public/foo'] = 'http://example.com/public/foo';
env.connectedClient.getItemURL('/public/foo').then((itemURL) => {
test.assert(itemURL, 'http://example.com/public/foo');
});
}
},

{
desc: "#getItemURL creates shared link if it does not exist",
run: function (env, test) {
env.connectedClient.getItemURL('/public/foo').then((itemURL) => {
test.assert(itemURL, 'http://example.com/public/foo');
});

setTimeout(() => {
let req = XMLHttpRequest.instances.shift();
test.assertFail(req, undefined);
req.status = 200;
req.responseText = JSON.stringify({ links: [] });
req._onload();
}, 10);

setTimeout(() => {
req = XMLHttpRequest.instances.shift();
test.assertFail(req, undefined);
test.assertAnd(req.url, 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings');
req.status = 200;
req.responseText = JSON.stringify({
'.tag': 'file',
url: 'http://example.com/public/foo',
});
req._onload();
}, 20);
}
},

{
desc: "requests are aborted if they aren't responded after the configured timeout",
timeout: 2000,
Expand Down

0 comments on commit 8ec6a83

Please sign in to comment.