Skip to content

Commit dd36493

Browse files
authored
Saving files with sessionToken (#1057)
Closes: #1049 A small optimization with saving files in saveAll. Clean up deferred promises.
1 parent 77e4068 commit dd36493

File tree

8 files changed

+92
-28
lines changed

8 files changed

+92
-28
lines changed

src/ParseFile.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ class ParseFile {
208208
* * Valid options are:<ul>
209209
* <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
210210
* be used for this request.
211+
* <li>sessionToken: A valid session token, used for making a request on
212+
* behalf of a specific user.
211213
* <li>progress: In Browser only, callback for upload progress
212214
* </ul>
213215
* @return {Promise} Promise that is resolved when the save finishes.
@@ -323,7 +325,7 @@ class ParseFile {
323325
}
324326

325327
const DefaultController = {
326-
saveFile: function(name: string, source: FileSource, options?: FullOptions) {
328+
saveFile: async function(name: string, source: FileSource, options?: FullOptions) {
327329
if (source.format !== 'file') {
328330
throw new Error('saveFile can only be used with File-type sources.');
329331
}
@@ -336,6 +338,15 @@ const DefaultController = {
336338
if (jsKey) {
337339
headers['X-Parse-JavaScript-Key'] = jsKey;
338340
}
341+
let sessionToken = options.sessionToken;
342+
const userController = CoreManager.getUserController();
343+
if (!sessionToken && userController) {
344+
const currentUser = await userController.currentUserAsync();
345+
sessionToken = currentUser ? currentUser.getSessionToken() : undefined;
346+
}
347+
if (sessionToken) {
348+
headers['X-Parse-Session-Token'] = sessionToken;
349+
}
339350
let url = CoreManager.get('SERVER_URL');
340351
if (url[url.length - 1] !== '/') {
341352
url += '/';

src/ParseObject.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import ParseACL from './ParseACL';
1919
import parseDate from './parseDate';
2020
import ParseError from './ParseError';
2121
import ParseFile from './ParseFile';
22-
import { when, continueWhile } from './promiseUtils';
22+
import { when, continueWhile, resolvingPromise } from './promiseUtils';
2323
import { DEFAULT_PIN, PIN_PREFIX } from './LocalDatastoreUtils';
2424

2525
import {
@@ -2236,19 +2236,17 @@ const DefaultController = {
22362236
}
22372237
unsaved = unique(unsaved);
22382238

2239-
let filesSaved = Promise.resolve();
2239+
const filesSaved: Array<ParseFile> = [];
22402240
let pending: Array<ParseObject> = [];
22412241
unsaved.forEach((el) => {
22422242
if (el instanceof ParseFile) {
2243-
filesSaved = filesSaved.then(() => {
2244-
return el.save();
2245-
});
2243+
filesSaved.push(el.save());
22462244
} else if (el instanceof ParseObject) {
22472245
pending.push(el);
22482246
}
22492247
});
22502248

2251-
return filesSaved.then(() => {
2249+
return Promise.all(filesSaved).then(() => {
22522250
let objectError = null;
22532251
return continueWhile(() => {
22542252
return pending.length > 0;
@@ -2274,17 +2272,11 @@ const DefaultController = {
22742272

22752273
// Queue up tasks for each object in the batch.
22762274
// When every task is ready, the API request will execute
2277-
let res, rej;
2278-
const batchReturned = new Promise((resolve, reject) => { res = resolve; rej = reject; });
2279-
batchReturned.resolve = res;
2280-
batchReturned.reject = rej;
2275+
const batchReturned = new resolvingPromise();
22812276
const batchReady = [];
22822277
const batchTasks = [];
22832278
batch.forEach((obj, index) => {
2284-
let res, rej;
2285-
const ready = new Promise((resolve, reject) => { res = resolve; rej = reject; });
2286-
ready.resolve = res;
2287-
ready.reject = rej;
2279+
const ready = new resolvingPromise();
22882280
batchReady.push(ready);
22892281
const task = function() {
22902282
ready.resolve();

src/RESTController.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/* global XMLHttpRequest, XDomainRequest */
1212
import CoreManager from './CoreManager';
1313
import ParseError from './ParseError';
14+
import { resolvingPromise } from './promiseUtils';
1415

1516
export type RequestOptions = {
1617
useMasterKey?: boolean;
@@ -90,11 +91,7 @@ const RESTController = {
9091
if (useXDomainRequest) {
9192
return ajaxIE9(method, url, data, headers, options);
9293
}
93-
94-
let res, rej;
95-
const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; });
96-
promise.resolve = res;
97-
promise.reject = rej;
94+
const promise = resolvingPromise();
9895
let attempts = 0;
9996

10097
const dispatch = function() {

src/TaskQueue.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*
99
* @flow
1010
*/
11+
import { resolvingPromise } from './promiseUtils';
1112

1213
type Task = {
1314
task: () => Promise;
@@ -22,14 +23,7 @@ class TaskQueue {
2223
}
2324

2425
enqueue(task: () => Promise): Promise {
25-
let res;
26-
let rej;
27-
const taskComplete = new Promise((resolve, reject) => {
28-
res = resolve;
29-
rej = reject;
30-
});
31-
taskComplete.resolve = res;
32-
taskComplete.reject = rej;
26+
const taskComplete = new resolvingPromise();
3327
this.queue.push({
3428
task: task,
3529
_completion: taskComplete

src/__tests__/ParseFile-test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,4 +546,71 @@ describe('FileController', () => {
546546
expect(data).toBe('ParseA==');
547547
spy.mockRestore();
548548
});
549+
550+
it('saves files via ajax with sessionToken option', () => {
551+
const request = function(method, path) {
552+
const name = path.substr(path.indexOf('/') + 1);
553+
return Promise.resolve({
554+
name: name,
555+
url: 'https://files.parsetfss.com/a/' + name
556+
});
557+
};
558+
const ajax = function(method, path, data, headers) {
559+
expect(headers['X-Parse-Session-Token']).toBe('testing_sessionToken')
560+
const name = path.substr(path.indexOf('/') + 1);
561+
return Promise.resolve({
562+
response: {
563+
name: name,
564+
url: 'https://files.parsetfss.com/a/' + name
565+
}
566+
});
567+
};
568+
CoreManager.setRESTController({ request, ajax });
569+
const file = new ParseFile('parse.txt', [61, 170, 236, 120]);
570+
file._source.format = 'file';
571+
572+
return file.save({ sessionToken: 'testing_sessionToken' }).then(function(f) {
573+
expect(f).toBe(file);
574+
expect(f.name()).toBe('/api.parse.com/1/files/parse.txt');
575+
expect(f.url()).toBe('https://files.parsetfss.com/a//api.parse.com/1/files/parse.txt');
576+
});
577+
});
578+
579+
it('saves files via ajax currentUser sessionToken', () => {
580+
CoreManager.set('UserController', {
581+
currentUserAsync() {
582+
return Promise.resolve({
583+
getSessionToken() {
584+
return 'currentUserToken';
585+
}
586+
});
587+
}
588+
});
589+
const request = function(method, path) {
590+
const name = path.substr(path.indexOf('/') + 1);
591+
return Promise.resolve({
592+
name: name,
593+
url: 'https://files.parsetfss.com/a/' + name
594+
});
595+
};
596+
const ajax = function(method, path, data, headers) {
597+
expect(headers['X-Parse-Session-Token']).toBe('currentUserToken')
598+
const name = path.substr(path.indexOf('/') + 1);
599+
return Promise.resolve({
600+
response: {
601+
name: name,
602+
url: 'https://files.parsetfss.com/a/' + name
603+
}
604+
});
605+
};
606+
CoreManager.setRESTController({ request, ajax });
607+
const file = new ParseFile('parse.txt', [61, 170, 236, 120]);
608+
file._source.format = 'file';
609+
610+
return file.save().then(function(f) {
611+
expect(f).toBe(file);
612+
expect(f.name()).toBe('/api.parse.com/1/files/parse.txt');
613+
expect(f.url()).toBe('https://files.parsetfss.com/a//api.parse.com/1/files/parse.txt');
614+
});
615+
});
549616
});

src/__tests__/ParseUser-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jest.dontMock('../ParseError');
2020
jest.dontMock('../ParseObject');
2121
jest.dontMock('../ParseOp');
2222
jest.dontMock('../ParseUser');
23+
jest.dontMock('../promiseUtils');
2324
jest.dontMock('../RESTController');
2425
jest.dontMock('../SingleInstanceStateController');
2526
jest.dontMock('../Storage');

src/__tests__/SingleInstanceStateController-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jest.dontMock('../ObjectStateMutations');
1313
jest.dontMock('../ParseFile');
1414
jest.dontMock('../ParseGeoPoint');
1515
jest.dontMock('../ParseOp');
16+
jest.dontMock('../promiseUtils');
1617
jest.dontMock('../SingleInstanceStateController');
1718
jest.dontMock('../TaskQueue');
1819

src/promiseUtils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Create Deferred Promise
12
export function resolvingPromise() {
23
let res;
34
let rej;

0 commit comments

Comments
 (0)