Skip to content

Saving files with sessionToken #1057

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/ParseFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class ParseFile {
* * Valid options are:<ul>
* <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
* be used for this request.
* <li>sessionToken: A valid session token, used for making a request on
* behalf of a specific user.
* <li>progress: In Browser only, callback for upload progress
* </ul>
* @return {Promise} Promise that is resolved when the save finishes.
Expand Down Expand Up @@ -323,7 +325,7 @@ class ParseFile {
}

const DefaultController = {
saveFile: function(name: string, source: FileSource, options?: FullOptions) {
saveFile: async function(name: string, source: FileSource, options?: FullOptions) {
if (source.format !== 'file') {
throw new Error('saveFile can only be used with File-type sources.');
}
Expand All @@ -336,6 +338,15 @@ const DefaultController = {
if (jsKey) {
headers['X-Parse-JavaScript-Key'] = jsKey;
}
let sessionToken = options.sessionToken;
const userController = CoreManager.getUserController();
if (!sessionToken && userController) {
const currentUser = await userController.currentUserAsync();
sessionToken = currentUser ? currentUser.getSessionToken() : undefined;
}
if (sessionToken) {
headers['X-Parse-Session-Token'] = sessionToken;
}
let url = CoreManager.get('SERVER_URL');
if (url[url.length - 1] !== '/') {
url += '/';
Expand Down
20 changes: 6 additions & 14 deletions src/ParseObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import ParseACL from './ParseACL';
import parseDate from './parseDate';
import ParseError from './ParseError';
import ParseFile from './ParseFile';
import { when, continueWhile } from './promiseUtils';
import { when, continueWhile, resolvingPromise } from './promiseUtils';
import { DEFAULT_PIN, PIN_PREFIX } from './LocalDatastoreUtils';

import {
Expand Down Expand Up @@ -2236,19 +2236,17 @@ const DefaultController = {
}
unsaved = unique(unsaved);

let filesSaved = Promise.resolve();
const filesSaved: Array<ParseFile> = [];
let pending: Array<ParseObject> = [];
unsaved.forEach((el) => {
if (el instanceof ParseFile) {
filesSaved = filesSaved.then(() => {
return el.save();
});
filesSaved.push(el.save());
} else if (el instanceof ParseObject) {
pending.push(el);
}
});

return filesSaved.then(() => {
return Promise.all(filesSaved).then(() => {
let objectError = null;
return continueWhile(() => {
return pending.length > 0;
Expand All @@ -2274,17 +2272,11 @@ const DefaultController = {

// Queue up tasks for each object in the batch.
// When every task is ready, the API request will execute
let res, rej;
const batchReturned = new Promise((resolve, reject) => { res = resolve; rej = reject; });
batchReturned.resolve = res;
batchReturned.reject = rej;
const batchReturned = new resolvingPromise();
const batchReady = [];
const batchTasks = [];
batch.forEach((obj, index) => {
let res, rej;
const ready = new Promise((resolve, reject) => { res = resolve; rej = reject; });
ready.resolve = res;
ready.reject = rej;
const ready = new resolvingPromise();
batchReady.push(ready);
const task = function() {
ready.resolve();
Expand Down
7 changes: 2 additions & 5 deletions src/RESTController.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/* global XMLHttpRequest, XDomainRequest */
import CoreManager from './CoreManager';
import ParseError from './ParseError';
import { resolvingPromise } from './promiseUtils';

export type RequestOptions = {
useMasterKey?: boolean;
Expand Down Expand Up @@ -90,11 +91,7 @@ const RESTController = {
if (useXDomainRequest) {
return ajaxIE9(method, url, data, headers, options);
}

let res, rej;
const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; });
promise.resolve = res;
promise.reject = rej;
const promise = resolvingPromise();
let attempts = 0;

const dispatch = function() {
Expand Down
10 changes: 2 additions & 8 deletions src/TaskQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
* @flow
*/
import { resolvingPromise } from './promiseUtils';

type Task = {
task: () => Promise;
Expand All @@ -22,14 +23,7 @@ class TaskQueue {
}

enqueue(task: () => Promise): Promise {
let res;
let rej;
const taskComplete = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
taskComplete.resolve = res;
taskComplete.reject = rej;
const taskComplete = new resolvingPromise();
this.queue.push({
task: task,
_completion: taskComplete
Expand Down
67 changes: 67 additions & 0 deletions src/__tests__/ParseFile-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,4 +546,71 @@ describe('FileController', () => {
expect(data).toBe('ParseA==');
spy.mockRestore();
});

it('saves files via ajax with sessionToken option', () => {
const request = function(method, path) {
const name = path.substr(path.indexOf('/') + 1);
return Promise.resolve({
name: name,
url: 'https://files.parsetfss.com/a/' + name
});
};
const ajax = function(method, path, data, headers) {
expect(headers['X-Parse-Session-Token']).toBe('testing_sessionToken')
const name = path.substr(path.indexOf('/') + 1);
return Promise.resolve({
response: {
name: name,
url: 'https://files.parsetfss.com/a/' + name
}
});
};
CoreManager.setRESTController({ request, ajax });
const file = new ParseFile('parse.txt', [61, 170, 236, 120]);
file._source.format = 'file';

return file.save({ sessionToken: 'testing_sessionToken' }).then(function(f) {
expect(f).toBe(file);
expect(f.name()).toBe('/api.parse.com/1/files/parse.txt');
expect(f.url()).toBe('https://files.parsetfss.com/a//api.parse.com/1/files/parse.txt');
});
});

it('saves files via ajax currentUser sessionToken', () => {
CoreManager.set('UserController', {
currentUserAsync() {
return Promise.resolve({
getSessionToken() {
return 'currentUserToken';
}
});
}
});
const request = function(method, path) {
const name = path.substr(path.indexOf('/') + 1);
return Promise.resolve({
name: name,
url: 'https://files.parsetfss.com/a/' + name
});
};
const ajax = function(method, path, data, headers) {
expect(headers['X-Parse-Session-Token']).toBe('currentUserToken')
const name = path.substr(path.indexOf('/') + 1);
return Promise.resolve({
response: {
name: name,
url: 'https://files.parsetfss.com/a/' + name
}
});
};
CoreManager.setRESTController({ request, ajax });
const file = new ParseFile('parse.txt', [61, 170, 236, 120]);
file._source.format = 'file';

return file.save().then(function(f) {
expect(f).toBe(file);
expect(f.name()).toBe('/api.parse.com/1/files/parse.txt');
expect(f.url()).toBe('https://files.parsetfss.com/a//api.parse.com/1/files/parse.txt');
});
});
});
1 change: 1 addition & 0 deletions src/__tests__/ParseUser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jest.dontMock('../ParseError');
jest.dontMock('../ParseObject');
jest.dontMock('../ParseOp');
jest.dontMock('../ParseUser');
jest.dontMock('../promiseUtils');
jest.dontMock('../RESTController');
jest.dontMock('../SingleInstanceStateController');
jest.dontMock('../Storage');
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/SingleInstanceStateController-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jest.dontMock('../ObjectStateMutations');
jest.dontMock('../ParseFile');
jest.dontMock('../ParseGeoPoint');
jest.dontMock('../ParseOp');
jest.dontMock('../promiseUtils');
jest.dontMock('../SingleInstanceStateController');
jest.dontMock('../TaskQueue');

Expand Down
1 change: 1 addition & 0 deletions src/promiseUtils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Create Deferred Promise
export function resolvingPromise() {
let res;
let rej;
Expand Down