Skip to content

Fixed missing url for files on user login. #332

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 2 commits into from
Feb 10, 2016
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
16 changes: 16 additions & 0 deletions spec/ParseUser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ describe('Parse.User testing', () => {
});
});

it("user login with files", (done) => {
"use strict";

let file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
file.save().then((file) => {
return Parse.User.signUp("asdf", "zxcv", { "file" : file });
}).then(() => {
return Parse.User.logIn("asdf", "zxcv");
}).then((user) => {
let fileAgain = user.get('file');
ok(fileAgain.name());
ok(fileAgain.url());
done();
});
});

it("become", (done) => {
var user = null;
var sessionToken = null;
Expand Down
5 changes: 4 additions & 1 deletion src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ function Config(applicationId, mount) {

this.applicationId = applicationId;
this.collectionPrefix = cacheInfo.collectionPrefix || '';
this.database = DatabaseAdapter.getDatabaseConnection(applicationId);
this.masterKey = cacheInfo.masterKey;
this.clientKey = cacheInfo.clientKey;
this.javascriptKey = cacheInfo.javascriptKey;
this.dotNetKey = cacheInfo.dotNetKey;
this.restAPIKey = cacheInfo.restAPIKey;
this.fileKey = cacheInfo.fileKey;
this.facebookAppIds = cacheInfo.facebookAppIds;

this.database = DatabaseAdapter.getDatabaseConnection(applicationId);
this.filesController = cacheInfo.filesController;

this.mount = mount;
}

Expand Down
37 changes: 33 additions & 4 deletions src/Controllers/FilesController.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ export class FilesController {
getHandler() {
return (req, res) => {
let config = new Config(req.params.appId);
this._filesAdapter.getFileDataAsync(config, req.params.filename).then((data) => {
let filename = req.params.filename;
this._filesAdapter.getFileDataAsync(config, filename).then((data) => {
res.status(200);
var contentType = mime.lookup(req.params.filename);
var contentType = mime.lookup(filename);
res.set('Content-type', contentType);
res.end(data);
}).catch((error) => {
Expand Down Expand Up @@ -63,17 +64,45 @@ export class FilesController {
let filename = rack() + '_' + req.params.filename + extension;
this._filesAdapter.createFileAsync(req.config, filename, req.body).then(() => {
res.status(201);
var location = this._filesAdapter.getFileLocation(req.config, req, filename);
var location = this._filesAdapter.getFileLocation(req.config, filename);
res.set('Location', location);
res.json({ url: location, name: filename });
}).catch((error) => {
console.log(error);
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
'Could not store file.'));
});
};
}

/**
* Find file references in REST-format object and adds the url key
* with the current mount point and app id.
* Object may be a single object or list of REST-format objects.
*/
expandFilesInObject(config, object) {
if (object instanceof Array) {
object.map((obj) => this.expandFilesInObject(config, obj));
return;
}
if (typeof object !== 'object') {
return;
}
for (let key in object) {
let fileObject = object[key];
if (fileObject && fileObject['__type'] === 'File') {
if (fileObject['url']) {
continue;
}
let filename = fileObject['name'];
if (filename.indexOf('tfss-') === 0) {
fileObject['url'] = 'http://files.parsetfss.com/' + config.fileKey + '/' + encodeURIComponent(filename);
} else {
fileObject['url'] = this._filesAdapter.getFileLocation(config, filename);
}
}
}
}

getExpressRouter() {
let router = express.Router();
router.get('/files/:appId/:filename', this.getHandler());
Expand Down
2 changes: 1 addition & 1 deletion src/FilesAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class FilesAdapter {

getFileDataAsync(config, filename) { }

getFileLocation(config, request, filename) { }
getFileLocation(config, filename) { }
}

export default FilesAdapter;
8 changes: 2 additions & 6 deletions src/GridStoreAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
// Requires the database adapter to be based on mongoclient

import { GridStore } from 'mongodb';

import * as Path from 'path';
import { FilesAdapter } from './FilesAdapter';

class GridStoreAdapter extends FilesAdapter {
Expand Down Expand Up @@ -33,10 +31,8 @@ class GridStoreAdapter extends FilesAdapter {
});
}

getFileLocation(config, request, filename) {
return (request.protocol + '://' + request.get('host') +
Path.dirname(request.originalUrl) + '/' + config.applicationId +
'/' + encodeURIComponent(filename));
getFileLocation(config, filename) {
return (config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename));
}
}

Expand Down
75 changes: 24 additions & 51 deletions src/RestQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

var Parse = require('parse/node').Parse;

import { default as FilesController } from './Controllers/FilesController';

// restOptions can include:
// skip
// limit
Expand Down Expand Up @@ -316,35 +318,35 @@ RestQuery.prototype.replaceDontSelect = function() {
RestQuery.prototype.runFind = function() {
return this.config.database.find(
this.className, this.restWhere, this.findOptions).then((results) => {
if (this.className == '_User') {
for (var result of results) {
delete result.password;
}
if (this.className == '_User') {
for (var result of results) {
delete result.password;
}
}

updateParseFiles(this.config, results);
this.config.filesController.expandFilesInObject(this.config, results);

if (this.keys) {
var keySet = this.keys;
results = results.map((object) => {
var newObject = {};
for (var key in object) {
if (keySet.has(key)) {
newObject[key] = object[key];
}
if (this.keys) {
var keySet = this.keys;
results = results.map((object) => {
var newObject = {};
for (var key in object) {
if (keySet.has(key)) {
newObject[key] = object[key];
}
return newObject;
});
}

if (this.redirectClassName) {
for (var r of results) {
r.className = this.redirectClassName;
}
return newObject;
});
}

if (this.redirectClassName) {
for (var r of results) {
r.className = this.redirectClassName;
}
}

this.response = {results: results};
});
this.response = {results: results};
});
};

// Returns a promise for whether it was successful.
Expand Down Expand Up @@ -497,35 +499,6 @@ function replacePointers(object, path, replace) {
return answer;
}

// Find file references in REST-format object and adds the url key
// with the current mount point and app id
// Object may be a single object or list of REST-format objects
function updateParseFiles(config, object) {
if (object instanceof Array) {
object.map((obj) => updateParseFiles(config, obj));
return;
}
if (typeof object !== 'object') {
return;
}
for (var key in object) {
if (object[key] && object[key]['__type'] &&
object[key]['__type'] == 'File') {
var filename = object[key]['name'];
var encoded = encodeURIComponent(filename);
encoded = encoded.replace('%40', '@');
if (filename.indexOf('tfss-') === 0) {
object[key]['url'] = 'http://files.parsetfss.com/' +
config.fileKey + '/' + encoded;
} else {
object[key]['url'] = config.mount + '/files/' +
config.applicationId + '/' +
encoded;
}
}
}
}

// Finds a subobject that has the given key, if there is one.
// Returns undefined otherwise.
function findObjectWithKey(root, key) {
Expand Down
6 changes: 4 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ function ParseServer(args) {

}

let filesController = new FilesController(filesAdapter);

cache.apps[args.appId] = {
masterKey: args.masterKey,
collectionPrefix: args.collectionPrefix || '',
Expand All @@ -74,7 +76,8 @@ function ParseServer(args) {
dotNetKey: args.dotNetKey || '',
restAPIKey: args.restAPIKey || '',
fileKey: args.fileKey || 'invalid-file-key',
facebookAppIds: args.facebookAppIds || []
facebookAppIds: args.facebookAppIds || [],
filesController: filesController
};

// To maintain compatibility. TODO: Remove in v2.1
Expand All @@ -93,7 +96,6 @@ function ParseServer(args) {
var api = express();

// File handling needs to be before default middlewares are applied
let filesController = new FilesController(filesAdapter);
api.use('/', filesController.getExpressRouter());

// TODO: separate this from the regular ParseServer object
Expand Down
2 changes: 2 additions & 0 deletions src/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ function handleLogIn(req) {
user.sessionToken = token;
delete user.password;

req.config.filesController.expandFilesInObject(req.config, user);

var expiresAt = new Date();
expiresAt.setFullYear(expiresAt.getFullYear() + 1);

Expand Down