Viewing File: /usr/local/cpanel/share/libraries/cjt2/src/io/api.js

/*
# cjt/io/api.js                                      Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/

/* --------------------------*/
/* DEFINE GLOBALS FOR LINT
/*--------------------------*/
/* global define:true, require:true, console: true */
/* --------------------------*/

/**
 *
 * @module cjt/io/api
 * @example
 *
 * require(["cjt/io/api"], function(API) {
 *      return API.promise({
 *          module: "SetLang",
 *          func:   "setlocale",
 *          data: { locale: "en-US" },
 *          callback: {
 *              failure: function(tId, res, args) {
 *                  // We only get here for api failures
 *
 *                  // Do something for failure
 *                  var error = String(res.error || res.cpanel_error || res);
 *                  if (!error) {
 *                  }
 *              },
 *              success: function(tId, res, args) {
 *                  // Do something for success
 *              }
 *          }
 *      } );
 */

/* eslint-disable */
define([
        "cjt/core",
        "jquery",
        "cjt/util/query",
        "cjt/util/locale"
    ],
    function(CJT, $, QUERY, LOCALE) {

        "use strict";

        //------------------------------
        // Module
        //------------------------------
        var MODULE_NAME = "cjt/io/api"; // requirejs(["cjt/io/api"], function(api) {}); -> cjt/io/api.js || cjt/io/api.debug.js
        var MODULE_DESC = "";
        var MODULE_VERSION = 2.0;

        /* Each API is implemented in a module that constructs a static object with the
           following interface.  Implementers must provide a complete set of these methods
           on their API driver object for it to function in the API system.

        var IAPIDriver = {
            parse_response : function(resp) {
            },
            find_messages : function(resp) {
            },
            find_status : function(resp) {
            },
            get_data : function(resp) {
            },
            get_meta : function(resp) {
            },
            build_query : function(api_version, args_obj) {
            },
            get_url : function(token, args_obj) {
            }
        }
        */


        /**
         * Wrapper method to make localization to an alternative AJAX model a bit more
         * transparent.
         *
         * @method  _ajax
         * @private
         * @param  {String} method  POST or GET
         * @param  {String} url     The url for the request
         * @param  {Object} args    The arguments object to pass to the api call.
         * @param  {Function} filter
         * @param  {Boolean} json   If true, send application/json as the Content-Type
         * @return {Promise}        A Promise object that when resolved indicates the api was run,
         *                          and when rejected indicates the api was not run or failed.
         */
        var _ajax = function(method, url, args, filter, json) {
            // Setting traditional to true so query params will look like:
            // field=value1&field=value2
            // instead of:
            // field[]=value1&field[]=value2
            var ajaxArgs = {
                type: method || "POST",
                url: url,
                data: args,
                traditional: true
            };

            if (filter) {
                ajaxArgs.dataFilter = filter;
                ajaxArgs.converters = {
                    "text json": function(data) {
                        // Replace the internal converter so we dont double parse.
                        return data;
                    }
                };
            }

            if (json) {
                ajaxArgs.contentType = "application/json";
            }

            return $.ajax(ajaxArgs);
        };

        /**
         * Normalized the application detection
         *
         * @method _find_is_whm
         * @private
         * @param  {Object} args_obj Arguments to the api call.
         *             {String} args_obj.application Optional name of the application.
         * @return {Boolean}
         */
        var _find_is_whm = function(args_obj) {
            return (
                args_obj.application === CJT.KNOWN_APPLICATIONS.WHM
                || CJT.isWhm()
                || CJT.isUnitTest() && require("karmaHelpers").isWhmUnitTest()
            );
        };

        /**
         * Normalized the version information for the application.
         *
         * @name _find_api_version
         * @private
         * @param  {Object} args_obj Arguments to the api call.
         * @return {Number}          Version number of the invoked api call.
         */
        var _find_api_version = function(args_obj) {
            var version;
            if ("version" in args_obj) {
                version = args_obj.version;
            } else if ("api_data" in args_obj &&
                "version" in args_obj.api_data) {
                version = args_obj.api_data.version;
            } else {
                // Since we didn't pass it, we have to guess
                if (_find_is_whm(args_obj)) {
                    // We are in WHM so default to WHM v1.
                    version = 1;
                } else {
                    // We are in CPANEL so default to API2.
                    // CONSIDER: This assumption will have to be evaluated once UAPI is
                    // more widely implemented at which time this would be change to 3.
                    version = 2;
                }
            }
            return parseInt(version, 10);
        };

        /**
         * Retrieves the driver for the specified interface and version
         *
         * @method  _get_api_driver
         * @private
         * @param  {Boolean} is_whm      true if we are in WHM, false otherwise.
         * @param  {Number}  api_version Version of the api: Should be 1, 2 or 3.
         * @return {Object}              Driver object for the requested interface and version supporting the IAPIDriver interface.
         */
        var _get_api_driver = function(is_whm, api_version) {
            var api_driver;
            if (is_whm) {
                switch (api_version) {
                case 1:
                    api_driver = require("cjt/io/whm-v1");
                    break;
                case 3:
                    // NOTE: This is future proofing, but not actually supported until UAPI is ported to WHM.
                    api_driver = require("cjt/io/uapi");
                    break;
                default:
                    // WHM defaults to WHM v1
                    api_driver = require("cjt/io/whm-v1");
                    break;
                }
            } else {
                switch (api_version) {
                case 1:
                    api_driver = require("cjt/io/api1");
                    break;
                case 2:
                    api_driver = require("cjt/io/api2");
                    break;
                case 3:
                    api_driver = require("cjt/io/uapi");
                    break;
                default:
                    // CPANEL defaults to API2
                    api_driver = require("cjt/io/api2");
                    break;
                }
            }
            return api_driver;
        };

        /**
         * Construct the api call query string
         *
         * @method construct_api_query
         * @private
         * @param  {Number} api_version Version number
         * @param  {Object} args_obj    Arguments to the call.
         * @param  {Object} driver      Driver supporting the IAPIDriver interface.
         * @return {String}             Url to call the api call.
         */
        var _construct_api_query = function(args_obj, driver) {
            var api_call = driver.build_query(args_obj);

            if (args_obj.json){
                return JSON.stringify(api_call);
            }

            // TODO: See if we can use Y.QueryString.stringify() here.
            return QUERY.make_query_string(api_call);
        };

        /**
         * Build the data filter from the driver.
         *
         * @method _build_data_filter
         * @private
         * @param  {Number} api_version Version of the api: Should be 1, 2 or 3.
         * @param  {Object} args_obj    Arguments to the call.
         * @param  {Object} driver      Driver supporting the IAPIDriver interface.
         * @return {Object}             Object containing the callbacks for the call
         * adjusted into a standard format.
         */
        var _build_data_filter = function(api_version, args_obj, driver) {

            var dataFilter = function(data, type) {
                var parse_response = driver.parse_response;
                if (!parse_response) {
                    var msg = "No parser for the API version requested:" + CJT.applicationName + " " + api_version;
                    console.log(msg, "error", MODULE_NAME);
                    throw msg;
                }

                return parse_response(data, type, args_obj);
            };

            return dataFilter;
        };

        //CPANEL.api()
        //
        //Normalize interactions with cPanel and WHM's APIs.
        //
        //This checks for API failures as well as HTTP failures; both are
        //routed to the "failure" callback.
        //
        //"failure" callbacks receive the same argument as with YUI
        //asyncRequest, but with additional properties as given in api_base._parse_response below.
        //
        //NOTE: WHM API v1 responses are normalized to a list if the API return
        //is a hash with only 1 value, and that value is a list.
        //
        //
        //This function takes a single object as its argument with these keys:
        //  module  (not needed in WHM API v1)
        //  func
        //  callback (cf. YUI 2 asyncRequest)
        //  data (goes to the API call itself)
        //  api_data (see below)
        //
        //Sort, filter, and pagination are passed in as api_data.
        //They are formatted thus:
        //
        //sort: [ "foo", "!bar", ["baz","numeric"] ]
        //  "foo" is sorted normally, "bar" is descending, then "baz" with method "numeric"
        //  NB: "normally" means that the API determines the sort method to use.
        //
        //filter: [ ["foo","contains","whatsit"], ["baz","gt",2], ["*","contains","bar"]
        //  each [] is column,type,term
        //  column of "*" is a wild-card search (only does "contains")
        //
        //paginate: { start: 12, size: 20 }
        //  gets 20 records starting at index 12 (0-indexed)
        //
        //NOTE: sorting, filtering, and paginating do NOT work with cPanel API 1!

        var api = {
            MODULE_NAME: MODULE_NAME,
            MODULE_DESC: MODULE_DESC,
            MODULE_VERSION: MODULE_VERSION,

            /**
             * Setup the api call promise
             *
             * @method promise
             * @static
             * @param  {Object} args_obj Object containing the arguments for the call
             * @return {Promise} A promise that encapsulates the request.
             */
            promise: function(args_obj) {
                if(typeof args_obj === "undefined"){
                    throw new Error("Parameter args_obj does not exist.");
                }
                var is_whm = _find_is_whm(args_obj);
                var api_version = _find_api_version(args_obj);

                // Retrieve the driver for the selected api
                var api_driver = _get_api_driver(is_whm, api_version);

                if (!api_driver) {
                    var msg = "Could not find the driver for the API version requested:" + CJT.applicationName + " " + api_version;
                    throw msg;
                }

                // Fix up the filter callback
                var filter = _build_data_filter(api_version, args_obj, api_driver);

                // Get the url from the driver
                var url = api_driver.get_url(CJT.securityToken, args_obj);

                var query = _construct_api_query(args_obj, api_driver);

                var method = (args_obj.args && typeof args_obj.args.method !== "undefined") ? args_obj.args.method : "POST";

                // Start the request
                var req_obj = _ajax(
                    method,
                    url,
                    query,
                    filter,
                    args_obj.json
                );

                return req_obj;
            }
        };

        return api;
    }
);
/* eslint-enable */
Back to Directory File Manager