import { Parse } from 'parse/node'; import * as triggers from '../triggers'; import { addRateLimit } from '../middlewares'; const Config = require('../Config'); function isParseObjectConstructor(object) { return typeof object === 'function' && Object.prototype.hasOwnProperty.call(object, 'className'); } function validateValidator(validator) { if (!validator || typeof validator === 'function') { return; } const fieldOptions = { type: ['Any'], constant: [Boolean], default: ['Any'], options: [Array, 'function', 'Any'], required: [Boolean], error: [String], }; const allowedKeys = { requireUser: [Boolean], requireAnyUserRoles: [Array, 'function'], requireAllUserRoles: [Array, 'function'], requireMaster: [Boolean], validateMasterKey: [Boolean], skipWithMasterKey: [Boolean], requireUserKeys: [Array, Object], fields: [Array, Object], rateLimit: [Object], }; const getType = fn => { if (Array.isArray(fn)) { return 'array'; } if (fn === 'Any' || fn === 'function') { return fn; } const type = typeof fn; if (typeof fn === 'function') { const match = fn && fn.toString().match(/^\s*function (\w+)/); return (match ? match[1] : 'function').toLowerCase(); } return type; }; const checkKey = (key, data, validatorParam) => { const parameter = data[key]; if (!parameter) { throw `${key} is not a supported parameter for Cloud Function validations.`; } const types = parameter.map(type => getType(type)); const type = getType(validatorParam); if (!types.includes(type) && !types.includes('Any')) { throw `Invalid type for Cloud Function validation key ${key}. Expected ${types.join( '|' )}, actual ${type}`; } }; for (const key in validator) { checkKey(key, allowedKeys, validator[key]); if (key === 'fields' || key === 'requireUserKeys') { const values = validator[key]; if (Array.isArray(values)) { continue; } for (const value in values) { const data = values[value]; for (const subKey in data) { checkKey(subKey, fieldOptions, data[subKey]); } } } } } const getRoute = parseClass => { const route = { _User: 'users', _Session: 'sessions', '@File': 'files', '@Config' : 'config', }[parseClass] || 'classes'; if (parseClass === '@File') { return `/${route}{/*id}`; } if (parseClass === '@Config') { return `/${route}`; } return `/${route}/${parseClass}{/*id}`; }; /** @namespace * @name Parse * @description The Parse SDK. * see [api docs](https://docs.parseplatform.org/js/api) and [guide](https://docs.parseplatform.org/js/guide) */ /** @namespace * @name Parse.Cloud * @memberof Parse * @description The Parse Cloud Code SDK. */ var ParseCloud = {}; /** * Defines a Cloud Function. * * **Available in Cloud Code only.** * * **Traditional Style:** * ``` * Parse.Cloud.define('functionName', (request) => { * // code here * return result; * }, (request) => { * // validation code here * }); * * Parse.Cloud.define('functionName', (request) => { * // code here * return result; * }, { ...validationObject }); * ``` * * **Express Style with Custom HTTP Status Codes:** * ``` * Parse.Cloud.define('functionName', (request, response) => { * // Set custom HTTP status code and send response * response.status(201).success({ message: 'Created' }); * }); * * Parse.Cloud.define('unauthorizedFunction', (request, response) => { * if (!request.user) { * response.status(401).error('Unauthorized'); * } else { * response.success({ data: 'OK' }); * } * }); * * Parse.Cloud.define('withCustomHeaders', (request, response) => { * response.header('X-Custom-Header', 'value').success({ data: 'OK' }); * }); * * Parse.Cloud.define('errorFunction', (request, response) => { * response.error('Something went wrong'); * }); * ``` * * @static * @memberof Parse.Cloud * @param {String} name The name of the Cloud Function * @param {Function} data The Cloud Function to register. This function can be an async function and should take one parameter a {@link Parse.Cloud.FunctionRequest}, or two parameters (request, response) for Express-style functions where response is a {@link Parse.Cloud.FunctionResponse}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FunctionRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.define = function (functionName, handler, validationHandler) { validateValidator(validationHandler); triggers.addFunction(functionName, handler, validationHandler, Parse.applicationId); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: `/functions/${functionName}`, ...validationHandler.rateLimit }, Parse.applicationId, true ); } }; /** * Defines a Background Job. * * **Available in Cloud Code only.** * * @method job * @name Parse.Cloud.job * @param {String} name The name of the Background Job * @param {Function} func The Background Job to register. This function can be async should take a single parameters a {@link Parse.Cloud.JobRequest} * */ ParseCloud.job = function (functionName, handler) { triggers.addJob(functionName, handler, Parse.applicationId); }; /** * * Registers a before save function. * * **Available in Cloud Code only.** * * If you want to use beforeSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * * ``` * Parse.Cloud.beforeSave('MyCustomClass', (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.beforeSave(Parse.User, (request) => { * // code here * }, { ...validationObject }) * ``` * * @method beforeSave * @name Parse.Cloud.beforeSave * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run before a save. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest}; * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.beforeSave = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.beforeSave, className, handler, Parse.applicationId, validationHandler ); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: getRoute(className), requestMethods: ['POST', 'PUT'], ...validationHandler.rateLimit, }, Parse.applicationId, true ); } }; /** * Registers a before delete function. * * **Available in Cloud Code only.** * * If you want to use beforeDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * ``` * Parse.Cloud.beforeDelete('MyCustomClass', (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.beforeDelete(Parse.User, (request) => { * // code here * }, { ...validationObject }) *``` * * @method beforeDelete * @name Parse.Cloud.beforeDelete * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before delete function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run before a delete. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.beforeDelete = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.beforeDelete, className, handler, Parse.applicationId, validationHandler ); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: getRoute(className), requestMethods: 'DELETE', ...validationHandler.rateLimit, }, Parse.applicationId, true ); } }; /** * * Registers the before login function. * * **Available in Cloud Code only.** * * This function provides further control * in validating a login attempt. Specifically, * it is triggered after a user enters * correct credentials (or other valid authData), * but prior to a session being generated. * * ``` * Parse.Cloud.beforeLogin((request) => { * // code here * }) * * ``` * * @method beforeLogin * @name Parse.Cloud.beforeLogin * @param {Function} func The function to run before a login. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest}; */ ParseCloud.beforeLogin = function (handler, validationHandler) { let className = '_User'; if (typeof handler === 'string' || isParseObjectConstructor(handler)) { // validation will occur downstream, this is to maintain internal // code consistency with the other hook types. className = triggers.getClassName(handler); handler = arguments[1]; validationHandler = arguments.length >= 2 ? arguments[2] : null; } triggers.addTrigger(triggers.Types.beforeLogin, className, handler, Parse.applicationId); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: `/login`, requestMethods: 'POST', ...validationHandler.rateLimit }, Parse.applicationId, true ); } }; /** * * Registers the after login function. * * **Available in Cloud Code only.** * * This function is triggered after a user logs in successfully, * and after a _Session object has been created. * * ``` * Parse.Cloud.afterLogin((request) => { * // code here * }); * ``` * * @method afterLogin * @name Parse.Cloud.afterLogin * @param {Function} func The function to run after a login. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest}; */ ParseCloud.afterLogin = function (handler) { let className = '_User'; if (typeof handler === 'string' || isParseObjectConstructor(handler)) { // validation will occur downstream, this is to maintain internal // code consistency with the other hook types. className = triggers.getClassName(handler); handler = arguments[1]; } triggers.addTrigger(triggers.Types.afterLogin, className, handler, Parse.applicationId); }; /** * * Registers the after logout function. * * **Available in Cloud Code only.** * * This function is triggered after a user logs out. * * ``` * Parse.Cloud.afterLogout((request) => { * // code here * }); * ``` * * @method afterLogout * @name Parse.Cloud.afterLogout * @param {Function} func The function to run after a logout. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest}; */ ParseCloud.afterLogout = function (handler) { let className = '_Session'; if (typeof handler === 'string' || isParseObjectConstructor(handler)) { // validation will occur downstream, this is to maintain internal // code consistency with the other hook types. className = triggers.getClassName(handler); handler = arguments[1]; } triggers.addTrigger(triggers.Types.afterLogout, className, handler, Parse.applicationId); }; /** * Registers the before password reset request function. * * **Available in Cloud Code only.** * * This function provides control in validating a password reset request * before the reset email is sent. It is triggered after the user is found * by email, but before the reset token is generated and the email is sent. * * Code example: * * ``` * Parse.Cloud.beforePasswordResetRequest(request => { * if (request.object.get('banned')) { * throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, 'User is banned.'); * } * }); * ``` * * @method beforePasswordResetRequest * @name Parse.Cloud.beforePasswordResetRequest * @param {Function} func The function to run before a password reset request. This function can be async and should take one parameter a {@link Parse.Cloud.TriggerRequest}; */ ParseCloud.beforePasswordResetRequest = function (handler, validationHandler) { let className = '_User'; if (typeof handler === 'string' || isParseObjectConstructor(handler)) { // validation will occur downstream, this is to maintain internal // code consistency with the other hook types. className = triggers.getClassName(handler); handler = arguments[1]; validationHandler = arguments.length >= 2 ? arguments[2] : null; } triggers.addTrigger(triggers.Types.beforePasswordResetRequest, className, handler, Parse.applicationId); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: `/requestPasswordReset`, requestMethods: 'POST', ...validationHandler.rateLimit }, Parse.applicationId, true ); } }; /** * Registers an after save function. * * **Available in Cloud Code only.** * * If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * * ``` * Parse.Cloud.afterSave('MyCustomClass', async function(request) { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.afterSave(Parse.User, async function(request) { * // code here * }, { ...validationObject }); * ``` * * @method afterSave * @name Parse.Cloud.afterSave * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after save function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run after a save. This function can be an async function and should take just one parameter, {@link Parse.Cloud.TriggerRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.afterSave = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.afterSave, className, handler, Parse.applicationId, validationHandler ); }; /** * Registers an after delete function. * * **Available in Cloud Code only.** * * If you want to use afterDelete for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * ``` * Parse.Cloud.afterDelete('MyCustomClass', async (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.afterDelete(Parse.User, async (request) => { * // code here * }, { ...validationObject }); *``` * * @method afterDelete * @name Parse.Cloud.afterDelete * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after delete function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run after a delete. This function can be async and should take just one parameter, {@link Parse.Cloud.TriggerRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.afterDelete = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.afterDelete, className, handler, Parse.applicationId, validationHandler ); }; /** * Registers a before find function. * * **Available in Cloud Code only.** * * If you want to use beforeFind for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * ``` * Parse.Cloud.beforeFind('MyCustomClass', async (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.beforeFind(Parse.User, async (request) => { * // code here * }, { ...validationObject }); *``` * * @method beforeFind * @name Parse.Cloud.beforeFind * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before find function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run before a find. This function can be async and should take just one parameter, {@link Parse.Cloud.BeforeFindRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.BeforeFindRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.beforeFind = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.beforeFind, className, handler, Parse.applicationId, validationHandler ); if (validationHandler && validationHandler.rateLimit) { addRateLimit( { requestPath: getRoute(className), requestMethods: 'GET', ...validationHandler.rateLimit, }, Parse.applicationId, true ); } }; /** * Registers an after find function. * * **Available in Cloud Code only.** * * If you want to use afterFind for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * ``` * Parse.Cloud.afterFind('MyCustomClass', async (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.afterFind(Parse.User, async (request) => { * // code here * }, { ...validationObject }); *``` * * @method afterFind * @name Parse.Cloud.afterFind * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after find function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run before a find. This function can be async and should take just one parameter, {@link Parse.Cloud.AfterFindRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.AfterFindRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.afterFind = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.afterFind, className, handler, Parse.applicationId, validationHandler ); }; /** * Registers a before live query server connect function. * * **Available in Cloud Code only.** * * ``` * Parse.Cloud.beforeConnect(async (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.beforeConnect(async (request) => { * // code here * }, { ...validationObject }); *``` * * @method beforeConnect * @name Parse.Cloud.beforeConnect * @param {Function} func The function to before connection is made. This function can be async and should take just one parameter, {@link Parse.Cloud.ConnectTriggerRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.ConnectTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.beforeConnect = function (handler, validationHandler) { validateValidator(validationHandler); triggers.addConnectTrigger( triggers.Types.beforeConnect, handler, Parse.applicationId, validationHandler ); }; /** * Sends an email through the Parse Server mail adapter. * * **Available in Cloud Code only.** * **Requires a mail adapter to be configured for Parse Server.** * * ``` * Parse.Cloud.sendEmail({ * from: 'Example ', * to: 'contact@example.com', * subject: 'Test email', * text: 'This email is a test.' * }); *``` * * @method sendEmail * @name Parse.Cloud.sendEmail * @param {Object} data The object of the mail data to send. */ ParseCloud.sendEmail = function (data) { const config = Config.get(Parse.applicationId); const emailAdapter = config.userController.adapter; if (!emailAdapter) { config.loggerController.error( 'Failed to send email because no mail adapter is configured for Parse Server.' ); return; } return emailAdapter.sendMail(data); }; /** * Registers a before live query subscription function. * * **Available in Cloud Code only.** * * If you want to use beforeSubscribe for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User} or {@link Parse.File}), you should pass the class itself and not the String for arg1. * ``` * Parse.Cloud.beforeSubscribe('MyCustomClass', (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.beforeSubscribe(Parse.User, (request) => { * // code here * }, { ...validationObject }); *``` * * @method beforeSubscribe * @name Parse.Cloud.beforeSubscribe * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before subscription function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run before a subscription. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.TriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.beforeSubscribe = function (parseClass, handler, validationHandler) { validateValidator(validationHandler); const className = triggers.getClassName(parseClass); triggers.addTrigger( triggers.Types.beforeSubscribe, className, handler, Parse.applicationId, validationHandler ); }; ParseCloud.onLiveQueryEvent = function (handler) { triggers.addLiveQueryEventHandler(handler, Parse.applicationId); }; /** * Registers an after live query server event function. * * **Available in Cloud Code only.** * * ``` * Parse.Cloud.afterLiveQueryEvent('MyCustomClass', (request) => { * // code here * }, (request) => { * // validation code here * }); * * Parse.Cloud.afterLiveQueryEvent('MyCustomClass', (request) => { * // code here * }, { ...validationObject }); *``` * * @method afterLiveQueryEvent * @name Parse.Cloud.afterLiveQueryEvent * @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the after live query event function for. This can instead be a String that is the className of the subclass. * @param {Function} func The function to run after a live query event. This function can be async and should take one parameter, a {@link Parse.Cloud.LiveQueryEventTrigger}. * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.LiveQueryEventTrigger}, or a {@link Parse.Cloud.ValidatorObject}. */ ParseCloud.afterLiveQueryEvent = function (parseClass, handler, validationHandler) { const className = triggers.getClassName(parseClass); validateValidator(validationHandler); triggers.addTrigger( triggers.Types.afterEvent, className, handler, Parse.applicationId, validationHandler ); }; ParseCloud._removeAllHooks = () => { triggers._unregisterAll(); const config = Config.get(Parse.applicationId); config?.unregisterRateLimiters(); }; ParseCloud.useMasterKey = () => { // eslint-disable-next-line console.warn( 'Parse.Cloud.useMasterKey is deprecated (and has no effect anymore) on parse-server, please refer to the cloud code migration notes: http://docs.parseplatform.org/parse-server/guide/#master-key-must-be-passed-explicitly' ); }; module.exports = ParseCloud; /** * @interface Parse.Cloud.TriggerRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} master If true, means the master key was used. * @property {Boolean} isChallenge If true, means the current request is originally triggered by an auth challenge. * @property {Parse.User} user If set, the user that made the request. * @property {Parse.Object} object The object triggering the hook. * @property {String} ip The IP address of the client making the request. To ensure retrieving the correct IP address, set the Parse Server option `trustProxy: true` if Parse Server runs behind a proxy server, for example behind a load balancer. * @property {Object} headers The original HTTP headers for the request. * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) * @property {Object} log The current logger inside Parse Server. * @property {Parse.Object} original If set, the object, as currently stored. * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.FileTriggerRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} master If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {Parse.File} file The file that triggered the hook. * @property {Integer} fileSize The size of the file in bytes. * @property {Integer} contentLength The value from Content-Length header * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`) * @property {Object} log The current logger inside Parse Server. * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.ConnectTriggerRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} useMasterKey If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {Integer} clients The number of clients connected. * @property {Integer} subscriptions The number of subscriptions connected. * @property {String} sessionToken If set, the session of the user that made the request. */ /** * @interface Parse.Cloud.LiveQueryEventTrigger * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} useMasterKey If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {String} sessionToken If set, the session of the user that made the request. * @property {String} event The live query event that triggered the request. * @property {Parse.Object} object The object triggering the hook. * @property {Parse.Object} original If set, the object, as currently stored. * @property {Integer} clients The number of clients connected. * @property {Integer} subscriptions The number of subscriptions connected. * @property {Boolean} sendEvent If the LiveQuery event should be sent to the client. Set to false to prevent LiveQuery from pushing to the client. */ /** * @interface Parse.Cloud.BeforeFindRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} master If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {Parse.Query} query The query triggering the hook. * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) * @property {Object} log The current logger inside Parse Server. * @property {Boolean} isGet wether the query a `get` or a `find` * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.AfterFindRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} master If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {Parse.Query} query The query triggering the hook. * @property {Array} results The results the query yielded. * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`, ...) * @property {Object} log The current logger inside Parse Server. * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.FunctionRequest * @property {String} installationId If set, the installationId triggering the request. * @property {Boolean} master If true, means the master key was used. * @property {Parse.User} user If set, the user that made the request. * @property {Object} params The params passed to the cloud function. * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. * @property {Object} log The current logger inside Parse Server. * @property {String} functionName The name of the cloud function. * @property {Object} context The context of the cloud function call. * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.FunctionResponse * @property {function} success Call this function to return a successful response with an optional result. Usage: `response.success(result)` * @property {function} error Call this function to return an error response with an error message. Usage: `response.error(message)` * @property {function} status Call this function to set a custom HTTP status code for the response. Returns the response object for chaining. Usage: `response.status(code).success(result)` or `response.status(code).error(message)` * @property {function} header Call this function to set a custom HTTP header for the response. Returns the response object for chaining. Usage: `response.header('X-Custom-Header', 'value').success(result)` */ /** * @interface Parse.Cloud.JobRequest * @property {Object} params The params passed to the background job. * @property {function} message If message is called with a string argument, will update the current message to be stored in the job status. * @property {Object} config The Parse Server config. */ /** * @interface Parse.Cloud.ValidatorObject * @property {Boolean} requireUser whether the cloud trigger requires a user. * @property {Boolean} requireMaster whether the cloud trigger requires a master key. * @property {Boolean} validateMasterKey whether the validator should run if masterKey is provided. Defaults to false. * @property {Boolean} skipWithMasterKey whether the cloud code function should be ignored using a masterKey. * * @property {Array|Object} requireUserKeys If set, keys required on request.user to make the request. * @property {String} requireUserKeys.field If requireUserKeys is an object, name of field to validate on request user * @property {Array|function|Any} requireUserKeys.field.options array of options that the field can be, function to validate field, or single value. Throw an error if value is invalid. * @property {String} requireUserKeys.field.error custom error message if field is invalid. * * @property {Array|function}requireAnyUserRoles If set, request.user has to be part of at least one roles name to make the request. If set to a function, function must return role names. * @property {Array|function}requireAllUserRoles If set, request.user has to be part all roles name to make the request. If set to a function, function must return role names. * * @property {Object|Array} fields if an array of strings, validator will look for keys in request.params, and throw if not provided. If Object, fields to validate. If the trigger is a cloud function, `request.params` will be validated, otherwise `request.object`. * @property {String} fields.field name of field to validate. * @property {String} fields.field.type expected type of data for field. * @property {Boolean} fields.field.constant whether the field can be modified on the object. * @property {Any} fields.field.default default value if field is `null`, or initial value `constant` is `true`. * @property {Array|function|Any} fields.field.options array of options that the field can be, function to validate field, or single value. Throw an error if value is invalid. * @property {String} fields.field.error custom error message if field is invalid. */