Skip to content

Commit a008622

Browse files
committed
Re-implement Dropbox#getItemURL
1 parent cb65deb commit a008622

File tree

4 files changed

+90
-17
lines changed

4 files changed

+90
-17
lines changed

doc/getting-started/dropbox-and-google-drive.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Known issues
4949
* Listing and deleting folders with more than 10000 files will cause problems
5050
* Content-Type is not fully supported due to limitations of the Dropbox API
5151
* Dropbox preserves cases but is not case-sensitive
52-
* ``getItemURL`` is not implemented yet (see issue :issue:`1052`)
52+
* ``getItemURL`` works only for files which exist and are public
5353

5454
Google Drive
5555
------------

doc/js-api/base-client.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,9 @@ Other functions
430430
:short-name:
431431

432432
.. WARNING::
433-
This method currently only works for remoteStorage
434-
backends. The issues for implementing it for Dropbox and Google
435-
Drive can be found at :issue:`1052` and :issue:`1054`.
433+
This method currently only works for remoteStorage and Dropbox backends.
434+
The issue for implementing it for Google Drive can be found at
435+
:issue:`1054`.
436436

437437
.. autofunction:: BaseClient#scope(path)
438438
:short-name:

src/dropbox.js

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ var getDropboxPath = function (path) {
6060
return cleanPath(PATH_PREFIX + '/' + path).replace(/\/$/, '');
6161
};
6262

63+
const isPublicPath = path => path.match(/^\/public\/.*[^/]$/);
64+
6365
var compareApiError = function (response, expect) {
6466
return new RegExp('^' + expect.join('\\/') + '(\\/|$)').test(response.error_summary);
6567
};
@@ -573,26 +575,52 @@ Dropbox.prototype = {
573575
return this._deleteSimple(path);
574576
},
575577

578+
/**
579+
* Retrieve full, absolute URL of an item. Items which are non-public or do
580+
* not exist always resolve to undefined.
581+
*
582+
* @returns {Promise} - resolves to an absolute URL of the item
583+
*
584+
* @protected
585+
*/
586+
getItemURL: function (path) {
587+
if (!isPublicPath(path)) {
588+
return Promise.resolve(undefined);
589+
}
590+
591+
let url = this._itemRefs[path];
592+
if (url !== undefined) {
593+
return Promise.resolve(url);
594+
}
595+
596+
return this._getSharedLink(path).then((link) => {
597+
if (link !== undefined) {
598+
return link;
599+
}
600+
return this._share(path);
601+
});
602+
},
603+
576604
/**
577605
* Calls share, if the provided path resides in a public folder.
578606
*
579607
* @private
580608
*/
581609
_shareIfNeeded: function (path) {
582-
if (path.match(/^\/public\/.*[^/]$/) && this._itemRefs[path] === undefined) {
583-
this.share(path);
610+
if (isPublicPath(path) && this._itemRefs[path] === undefined) {
611+
this._share(path);
584612
}
585613
},
586614

587615
/**
588616
* Gets a publicly-accessible URL for the path from Dropbox and stores it
589-
* in ``_itemRefs``.
617+
* in ``_itemRefs``. Resolves to undefined if the path does not exist.
590618
*
591619
* @return {Promise} a promise for the URL
592620
*
593621
* @private
594622
*/
595-
share: function (path) {
623+
_share: function (path) {
596624
var url = 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings';
597625
var options = {
598626
body: {path: getDropboxPath(path)}
@@ -615,6 +643,9 @@ Dropbox.prototype = {
615643
if (compareApiError(body, ['shared_link_already_exists'])) {
616644
return this._getSharedLink(path);
617645
}
646+
if (compareApiError(body, ['path', 'not_found'])) {
647+
return Promise.resolve(undefined);
648+
}
618649

619650
return Promise.reject(new Error('API error: ' + body.error_summary));
620651
}
@@ -978,7 +1009,8 @@ Dropbox.prototype = {
9781009
},
9791010

9801011
/**
981-
* Requests the link for an already-shared file or folder.
1012+
* Requests the link for a shared file or folder. Resolves to undefined if
1013+
* the requested file or folder has not bee shared.
9821014
*
9831015
* @param {string} path - path to the file or folder
9841016
*
@@ -1000,7 +1032,8 @@ Dropbox.prototype = {
10001032
return Promise.reject(new Error('Invalid response status: ' + response.status));
10011033
}
10021034

1003-
var body;
1035+
let body;
1036+
let link;
10041037

10051038
try {
10061039
body = JSON.parse(response.responseText);
@@ -1009,14 +1042,16 @@ Dropbox.prototype = {
10091042
}
10101043

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

1015-
if (!body.links.length) {
1016-
return Promise.reject(new Error('No links returned'));
1051+
if (body.links.length) {
1052+
link = body.links[0].url;
10171053
}
1018-
1019-
return Promise.resolve(body.links[0].url);
1054+
return Promise.resolve(link);
10201055
}, (error) => {
10211056
error.message = 'Could not get link to a shared file or folder ("' + path + '"): ' + error.message;
10221057
return Promise.reject(error);
@@ -1064,9 +1099,7 @@ function unHookSync(rs) {
10641099
function hookGetItemURL (rs) {
10651100
if (rs._origBaseClientGetItemURL) { return; }
10661101
rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;
1067-
BaseClient.prototype.getItemURL = function (/*path*/) {
1068-
throw new Error('getItemURL is not implemented for Dropbox yet');
1069-
};
1102+
BaseClient.prototype.getItemURL = rs.dropbox.getItemURL.bind(rs.dropbox);
10701103
}
10711104

10721105
/**

test/unit/dropbox-suite.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,46 @@ define(['require', './src/util', './src/dropbox', './src/wireclient',
791791
}
792792
},
793793

794+
{
795+
desc: "#getItemURL returns from cache",
796+
run: function (env, test) {
797+
env.connectedClient._itemRefs['/public/foo'] = 'http://example.com/public/foo';
798+
env.connectedClient.getItemURL('/public/foo').then((itemURL) => {
799+
test.assert(itemURL, 'http://example.com/public/foo');
800+
});
801+
}
802+
},
803+
804+
{
805+
desc: "#getItemURL creates shared link if it does not exist",
806+
run: function (env, test) {
807+
env.connectedClient.getItemURL('/public/foo').then((itemURL) => {
808+
test.assert(itemURL, 'http://example.com/public/foo');
809+
});
810+
811+
setTimeout(() => {
812+
mockRequestSuccess({
813+
status: 200,
814+
responseText: JSON.stringify({
815+
links: []
816+
})
817+
});
818+
}, 10);
819+
820+
setTimeout(() => {
821+
test.assertAnd(getMockRequestUrl(), 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings');
822+
823+
mockRequestSuccess({
824+
status: 200,
825+
responseText: JSON.stringify({
826+
'.tag': 'file',
827+
url: 'http://example.com/public/foo',
828+
})
829+
});
830+
}, 20);
831+
}
832+
},
833+
794834
{
795835
desc: "requests are aborted if they aren't responded after the configured timeout",
796836
timeout: 2000,

0 commit comments

Comments
 (0)