Skip to content

Commit fe5e511

Browse files
committed
Merge pull request #332 from ParsePlatform/nlutsenko.login.files
Fixed missing url for files on user login.
2 parents 3072782 + 053ac99 commit fe5e511

File tree

8 files changed

+86
-65
lines changed

8 files changed

+86
-65
lines changed

spec/ParseUser.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ describe('Parse.User testing', () => {
6464
});
6565
});
6666

67+
it("user login with files", (done) => {
68+
"use strict";
69+
70+
let file = new Parse.File("yolo.txt", [1,2,3], "text/plain");
71+
file.save().then((file) => {
72+
return Parse.User.signUp("asdf", "zxcv", { "file" : file });
73+
}).then(() => {
74+
return Parse.User.logIn("asdf", "zxcv");
75+
}).then((user) => {
76+
let fileAgain = user.get('file');
77+
ok(fileAgain.name());
78+
ok(fileAgain.url());
79+
done();
80+
});
81+
});
82+
6783
it("become", (done) => {
6884
var user = null;
6985
var sessionToken = null;

src/Config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ function Config(applicationId, mount) {
1313

1414
this.applicationId = applicationId;
1515
this.collectionPrefix = cacheInfo.collectionPrefix || '';
16-
this.database = DatabaseAdapter.getDatabaseConnection(applicationId);
1716
this.masterKey = cacheInfo.masterKey;
1817
this.clientKey = cacheInfo.clientKey;
1918
this.javascriptKey = cacheInfo.javascriptKey;
2019
this.dotNetKey = cacheInfo.dotNetKey;
2120
this.restAPIKey = cacheInfo.restAPIKey;
2221
this.fileKey = cacheInfo.fileKey;
2322
this.facebookAppIds = cacheInfo.facebookAppIds;
23+
24+
this.database = DatabaseAdapter.getDatabaseConnection(applicationId);
25+
this.filesController = cacheInfo.filesController;
26+
2427
this.mount = mount;
2528
}
2629

src/Controllers/FilesController.js

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ export class FilesController {
1818
getHandler() {
1919
return (req, res) => {
2020
let config = new Config(req.params.appId);
21-
this._filesAdapter.getFileDataAsync(config, req.params.filename).then((data) => {
21+
let filename = req.params.filename;
22+
this._filesAdapter.getFileDataAsync(config, filename).then((data) => {
2223
res.status(200);
23-
var contentType = mime.lookup(req.params.filename);
24+
var contentType = mime.lookup(filename);
2425
res.set('Content-type', contentType);
2526
res.end(data);
2627
}).catch((error) => {
@@ -63,17 +64,45 @@ export class FilesController {
6364
let filename = rack() + '_' + req.params.filename + extension;
6465
this._filesAdapter.createFileAsync(req.config, filename, req.body).then(() => {
6566
res.status(201);
66-
var location = this._filesAdapter.getFileLocation(req.config, req, filename);
67+
var location = this._filesAdapter.getFileLocation(req.config, filename);
6768
res.set('Location', location);
6869
res.json({ url: location, name: filename });
6970
}).catch((error) => {
70-
console.log(error);
7171
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
7272
'Could not store file.'));
7373
});
7474
};
7575
}
7676

77+
/**
78+
* Find file references in REST-format object and adds the url key
79+
* with the current mount point and app id.
80+
* Object may be a single object or list of REST-format objects.
81+
*/
82+
expandFilesInObject(config, object) {
83+
if (object instanceof Array) {
84+
object.map((obj) => this.expandFilesInObject(config, obj));
85+
return;
86+
}
87+
if (typeof object !== 'object') {
88+
return;
89+
}
90+
for (let key in object) {
91+
let fileObject = object[key];
92+
if (fileObject && fileObject['__type'] === 'File') {
93+
if (fileObject['url']) {
94+
continue;
95+
}
96+
let filename = fileObject['name'];
97+
if (filename.indexOf('tfss-') === 0) {
98+
fileObject['url'] = 'http://files.parsetfss.com/' + config.fileKey + '/' + encodeURIComponent(filename);
99+
} else {
100+
fileObject['url'] = this._filesAdapter.getFileLocation(config, filename);
101+
}
102+
}
103+
}
104+
}
105+
77106
getExpressRouter() {
78107
let router = express.Router();
79108
router.get('/files/:appId/:filename', this.getHandler());

src/FilesAdapter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class FilesAdapter {
1616

1717
getFileDataAsync(config, filename) { }
1818

19-
getFileLocation(config, request, filename) { }
19+
getFileLocation(config, filename) { }
2020
}
2121

2222
export default FilesAdapter;

src/GridStoreAdapter.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
// Requires the database adapter to be based on mongoclient
55

66
import { GridStore } from 'mongodb';
7-
8-
import * as Path from 'path';
97
import { FilesAdapter } from './FilesAdapter';
108

119
class GridStoreAdapter extends FilesAdapter {
@@ -33,10 +31,8 @@ class GridStoreAdapter extends FilesAdapter {
3331
});
3432
}
3533

36-
getFileLocation(config, request, filename) {
37-
return (request.protocol + '://' + request.get('host') +
38-
Path.dirname(request.originalUrl) + '/' + config.applicationId +
39-
'/' + encodeURIComponent(filename));
34+
getFileLocation(config, filename) {
35+
return (config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename));
4036
}
4137
}
4238

src/RestQuery.js

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

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

6+
import { default as FilesController } from './Controllers/FilesController';
7+
68
// restOptions can include:
79
// skip
810
// limit
@@ -316,35 +318,35 @@ RestQuery.prototype.replaceDontSelect = function() {
316318
RestQuery.prototype.runFind = function() {
317319
return this.config.database.find(
318320
this.className, this.restWhere, this.findOptions).then((results) => {
319-
if (this.className == '_User') {
320-
for (var result of results) {
321-
delete result.password;
322-
}
321+
if (this.className == '_User') {
322+
for (var result of results) {
323+
delete result.password;
323324
}
325+
}
324326

325-
updateParseFiles(this.config, results);
327+
this.config.filesController.expandFilesInObject(this.config, results);
326328

327-
if (this.keys) {
328-
var keySet = this.keys;
329-
results = results.map((object) => {
330-
var newObject = {};
331-
for (var key in object) {
332-
if (keySet.has(key)) {
333-
newObject[key] = object[key];
334-
}
329+
if (this.keys) {
330+
var keySet = this.keys;
331+
results = results.map((object) => {
332+
var newObject = {};
333+
for (var key in object) {
334+
if (keySet.has(key)) {
335+
newObject[key] = object[key];
335336
}
336-
return newObject;
337-
});
338-
}
339-
340-
if (this.redirectClassName) {
341-
for (var r of results) {
342-
r.className = this.redirectClassName;
343337
}
338+
return newObject;
339+
});
340+
}
341+
342+
if (this.redirectClassName) {
343+
for (var r of results) {
344+
r.className = this.redirectClassName;
344345
}
346+
}
345347

346-
this.response = {results: results};
347-
});
348+
this.response = {results: results};
349+
});
348350
};
349351

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

500-
// Find file references in REST-format object and adds the url key
501-
// with the current mount point and app id
502-
// Object may be a single object or list of REST-format objects
503-
function updateParseFiles(config, object) {
504-
if (object instanceof Array) {
505-
object.map((obj) => updateParseFiles(config, obj));
506-
return;
507-
}
508-
if (typeof object !== 'object') {
509-
return;
510-
}
511-
for (var key in object) {
512-
if (object[key] && object[key]['__type'] &&
513-
object[key]['__type'] == 'File') {
514-
var filename = object[key]['name'];
515-
var encoded = encodeURIComponent(filename);
516-
encoded = encoded.replace('%40', '@');
517-
if (filename.indexOf('tfss-') === 0) {
518-
object[key]['url'] = 'http://files.parsetfss.com/' +
519-
config.fileKey + '/' + encoded;
520-
} else {
521-
object[key]['url'] = config.mount + '/files/' +
522-
config.applicationId + '/' +
523-
encoded;
524-
}
525-
}
526-
}
527-
}
528-
529502
// Finds a subobject that has the given key, if there is one.
530503
// Returns undefined otherwise.
531504
function findObjectWithKey(root, key) {

src/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ function ParseServer(args) {
6666

6767
}
6868

69+
let filesController = new FilesController(filesAdapter);
70+
6971
cache.apps[args.appId] = {
7072
masterKey: args.masterKey,
7173
collectionPrefix: args.collectionPrefix || '',
@@ -74,7 +76,8 @@ function ParseServer(args) {
7476
dotNetKey: args.dotNetKey || '',
7577
restAPIKey: args.restAPIKey || '',
7678
fileKey: args.fileKey || 'invalid-file-key',
77-
facebookAppIds: args.facebookAppIds || []
79+
facebookAppIds: args.facebookAppIds || [],
80+
filesController: filesController
7881
};
7982

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

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

99101
// TODO: separate this from the regular ParseServer object

src/users.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ function handleLogIn(req) {
5858
user.sessionToken = token;
5959
delete user.password;
6060

61+
req.config.filesController.expandFilesInObject(req.config, user);
62+
6163
var expiresAt = new Date();
6264
expiresAt.setFullYear(expiresAt.getFullYear() + 1);
6365

0 commit comments

Comments
 (0)