Migrate to new cloud code interfaces
removes job status object, moves messasge method on req object Adds 3.0.0 migration guide Fixes nits about 3.0.0 documentation Adds update guide to README
This commit is contained in:
@@ -166,7 +166,7 @@ export class HooksController {
|
||||
}
|
||||
|
||||
function wrapToHTTPRequest(hook, key) {
|
||||
return (req, res) => {
|
||||
return (req) => {
|
||||
const jsonBody = {};
|
||||
for (var i in req) {
|
||||
jsonBody[i] = req[i];
|
||||
@@ -195,37 +195,38 @@ function wrapToHTTPRequest(hook, key) {
|
||||
logger.warn('Making outgoing webhook request without webhookKey being set!');
|
||||
}
|
||||
|
||||
request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
|
||||
var result;
|
||||
if (body) {
|
||||
if (typeof body === "string") {
|
||||
try {
|
||||
body = JSON.parse(body);
|
||||
} catch (e) {
|
||||
err = {
|
||||
error: "Malformed response",
|
||||
code: -1,
|
||||
partialResponse: body.substring(0, 100)
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
|
||||
var result;
|
||||
if (body) {
|
||||
if (typeof body === "string") {
|
||||
try {
|
||||
body = JSON.parse(body);
|
||||
} catch (e) {
|
||||
err = {
|
||||
error: "Malformed response",
|
||||
code: -1,
|
||||
partialResponse: body.substring(0, 100)
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
result = body.success;
|
||||
err = body.error;
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
result = body.success;
|
||||
err = body.error;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
} else if (hook.triggerName === 'beforeSave') {
|
||||
if (typeof result === 'object') {
|
||||
delete result.createdAt;
|
||||
delete result.updatedAt;
|
||||
}
|
||||
return resolve({object: result});
|
||||
} else {
|
||||
return resolve(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return res.error(err);
|
||||
} else if (hook.triggerName === 'beforeSave') {
|
||||
if (typeof result === 'object') {
|
||||
delete result.createdAt;
|
||||
delete result.updatedAt;
|
||||
}
|
||||
return res.success({object: result});
|
||||
} else {
|
||||
return res.success(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,18 +56,21 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
jobName
|
||||
};
|
||||
const status = {
|
||||
success: jobHandler.setSucceeded.bind(jobHandler),
|
||||
error: jobHandler.setFailed.bind(jobHandler),
|
||||
jobName,
|
||||
message: jobHandler.setMessage.bind(jobHandler)
|
||||
}
|
||||
};
|
||||
|
||||
return jobHandler.setRunning(jobName, params).then((jobStatus) => {
|
||||
request.jobId = jobStatus.objectId
|
||||
// run the function async
|
||||
process.nextTick(() => {
|
||||
jobFunction(request, status);
|
||||
Promise.resolve().then(() => {
|
||||
return jobFunction(request);
|
||||
}).then((result) => {
|
||||
jobHandler.setSucceeded(result);
|
||||
}, (error) => {
|
||||
jobHandler.setFailed(error);
|
||||
});
|
||||
});
|
||||
return {
|
||||
headers: {
|
||||
@@ -87,13 +90,19 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function(code, message) {
|
||||
if (!message) {
|
||||
if (code instanceof Parse.Error) {
|
||||
return reject(code)
|
||||
}
|
||||
message = code;
|
||||
code = Parse.Error.SCRIPT_FAILED;
|
||||
error: function(message) {
|
||||
// parse error, process away
|
||||
if (message instanceof Parse.Error) {
|
||||
return reject(message);
|
||||
}
|
||||
|
||||
const code = Parse.Error.SCRIPT_FAILED;
|
||||
// If it's an error, mark it as a script failed
|
||||
if (typeof message === 'string') {
|
||||
return reject(new Parse.Error(code, message));
|
||||
}
|
||||
if (message instanceof Error) {
|
||||
message = message.message;
|
||||
}
|
||||
reject(new Parse.Error(code, message));
|
||||
},
|
||||
@@ -106,69 +115,66 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
const applicationId = req.config.applicationId;
|
||||
const theFunction = triggers.getFunction(functionName, applicationId);
|
||||
const theValidator = triggers.getValidator(req.params.functionName, applicationId);
|
||||
if (theFunction) {
|
||||
let params = Object.assign({}, req.body, req.query);
|
||||
params = parseParams(params);
|
||||
var request = {
|
||||
params: params,
|
||||
master: req.auth && req.auth.isMaster,
|
||||
user: req.auth && req.auth.user,
|
||||
installationId: req.info.installationId,
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
functionName
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === "function") {
|
||||
var result = theValidator(request);
|
||||
if (!result) {
|
||||
throw new Parse.Error(Parse.Error.VALIDATION_ERROR, 'Validation failed.');
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const userString = (req.auth && req.auth.user) ? req.auth.user.id : undefined;
|
||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||
var response = FunctionsRouter.createResponseObject((result) => {
|
||||
try {
|
||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
||||
logger.info(
|
||||
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput }\n Result: ${cleanResult }`,
|
||||
{
|
||||
functionName,
|
||||
params,
|
||||
user: userString,
|
||||
}
|
||||
);
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, (error) => {
|
||||
try {
|
||||
logger.error(
|
||||
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + JSON.stringify(error),
|
||||
{
|
||||
functionName,
|
||||
error,
|
||||
params,
|
||||
user: userString
|
||||
}
|
||||
);
|
||||
reject(error);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
// Force the keys before the function calls.
|
||||
Parse.applicationId = req.config.applicationId;
|
||||
Parse.javascriptKey = req.config.javascriptKey;
|
||||
Parse.masterKey = req.config.masterKey;
|
||||
theFunction(request, response);
|
||||
});
|
||||
} else {
|
||||
if (!theFunction) {
|
||||
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, `Invalid function: "${functionName}"`);
|
||||
}
|
||||
let params = Object.assign({}, req.body, req.query);
|
||||
params = parseParams(params);
|
||||
const request = {
|
||||
params: params,
|
||||
master: req.auth && req.auth.isMaster,
|
||||
user: req.auth && req.auth.user,
|
||||
installationId: req.info.installationId,
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
functionName
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === "function") {
|
||||
var result = theValidator(request);
|
||||
if (!result) {
|
||||
throw new Parse.Error(Parse.Error.VALIDATION_ERROR, 'Validation failed.');
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const userString = (req.auth && req.auth.user) ? req.auth.user.id : undefined;
|
||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||
const { success, error, message } = FunctionsRouter.createResponseObject((result) => {
|
||||
try {
|
||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
||||
logger.info(
|
||||
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput }\n Result: ${cleanResult }`,
|
||||
{
|
||||
functionName,
|
||||
params,
|
||||
user: userString,
|
||||
}
|
||||
);
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, (error) => {
|
||||
try {
|
||||
logger.error(
|
||||
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + JSON.stringify(error),
|
||||
{
|
||||
functionName,
|
||||
error,
|
||||
params,
|
||||
user: userString
|
||||
}
|
||||
);
|
||||
reject(error);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
return Promise.resolve().then(() => {
|
||||
return theFunction(request, { message });
|
||||
}).then(success, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,16 +222,11 @@ export function getResponseObject(request, resolve, reject) {
|
||||
}
|
||||
return resolve(response);
|
||||
},
|
||||
error: function(code, message) {
|
||||
if (!message) {
|
||||
if (code instanceof Parse.Error) {
|
||||
return reject(code)
|
||||
}
|
||||
message = code;
|
||||
code = Parse.Error.SCRIPT_FAILED;
|
||||
error: function(error) {
|
||||
if (typeof error === 'string') {
|
||||
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, error));
|
||||
}
|
||||
var scriptError = new Parse.Error(code, message);
|
||||
return reject(scriptError);
|
||||
return reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,7 +271,7 @@ export function maybeRunAfterFindTrigger(triggerType, auth, className, objects,
|
||||
return resolve();
|
||||
}
|
||||
const request = getRequestObject(triggerType, auth, null, null, config);
|
||||
const response = getResponseObject(request,
|
||||
const { success, error } = getResponseObject(request,
|
||||
object => {
|
||||
resolve(object);
|
||||
},
|
||||
@@ -289,16 +284,18 @@ export function maybeRunAfterFindTrigger(triggerType, auth, className, objects,
|
||||
object.className = className;
|
||||
return Parse.Object.fromJSON(object);
|
||||
});
|
||||
const triggerPromise = trigger(request, response);
|
||||
if (triggerPromise && typeof triggerPromise.then === "function") {
|
||||
return triggerPromise.then(promiseResults => {
|
||||
if(promiseResults) {
|
||||
resolve(promiseResults);
|
||||
}else{
|
||||
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
|
||||
}
|
||||
});
|
||||
}
|
||||
return Promise.resolve().then(() => {
|
||||
const response = trigger(request);
|
||||
if (response && typeof response.then === 'function') {
|
||||
return response.then((results) => {
|
||||
if (!results) {
|
||||
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise");
|
||||
}
|
||||
return results;
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}).then(success, error);
|
||||
}).then((results) => {
|
||||
logTriggerAfterHook(triggerType, className, JSON.stringify(results), auth);
|
||||
return results;
|
||||
@@ -401,7 +398,7 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
|
||||
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
|
||||
if (!trigger) return resolve();
|
||||
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
|
||||
var response = getResponseObject(request, (object) => {
|
||||
var { success, error } = getResponseObject(request, (object) => {
|
||||
logTriggerSuccessBeforeHook(
|
||||
triggerType, parseObject.className, parseObject.toJSON(), object, auth);
|
||||
resolve(object);
|
||||
@@ -410,27 +407,19 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
|
||||
triggerType, parseObject.className, parseObject.toJSON(), auth, error);
|
||||
reject(error);
|
||||
});
|
||||
// Force the current Parse app before the trigger
|
||||
Parse.applicationId = config.applicationId;
|
||||
Parse.javascriptKey = config.javascriptKey || '';
|
||||
Parse.masterKey = config.masterKey;
|
||||
|
||||
// AfterSave and afterDelete triggers can return a promise, which if they
|
||||
// do, needs to be resolved before this promise is resolved,
|
||||
// so trigger execution is synced with RestWrite.execute() call.
|
||||
// If triggers do not return a promise, they can run async code parallel
|
||||
// to the RestWrite.execute() call.
|
||||
var triggerPromise = trigger(request, response);
|
||||
if(triggerType === Types.afterSave || triggerType === Types.afterDelete)
|
||||
{
|
||||
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
|
||||
if(triggerPromise && typeof triggerPromise.then === "function") {
|
||||
return triggerPromise.then(resolve, resolve);
|
||||
return Promise.resolve().then(() => {
|
||||
const promise = trigger(request);
|
||||
if(triggerType === Types.afterSave || triggerType === Types.afterDelete) {
|
||||
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
|
||||
}
|
||||
else {
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
return promise;
|
||||
}).then(success, error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user