Skip to content

Commit a753765

Browse files
committed
file DELETE support
1 parent c66cc8d commit a753765

File tree

5 files changed

+142
-0
lines changed

5 files changed

+142
-0
lines changed

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(400);
105+
expect(del_b.code).toEqual(119);
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(400);
118+
expect(del_b2.code).toEqual(119);
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) {

src/Controllers/FilesController.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,26 @@ export class FilesController {
7474
};
7575
}
7676

77+
deleteHandler() {
78+
return (req, res, next) => {
79+
// enforce use of master key for file deletions
80+
if(!req.auth.isMaster){
81+
next(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN,
82+
'Master key required for file deletion.'));
83+
return;
84+
}
85+
86+
this._filesAdapter.deleteFile(req.config, req.params.filename).then(() => {
87+
res.status(200);
88+
// TODO: return useful JSON here?
89+
res.end();
90+
}).catch((error) => {
91+
next(new Parse.Error(Parse.Error.FILE_DELETE_ERROR,
92+
'Could not delete file.'));
93+
});
94+
};
95+
}
96+
7797
/**
7898
* Find file references in REST-format object and adds the url key
7999
* with the current mount point and app id.
@@ -119,6 +139,12 @@ export class FilesController {
119139
this.createHandler()
120140
);
121141

142+
router.delete('/files/:filename',
143+
Middlewares.allowCrossDomain,
144+
Middlewares.handleParseHeaders,
145+
this.deleteHandler()
146+
);
147+
122148
return router;
123149
}
124150
}

0 commit comments

Comments
 (0)