Endpoint for purging all objects in class (#2032)
* Endpoint for purging all objects in class * Use deleteObjectsByQuery * Standalone handling function and purge cache * Change endpoint url
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
var DatabaseAdapter = require('../src/DatabaseAdapter');
|
||||
const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
|
||||
var request = require('request');
|
||||
const rp = require('request-promise');
|
||||
const Parse = require("parse/node");
|
||||
let Config = require('../src/Config');
|
||||
let defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
|
||||
@@ -1347,4 +1348,111 @@ describe('miscellaneous', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('purge all objects in class', (done) => {
|
||||
let object = new Parse.Object('TestObject');
|
||||
object.set('foo', 'bar');
|
||||
let object2 = new Parse.Object('TestObject');
|
||||
object2.set('alice', 'wonderland');
|
||||
Parse.Object.saveAll([object, object2])
|
||||
.then(() => {
|
||||
let query = new Parse.Query(TestObject);
|
||||
return query.count()
|
||||
}).then((count) => {
|
||||
expect(count).toBe(2);
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': 'test',
|
||||
'X-Parse-Master-Key': 'test'
|
||||
};
|
||||
request.del({
|
||||
headers: headers,
|
||||
url: 'http://localhost:8378/1/purge/TestObject',
|
||||
json: true
|
||||
}, (err, res, body) => {
|
||||
expect(err).toBe(null);
|
||||
let query = new Parse.Query(TestObject);
|
||||
return query.count().then((count) => {
|
||||
expect(count).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('fail on purge all objects in class without master key', (done) => {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': 'test',
|
||||
'X-Parse-REST-API-Key': 'rest'
|
||||
};
|
||||
rp({
|
||||
method: 'DELETE',
|
||||
headers: headers,
|
||||
uri: 'http://localhost:8378/1/purge/TestObject',
|
||||
json: true
|
||||
}).then(body => {
|
||||
fail('Should not succeed');
|
||||
}).catch(err => {
|
||||
expect(err.error.error).toEqual('unauthorized: master key is required');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('purge all objects in _Role also purge cache', (done) => {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': 'test',
|
||||
'X-Parse-Master-Key': 'test'
|
||||
};
|
||||
var user, object;
|
||||
createTestUser().then((x) => {
|
||||
user = x;
|
||||
let acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(false);
|
||||
let role = new Parse.Object('_Role');
|
||||
role.set('name', 'TestRole');
|
||||
role.setACL(acl);
|
||||
let users = role.relation('users');
|
||||
users.add(user);
|
||||
return role.save({}, { useMasterKey: true });
|
||||
}).then((x) => {
|
||||
let query = new Parse.Query('_Role');
|
||||
return query.find({ useMasterKey: true });
|
||||
}).then((x) => {
|
||||
expect(x.length).toEqual(1);
|
||||
let relation = x[0].relation('users').query();
|
||||
return relation.first({ useMasterKey: true });
|
||||
}).then((x) => {
|
||||
expect(x.id).toEqual(user.id);
|
||||
object = new Parse.Object('TestObject');
|
||||
let acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(false);
|
||||
acl.setPublicWriteAccess(false);
|
||||
acl.setRoleReadAccess('TestRole', true);
|
||||
acl.setRoleWriteAccess('TestRole', true);
|
||||
object.setACL(acl);
|
||||
return object.save();
|
||||
}).then((x) => {
|
||||
let query = new Parse.Query('TestObject');
|
||||
return query.find({ sessionToken: user.getSessionToken() });
|
||||
}).then((x) => {
|
||||
expect(x.length).toEqual(1);
|
||||
return rp({
|
||||
method: 'DELETE',
|
||||
headers: headers,
|
||||
uri: 'http://localhost:8378/1/purge/_Role',
|
||||
json: true
|
||||
});
|
||||
}).then((x) => {
|
||||
let query = new Parse.Query('TestObject');
|
||||
return query.get(object.id, { sessionToken: user.getSessionToken() });
|
||||
}).then((x) => {
|
||||
fail('Should not succeed');
|
||||
}, (e) => {
|
||||
expect(e.code).toEqual(Parse.Error.OBJECT_NOT_FOUND);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -91,6 +91,16 @@ DatabaseController.prototype.collectionExists = function(className) {
|
||||
return this.adapter.classExists(className);
|
||||
};
|
||||
|
||||
DatabaseController.prototype.purgeCollection = function(className) {
|
||||
return this.loadSchema()
|
||||
.then((schema) => {
|
||||
schema.getOneSchema(className)
|
||||
})
|
||||
.then((schema) => {
|
||||
this.adapter.deleteObjectsByQuery(className, {}, schema);
|
||||
});
|
||||
};
|
||||
|
||||
DatabaseController.prototype.validateClassName = function(className) {
|
||||
if (this.skipValidation) {
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -50,6 +50,7 @@ import { SchemasRouter } from './Routers/SchemasRouter';
|
||||
import { SessionsRouter } from './Routers/SessionsRouter';
|
||||
import { UserController } from './Controllers/UserController';
|
||||
import { UsersRouter } from './Routers/UsersRouter';
|
||||
import { PurgeRouter } from './Routers/PurgeRouter';
|
||||
|
||||
import DatabaseController from './Controllers/DatabaseController';
|
||||
const SchemaController = require('./Controllers/SchemaController');
|
||||
@@ -291,6 +292,7 @@ class ParseServer {
|
||||
new IAPValidationRouter(),
|
||||
new FeaturesRouter(),
|
||||
new GlobalConfigRouter(),
|
||||
new PurgeRouter(),
|
||||
];
|
||||
|
||||
if (process.env.PARSE_EXPERIMENTAL_HOOKS_ENABLED || process.env.TESTING) {
|
||||
|
||||
@@ -36,7 +36,7 @@ export class FeaturesRouter extends PromiseRouter {
|
||||
removeField: true,
|
||||
addClass: true,
|
||||
removeClass: true,
|
||||
clearAllDataFromClass: false,
|
||||
clearAllDataFromClass: true,
|
||||
exportClass: false,
|
||||
editClassLevelPermissions: true,
|
||||
editPointerPermissions: true,
|
||||
|
||||
24
src/Routers/PurgeRouter.js
Normal file
24
src/Routers/PurgeRouter.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import PromiseRouter from '../PromiseRouter';
|
||||
import * as middleware from '../middlewares';
|
||||
|
||||
export class PurgeRouter extends PromiseRouter {
|
||||
|
||||
handlePurge(req) {
|
||||
return req.config.database.purgeCollection(req.params.className)
|
||||
.then(() => {
|
||||
var cacheAdapter = req.config.cacheController;
|
||||
if (req.params.className == '_Session') {
|
||||
cacheAdapter.user.clear();
|
||||
} else if (req.params.className == '_Role') {
|
||||
cacheAdapter.role.clear();
|
||||
}
|
||||
return {response: {}};
|
||||
});
|
||||
}
|
||||
|
||||
mountRoutes() {
|
||||
this.route('DELETE', '/purge/:className', middleware.promiseEnforceMasterKeyAccess, (req) => { return this.handlePurge(req); });
|
||||
}
|
||||
}
|
||||
|
||||
export default PurgeRouter;
|
||||
Reference in New Issue
Block a user