Skip to content

Commit 175d16a

Browse files
author
Francis Lessard
committed
Merge branch 'master' into session-token
# Conflicts: # src/users.js
2 parents 5655253 + 5efb759 commit 175d16a

20 files changed

+879
-160
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ The client keys used with Parse are no longer necessary with parse-server. If y
3838

3939
#### Advanced options:
4040

41-
* filesAdapter - The default behavior (GridStore) can be changed by creating an adapter class (see `FilesAdapter.js`)
41+
* filesAdapter - The default behavior (GridStore) can be changed by creating an adapter class (see [`FilesAdapter.js`](https://github.com/ParsePlatform/parse-server/blob/master/src/Adapters/Files/FilesAdapter.js))
4242
* databaseAdapter (unfinished) - The backing store can be changed by creating an adapter class (see `DatabaseAdapter.js`)
43+
* loggerAdapter - The default behavior/transport (File) can be changed by creating an adapter class (see [`LoggerAdapter.js`](https://github.com/ParsePlatform/parse-server/blob/master/src/Adapters/Logger/LoggerAdapter.js))
4344

4445
---
4546

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"node-gcm": "^0.14.0",
2424
"parse": "^1.7.0",
2525
"randomstring": "^1.1.3",
26-
"request": "^2.65.0"
26+
"request": "^2.65.0",
27+
"winston": "^2.1.1"
2728
},
2829
"devDependencies": {
2930
"babel-cli": "^6.5.1",

spec/FileLoggerAdapter.spec.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
2+
var Parse = require('parse/node').Parse;
3+
var request = require('request');
4+
var fs = require('fs');
5+
6+
var LOGS_FOLDER = './test_logs/';
7+
8+
var deleteFolderRecursive = function(path) {
9+
if( fs.existsSync(path) ) {
10+
fs.readdirSync(path).forEach(function(file,index){
11+
var curPath = path + "/" + file;
12+
if(fs.lstatSync(curPath).isDirectory()) { // recurse
13+
deleteFolderRecursive(curPath);
14+
} else { // delete file
15+
fs.unlinkSync(curPath);
16+
}
17+
});
18+
fs.rmdirSync(path);
19+
}
20+
};
21+
22+
describe('info logs', () => {
23+
24+
afterEach((done) => {
25+
deleteFolderRecursive(LOGS_FOLDER);
26+
done();
27+
});
28+
29+
it("Verify INFO logs", (done) => {
30+
var fileLoggerAdapter = new FileLoggerAdapter({
31+
logsFolder: LOGS_FOLDER
32+
});
33+
fileLoggerAdapter.info('testing info logs', () => {
34+
fileLoggerAdapter.query({
35+
size: 1,
36+
level: 'info'
37+
}, (results) => {
38+
expect(results[0].message).toEqual('testing info logs');
39+
done();
40+
});
41+
});
42+
});
43+
});
44+
45+
describe('error logs', () => {
46+
47+
afterEach((done) => {
48+
deleteFolderRecursive(LOGS_FOLDER);
49+
done();
50+
});
51+
52+
it("Verify ERROR logs", (done) => {
53+
var fileLoggerAdapter = new FileLoggerAdapter();
54+
fileLoggerAdapter.error('testing error logs', () => {
55+
fileLoggerAdapter.query({
56+
size: 1,
57+
level: 'error'
58+
}, (results) => {
59+
expect(results[0].message).toEqual('testing error logs');
60+
done();
61+
});
62+
});
63+
});
64+
});

spec/LoggerController.spec.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
var LoggerController = require('../src/Controllers/LoggerController').LoggerController;
2+
var FileLoggerAdapter = require('../src/Adapters/Logger/FileLoggerAdapter').FileLoggerAdapter;
3+
4+
describe('LoggerController', () => {
5+
it('can check valid master key of request', (done) => {
6+
// Make mock request
7+
var request = {
8+
auth: {
9+
isMaster: true
10+
},
11+
query: {}
12+
};
13+
14+
var loggerController = new LoggerController(new FileLoggerAdapter());
15+
16+
expect(() => {
17+
loggerController.handleGET(request);
18+
}).not.toThrow();
19+
done();
20+
});
21+
22+
it('can check invalid construction of controller', (done) => {
23+
// Make mock request
24+
var request = {
25+
auth: {
26+
isMaster: true
27+
},
28+
query: {}
29+
};
30+
31+
var loggerController = new LoggerController();
32+
33+
expect(() => {
34+
loggerController.handleGET(request);
35+
}).toThrow();
36+
done();
37+
});
38+
39+
it('can check invalid master key of request', (done) => {
40+
// Make mock request
41+
var request = {
42+
auth: {
43+
isMaster: false
44+
},
45+
query: {}
46+
};
47+
48+
var loggerController = new LoggerController(new FileLoggerAdapter());
49+
50+
expect(() => {
51+
loggerController.handleGET(request);
52+
}).toThrow();
53+
done();
54+
});
55+
});

spec/ParseFile.spec.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,95 @@ describe('Parse.File testing', () => {
3333
});
3434
});
3535

36+
it('supports REST end-to-end file create, read, delete, read', done => {
37+
var headers = {
38+
'Content-Type': 'image/jpeg',
39+
'X-Parse-Application-Id': 'test',
40+
'X-Parse-REST-API-Key': 'rest'
41+
};
42+
request.post({
43+
headers: headers,
44+
url: 'http://localhost:8378/1/files/testfile.txt',
45+
body: 'check one two',
46+
}, (error, response, body) => {
47+
expect(error).toBe(null);
48+
var b = JSON.parse(body);
49+
expect(b.name).toMatch(/_testfile.txt$/);
50+
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*testfile.txt$/);
51+
request.get(b.url, (error, response, body) => {
52+
expect(error).toBe(null);
53+
expect(body).toEqual('check one two');
54+
request.del({
55+
headers: {
56+
'X-Parse-Application-Id': 'test',
57+
'X-Parse-REST-API-Key': 'rest',
58+
'X-Parse-Master-Key': 'test'
59+
},
60+
url: 'http://localhost:8378/1/files/' + b.name
61+
}, (error, response, body) => {
62+
expect(error).toBe(null);
63+
expect(response.statusCode).toEqual(200);
64+
request.get({
65+
headers: {
66+
'X-Parse-Application-Id': 'test',
67+
'X-Parse-REST-API-Key': 'rest'
68+
},
69+
url: b.url
70+
}, (error, response, body) => {
71+
expect(error).toBe(null);
72+
expect(response.statusCode).toEqual(404);
73+
done();
74+
});
75+
});
76+
});
77+
});
78+
});
79+
80+
it('blocks file deletions with missing or incorrect master-key header', done => {
81+
var headers = {
82+
'Content-Type': 'image/jpeg',
83+
'X-Parse-Application-Id': 'test',
84+
'X-Parse-REST-API-Key': 'rest'
85+
};
86+
request.post({
87+
headers: headers,
88+
url: 'http://localhost:8378/1/files/thefile.jpg',
89+
body: 'the file body'
90+
}, (error, response, body) => {
91+
expect(error).toBe(null);
92+
var b = JSON.parse(body);
93+
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*thefile.jpg$/);
94+
// missing X-Parse-Master-Key header
95+
request.del({
96+
headers: {
97+
'X-Parse-Application-Id': 'test',
98+
'X-Parse-REST-API-Key': 'rest'
99+
},
100+
url: 'http://localhost:8378/1/files/' + b.name
101+
}, (error, response, body) => {
102+
expect(error).toBe(null);
103+
var del_b = JSON.parse(body);
104+
expect(response.statusCode).toEqual(403);
105+
expect(del_b.error).toMatch(/unauthorized/);
106+
// incorrect X-Parse-Master-Key header
107+
request.del({
108+
headers: {
109+
'X-Parse-Application-Id': 'test',
110+
'X-Parse-REST-API-Key': 'rest',
111+
'X-Parse-Master-Key': 'tryagain'
112+
},
113+
url: 'http://localhost:8378/1/files/' + b.name
114+
}, (error, response, body) => {
115+
expect(error).toBe(null);
116+
var del_b2 = JSON.parse(body);
117+
expect(response.statusCode).toEqual(403);
118+
expect(del_b2.error).toMatch(/unauthorized/);
119+
done();
120+
});
121+
});
122+
});
123+
});
124+
36125
it('handles other filetypes', done => {
37126
var headers = {
38127
'Content-Type': 'image/jpeg',

src/Adapters/Files/FilesAdapter.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
export class FilesAdapter {
1515
createFile(config, filename, data) { }
1616

17+
deleteFile(config, filename) { }
18+
1719
getFileData(config, filename) { }
1820

1921
getFileLocation(config, filename) { }

src/Adapters/Files/GridStoreAdapter.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ export class GridStoreAdapter extends FilesAdapter {
2020
});
2121
}
2222

23+
deleteFile(config, filename) {
24+
return config.database.connect().then(() => {
25+
let gridStore = new GridStore(config.database.db, filename, 'w');
26+
return gridStore.open();
27+
}).then((gridStore) => {
28+
return gridStore.unlink();
29+
}).then((gridStore) => {
30+
return gridStore.close();
31+
});
32+
}
33+
2334
getFileData(config, filename) {
2435
return config.database.connect().then(() => {
2536
return GridStore.exist(config.database.db, filename);

src/Adapters/Files/S3Adapter.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ export class S3Adapter extends FilesAdapter {
5656
});
5757
}
5858

59+
deleteFile(config, filename) {
60+
return new Promise((resolve, reject) => {
61+
let params = {
62+
Key: this._bucketPrefix + filename
63+
};
64+
this._s3Client.deleteObject(params, (err, data) =>{
65+
if(err !== null) {
66+
return reject(err);
67+
}
68+
resolve(data);
69+
});
70+
});
71+
}
72+
5973
// Search for and return a file if found by filename
6074
// Returns a promise that succeeds with the buffer result from S3
6175
getFileData(config, filename) {

0 commit comments

Comments
 (0)