Pass context in beforeDelete, afterDelete, beforeFind and Parse.Cloud.run. (#6666)
* add context for following hooks. 1. beforeDelete 2. afterDelete 3. beforeFind 4. Cloud Function * revert un-necessary code change. * fix: failing test cases. * fix: failing test cases. * fix: failing test cases. * fix: failing test cases. * fix: failing test cases. * fix: failing test cases. * fix: failing test cases. * review changes * revert changes * revert changes * review changes * lint changes * review changes
This commit is contained in:
@@ -2968,4 +2968,58 @@ describe('afterLogin hook', () => {
|
||||
obj.set("obj2", obj2);
|
||||
await obj.save(null, { context: { a: 'a' } });
|
||||
});
|
||||
|
||||
it('should have access to context as saveAll argument', async () => {
|
||||
Parse.Cloud.beforeSave('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
Parse.Cloud.afterSave('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
const obj1 = new TestObject();
|
||||
const obj2 = new TestObject();
|
||||
await Parse.Object.saveAll([obj1, obj2], { context: { a: 'a' }});
|
||||
});
|
||||
|
||||
it('should have access to context as destroyAll argument', async () => {
|
||||
Parse.Cloud.beforeDelete('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
Parse.Cloud.afterDelete('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
const obj1 = new TestObject();
|
||||
const obj2 = new TestObject();
|
||||
await Parse.Object.saveAll([obj1, obj2]);
|
||||
await Parse.Object.destroyAll([obj1, obj2], { context: { a: 'a' } });
|
||||
});
|
||||
|
||||
it('should have access to context as destroy a object', async () => {
|
||||
Parse.Cloud.beforeDelete('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
Parse.Cloud.afterDelete('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
const obj = new TestObject();
|
||||
await obj.save();
|
||||
await obj.destroy({ context: { a: 'a' } });
|
||||
});
|
||||
|
||||
it('should have access to context in beforeFind hook', async () => {
|
||||
Parse.Cloud.beforeFind('TestObject', (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
});
|
||||
const query = new Parse.Query('TestObject');
|
||||
return query.find({ context: { a: 'a' } });
|
||||
});
|
||||
|
||||
it('should have access to context when cloud function is called.', async () => {
|
||||
Parse.Cloud.define('contextTest', async (req) => {
|
||||
expect(req.context.a).toEqual('a');
|
||||
return {};
|
||||
});
|
||||
|
||||
await Parse.Cloud.run('contextTest', {}, { context: { a: 'a' } });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ const createObject = async (className, fields, config, auth, info) => {
|
||||
fields = {};
|
||||
}
|
||||
|
||||
return (await rest.create(config, auth, className, fields, info.clientSDK))
|
||||
return (await rest.create(config, auth, className, fields, info.clientSDK, info.context))
|
||||
.response;
|
||||
};
|
||||
|
||||
@@ -27,12 +27,13 @@ const updateObject = async (
|
||||
className,
|
||||
{ objectId },
|
||||
fields,
|
||||
info.clientSDK
|
||||
info.clientSDK,
|
||||
info.context
|
||||
)).response;
|
||||
};
|
||||
|
||||
const deleteObject = async (className, objectId, config, auth, info) => {
|
||||
await rest.del(config, auth, className, objectId, info.clientSDK);
|
||||
await rest.del(config, auth, className, objectId, info.context);
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ const getObject = async (
|
||||
className,
|
||||
objectId,
|
||||
options,
|
||||
info.clientSDK
|
||||
info.clientSDK,
|
||||
info.context
|
||||
);
|
||||
|
||||
if (!response.results || response.results.length == 0) {
|
||||
@@ -142,7 +143,8 @@ const findObjects = async (
|
||||
className,
|
||||
where,
|
||||
preCountOptions,
|
||||
info.clientSDK
|
||||
info.clientSDK,
|
||||
info.context
|
||||
)
|
||||
).count;
|
||||
if ((skip || 0) + limit < preCount) {
|
||||
@@ -222,7 +224,8 @@ const findObjects = async (
|
||||
className,
|
||||
where,
|
||||
options,
|
||||
info.clientSDK
|
||||
info.clientSDK,
|
||||
info.context
|
||||
);
|
||||
results = findResult.results;
|
||||
count = findResult.count;
|
||||
|
||||
@@ -55,7 +55,8 @@ const getUserFromSessionToken = async (
|
||||
'_Session',
|
||||
{ sessionToken },
|
||||
options,
|
||||
info.clientVersion
|
||||
info.clientVersion,
|
||||
info.context,
|
||||
);
|
||||
if (
|
||||
!response.results ||
|
||||
|
||||
@@ -107,6 +107,7 @@ function ParseServerRESTController(applicationId, router) {
|
||||
info: {
|
||||
applicationId: applicationId,
|
||||
sessionToken: options.sessionToken,
|
||||
context: options.context || {}, // Add context
|
||||
},
|
||||
query,
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ function RestWrite(
|
||||
data,
|
||||
originalData,
|
||||
clientSDK,
|
||||
context,
|
||||
action
|
||||
) {
|
||||
if (auth.isReadOnly) {
|
||||
@@ -46,18 +47,12 @@ function RestWrite(
|
||||
this.clientSDK = clientSDK;
|
||||
this.storage = {};
|
||||
this.runOptions = {};
|
||||
this.context = {};
|
||||
this.context = context || {};
|
||||
|
||||
if (action) {
|
||||
this.runOptions.action = action;
|
||||
}
|
||||
|
||||
// Parse context
|
||||
if (data._context && data._context instanceof Object) {
|
||||
this.context = data._context;
|
||||
delete data._context;
|
||||
}
|
||||
|
||||
if (!query) {
|
||||
if (this.config.allowCustomObjectId) {
|
||||
if (
|
||||
|
||||
@@ -69,7 +69,8 @@ export class AggregateRouter extends ClassesRouter {
|
||||
this.className(req),
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context,
|
||||
)
|
||||
.then(response => {
|
||||
for (const result of response.results) {
|
||||
|
||||
@@ -21,7 +21,8 @@ export class AudiencesRouter extends ClassesRouter {
|
||||
'_Audience',
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context,
|
||||
)
|
||||
.then(response => {
|
||||
response.results.forEach(item => {
|
||||
|
||||
@@ -40,7 +40,8 @@ export class ClassesRouter extends PromiseRouter {
|
||||
this.className(req),
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context,
|
||||
)
|
||||
.then(response => {
|
||||
return { response: response };
|
||||
@@ -120,7 +121,8 @@ export class ClassesRouter extends PromiseRouter {
|
||||
req.auth,
|
||||
this.className(req),
|
||||
req.body,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,7 +134,8 @@ export class ClassesRouter extends PromiseRouter {
|
||||
this.className(req),
|
||||
where,
|
||||
req.body,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,7 +146,7 @@ export class ClassesRouter extends PromiseRouter {
|
||||
req.auth,
|
||||
this.className(req),
|
||||
req.params.objectId,
|
||||
req.info.clientSDK
|
||||
req.info.context
|
||||
)
|
||||
.then(() => {
|
||||
return { response: {} };
|
||||
|
||||
@@ -88,7 +88,8 @@ export class CloudCodeRouter extends PromiseRouter {
|
||||
req.auth,
|
||||
'_JobSchedule',
|
||||
formatJobSchedule(job_schedule),
|
||||
req.client
|
||||
req.client,
|
||||
req.info.context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,7 +103,9 @@ export class CloudCodeRouter extends PromiseRouter {
|
||||
req.auth,
|
||||
'_JobSchedule',
|
||||
{ objectId },
|
||||
formatJobSchedule(job_schedule)
|
||||
formatJobSchedule(job_schedule),
|
||||
undefined,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
return {
|
||||
@@ -114,7 +117,7 @@ export class CloudCodeRouter extends PromiseRouter {
|
||||
static deleteJob(req) {
|
||||
const { objectId } = req.params;
|
||||
return rest
|
||||
.del(req.config, req.auth, '_JobSchedule', objectId)
|
||||
.del(req.config, req.auth, '_JobSchedule', objectId, req.info.context)
|
||||
.then(response => {
|
||||
return {
|
||||
response,
|
||||
|
||||
@@ -148,6 +148,7 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
functionName,
|
||||
context: req.info.context,
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === 'function') {
|
||||
|
||||
@@ -51,7 +51,8 @@ function getFileForProductIdentifier(productIdentifier, req) {
|
||||
'_Product',
|
||||
{ productIdentifier: productIdentifier },
|
||||
undefined,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(function(result) {
|
||||
const products = result.results;
|
||||
|
||||
@@ -21,7 +21,8 @@ export class InstallationsRouter extends ClassesRouter {
|
||||
'_Installation',
|
||||
body.where,
|
||||
options,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
return { response: response };
|
||||
|
||||
@@ -23,7 +23,8 @@ export class SessionsRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken: req.info.sessionToken },
|
||||
undefined,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
if (!response.results || response.results.length == 0) {
|
||||
|
||||
@@ -178,7 +178,8 @@ export class UsersRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken },
|
||||
{ include: 'user' },
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(response => {
|
||||
if (
|
||||
@@ -302,7 +303,8 @@ export class UsersRouter extends ClassesRouter {
|
||||
'_Session',
|
||||
{ sessionToken: req.info.sessionToken },
|
||||
undefined,
|
||||
req.info.clientSDK
|
||||
req.info.clientSDK,
|
||||
req.info.context
|
||||
)
|
||||
.then(records => {
|
||||
if (records.results && records.results.length) {
|
||||
@@ -311,7 +313,8 @@ export class UsersRouter extends ClassesRouter {
|
||||
req.config,
|
||||
Auth.master(req.config),
|
||||
'_Session',
|
||||
records.results[0].objectId
|
||||
records.results[0].objectId,
|
||||
req.info.context
|
||||
)
|
||||
.then(() => {
|
||||
this._runAfterLogoutTrigger(req, records.results[0]);
|
||||
|
||||
@@ -100,9 +100,6 @@ function handleBatch(router, req) {
|
||||
info: req.info,
|
||||
};
|
||||
|
||||
// Add context to request body
|
||||
if (req.body._context) { request.body._context = req.body._context; }
|
||||
|
||||
return router
|
||||
.tryRouteRequest(restRequest.method, routablePath, request)
|
||||
.then(
|
||||
|
||||
@@ -33,6 +33,7 @@ export function handleParseHeaders(req, res, next) {
|
||||
dotNetKey: req.get('X-Parse-Windows-Key'),
|
||||
restAPIKey: req.get('X-Parse-REST-API-Key'),
|
||||
clientVersion: req.get('X-Parse-Client-Version'),
|
||||
context: {},
|
||||
};
|
||||
|
||||
var basicAuth = httpAuth(req);
|
||||
@@ -103,6 +104,10 @@ export function handleParseHeaders(req, res, next) {
|
||||
info.masterKey = req.body._MasterKey;
|
||||
delete req.body._MasterKey;
|
||||
}
|
||||
if (req.body._context && req.body._context instanceof Object) {
|
||||
info.context = req.body._context;
|
||||
delete req.body._context;
|
||||
}
|
||||
if (req.body._ContentType) {
|
||||
req.headers['content-type'] = req.body._ContentType;
|
||||
delete req.body._ContentType;
|
||||
|
||||
24
src/rest.js
24
src/rest.js
@@ -31,7 +31,7 @@ function checkLiveQuery(className, config) {
|
||||
}
|
||||
|
||||
// Returns a promise for an object with optional keys 'results' and 'count'.
|
||||
function find(config, auth, className, restWhere, restOptions, clientSDK) {
|
||||
function find(config, auth, className, restWhere, restOptions, clientSDK, context) {
|
||||
enforceRoleSecurity('find', className, auth);
|
||||
return triggers
|
||||
.maybeRunQueryTrigger(
|
||||
@@ -40,7 +40,8 @@ function find(config, auth, className, restWhere, restOptions, clientSDK) {
|
||||
restWhere,
|
||||
restOptions,
|
||||
config,
|
||||
auth
|
||||
auth,
|
||||
context
|
||||
)
|
||||
.then(result => {
|
||||
restWhere = result.restWhere || restWhere;
|
||||
@@ -58,7 +59,7 @@ function find(config, auth, className, restWhere, restOptions, clientSDK) {
|
||||
}
|
||||
|
||||
// get is just like find but only queries an objectId.
|
||||
const get = (config, auth, className, objectId, restOptions, clientSDK) => {
|
||||
const get = (config, auth, className, objectId, restOptions, clientSDK, context) => {
|
||||
var restWhere = { objectId };
|
||||
enforceRoleSecurity('get', className, auth);
|
||||
return triggers
|
||||
@@ -69,6 +70,7 @@ const get = (config, auth, className, objectId, restOptions, clientSDK) => {
|
||||
restOptions,
|
||||
config,
|
||||
auth,
|
||||
context,
|
||||
true
|
||||
)
|
||||
.then(result => {
|
||||
@@ -87,7 +89,7 @@ const get = (config, auth, className, objectId, restOptions, clientSDK) => {
|
||||
};
|
||||
|
||||
// Returns a promise that doesn't resolve to any useful value.
|
||||
function del(config, auth, className, objectId) {
|
||||
function del(config, auth, className, objectId, context) {
|
||||
if (typeof objectId !== 'string') {
|
||||
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad objectId');
|
||||
}
|
||||
@@ -134,7 +136,8 @@ function del(config, auth, className, objectId) {
|
||||
auth,
|
||||
inflatedObject,
|
||||
null,
|
||||
config
|
||||
config,
|
||||
context
|
||||
);
|
||||
}
|
||||
throw new Parse.Error(
|
||||
@@ -187,7 +190,8 @@ function del(config, auth, className, objectId) {
|
||||
auth,
|
||||
inflatedObject,
|
||||
null,
|
||||
config
|
||||
config,
|
||||
context
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -196,7 +200,7 @@ function del(config, auth, className, objectId) {
|
||||
}
|
||||
|
||||
// Returns a promise for a {response, status, location} object.
|
||||
function create(config, auth, className, restObject, clientSDK) {
|
||||
function create(config, auth, className, restObject, clientSDK, context) {
|
||||
enforceRoleSecurity('create', className, auth);
|
||||
var write = new RestWrite(
|
||||
config,
|
||||
@@ -205,7 +209,8 @@ function create(config, auth, className, restObject, clientSDK) {
|
||||
null,
|
||||
restObject,
|
||||
null,
|
||||
clientSDK
|
||||
clientSDK,
|
||||
context
|
||||
);
|
||||
return write.execute();
|
||||
}
|
||||
@@ -213,7 +218,7 @@ function create(config, auth, className, restObject, clientSDK) {
|
||||
// Returns a promise that contains the fields of the update that the
|
||||
// REST API is supposed to return.
|
||||
// Usually, this is just updatedAt.
|
||||
function update(config, auth, className, restWhere, restObject, clientSDK) {
|
||||
function update(config, auth, className, restWhere, restObject, clientSDK, context) {
|
||||
enforceRoleSecurity('update', className, auth);
|
||||
|
||||
return Promise.resolve()
|
||||
@@ -252,6 +257,7 @@ function update(config, auth, className, restWhere, restObject, clientSDK) {
|
||||
restObject,
|
||||
originalRestObject,
|
||||
clientSDK,
|
||||
context,
|
||||
'update'
|
||||
).execute();
|
||||
})
|
||||
|
||||
@@ -233,7 +233,10 @@ export function getRequestObject(
|
||||
request.original = originalParseObject;
|
||||
}
|
||||
|
||||
if (triggerType === Types.beforeSave || triggerType === Types.afterSave) {
|
||||
if (triggerType === Types.beforeSave ||
|
||||
triggerType === Types.afterSave ||
|
||||
triggerType === Types.beforeDelete ||
|
||||
triggerType === Types.afterDelete) {
|
||||
// Set a copy of the context on the request object.
|
||||
request.context = Object.assign({}, context);
|
||||
}
|
||||
@@ -259,6 +262,7 @@ export function getRequestQueryObject(
|
||||
query,
|
||||
count,
|
||||
config,
|
||||
context,
|
||||
isGet
|
||||
) {
|
||||
isGet = !!isGet;
|
||||
@@ -272,6 +276,7 @@ export function getRequestQueryObject(
|
||||
isGet,
|
||||
headers: config.headers,
|
||||
ip: config.ip,
|
||||
context: context || {},
|
||||
};
|
||||
|
||||
if (!auth) {
|
||||
@@ -460,6 +465,7 @@ export function maybeRunQueryTrigger(
|
||||
restOptions,
|
||||
config,
|
||||
auth,
|
||||
context,
|
||||
isGet
|
||||
) {
|
||||
const trigger = getTrigger(className, triggerType, config.applicationId);
|
||||
@@ -485,6 +491,7 @@ export function maybeRunQueryTrigger(
|
||||
parseQuery,
|
||||
count,
|
||||
config,
|
||||
context,
|
||||
isGet
|
||||
);
|
||||
return Promise.resolve()
|
||||
@@ -605,7 +612,9 @@ export function maybeRunTrigger(
|
||||
);
|
||||
if (
|
||||
triggerType === Types.beforeSave ||
|
||||
triggerType === Types.afterSave
|
||||
triggerType === Types.afterSave ||
|
||||
triggerType === Types.beforeDelete ||
|
||||
triggerType === Types.afterDelete
|
||||
) {
|
||||
Object.assign(context, request.context);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user