# cloudfunction.js

    const _ = require('underscore');
    const { _request, request } = require('./request');
    const Promise = require('./promise');

    module.exports = function(AV) {
      /**
       * Contains functions for calling and declaring
       * <p><strong><em>
       *   Some functions are only available from Cloud Code.
       * </em></strong></p>
       *
       * @namespace
       * @borrows AV.Captcha.request as requestCaptcha
       */
      AV.Cloud = AV.Cloud || {};

      _.extend(
        AV.Cloud,
        /** @lends AV.Cloud */ {
          /**
           * Makes a call to a cloud function.
           * @param {String} name The function name.
           * @param {Object} data The parameters to send to the cloud function.
           * @param {AuthOptions} options
           * @return {Promise} A promise that will be resolved with the result
           * of the function.
           */
          run(name, data, options) {
            return request({
              service: 'engine',
              method: 'POST',
              path: `/functions/${name}`,
              data: AV._encode(data, null, true),
              authOptions: options,
            }).then(resp => {
              return AV._decode(resp).result;
            });
          },

          /**
           * Makes a call to a cloud function, you can send {AV.Object} as param or a field of param; the response
           * from server will also be parsed as an {AV.Object}, array of {AV.Object}, or object includes {AV.Object}
           * @param {String} name The function name.
           * @param {Object} data The parameters to send to the cloud function.
           * @param {AuthOptions} options
           * @return {Promise} A promise that will be resolved with the result of the function.
           */
          rpc(name, data, options) {
            if (_.isArray(data)) {
              return Promise.reject(
                new Error(
                  "Can't pass Array as the param of rpc function in JavaScript SDK."
                )
              );
            }

            return request({
              service: 'engine',
              method: 'POST',
              path: `/call/${name}`,
              data: AV._encodeObjectOrArray(data),
              authOptions: options,
            }).then(resp => {
              return AV._decode(resp).result;
            });
          },

          /**
           * Make a call to request server date time.
           * @return {Promise.<Date>} A promise that will be resolved with the result
           * of the function.
           * @since 0.5.9
           */
          getServerDate() {
            return _request('date', null, null, 'GET').then(function(resp) {
              return AV._decode(resp);
            });
          },

          /**
           * Makes a call to request a sms code for operation verification.
           * @param {String|Object} data The mobile phone number string or a JSON
           *    object that contains mobilePhoneNumber,template,sign,op,ttl,name etc.
           * @param {String} data.mobilePhoneNumber
           * @param {String} [data.template] sms template name
           * @param {String} [data.sign] sms signature name
           * @param {AuthOptions} [options] AuthOptions plus:
           * @param {String} [options.validateToken] a validate token returned by {@link AV.Cloud.verifyCaptcha}
           * @return {Promise} A promise that will be resolved if the request succeed
           */
          requestSmsCode(data, options = {}) {
            if (_.isString(data)) {
              data = { mobilePhoneNumber: data };
            }
            if (!data.mobilePhoneNumber) {
              throw new Error('Missing mobilePhoneNumber.');
            }
            if (options.validateToken) {
              data = _.extend({}, data, {
                validate_token: options.validateToken,
              });
            }
            return _request('requestSmsCode', null, null, 'POST', data, options);
          },

          /**
           * Makes a call to verify sms code that sent by AV.Cloud.requestSmsCode
           * @param {String} code The sms code sent by AV.Cloud.requestSmsCode
           * @param {phone} phone The mobile phoner number(optional).
           * @return {Promise} A promise that will be resolved with the result
           * of the function.
           */
          verifySmsCode(code, phone) {
            if (!code) throw new Error('Missing sms code.');
            var params = {};
            if (_.isString(phone)) {
              params['mobilePhoneNumber'] = phone;
            }

            return _request('verifySmsCode', code, null, 'POST', params);
          },

          _requestCaptcha(options, authOptions) {
            return _request(
              'requestCaptcha',
              null,
              null,
              'GET',
              options,
              authOptions
            ).then(({ captcha_url: url, captcha_token: captchaToken }) => ({
              captchaToken,
              url,
            }));
          },

          /**
           * Request a captcha.
           */
          requestCaptcha: AV.Captcha.request,

          /**
           * Verify captcha code. This is the low-level API for captcha.
           * Checkout {@link AV.Captcha} for high abstract APIs.
           * @param {String} code the code from user input
           * @param {String} captchaToken captchaToken returned by {@link AV.Cloud.requestCaptcha}
           * @return {Promise.<String>} validateToken if the code is valid
           */
          verifyCaptcha(code, captchaToken) {
            return _request('verifyCaptcha', null, null, 'POST', {
              captcha_code: code,
              captcha_token: captchaToken,
            }).then(({ validate_token: validateToken }) => validateToken);
          },
        }
      );
    };