UNPKG

@cpanel/api

Version:

cPanel API JavaScript and TypeScript interface libraries. This library provides a set of classes for calling cPanel WHM API 1 and UAPI calls. The classes hide much of the complexity of these APIs behind classes the abstract the underlying variances betwee

306 lines 11.6 kB
"use strict"; // MIT License // // Copyright 2021 cPanel L.L.C. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UapiRequest = void 0; const snakeCase_1 = __importDefault(require("lodash/snakeCase")); const Perl = __importStar(require("../utils/perl")); const sort_1 = require("../utils/sort"); const filter_1 = require("../utils/filter"); const request_1 = require("../request"); const verb_1 = require("../http/verb"); const headers_1 = require("../utils/headers"); const argument_serializer_rules_1 = require("../argument-serializer-rules"); const encoders_1 = require("../utils/encoders"); class UapiRequest extends request_1.Request { /** * Add a custom HTTP header to the request * * @param name Name of a column * @return Updated Request object. */ addHeader(header) { if (header instanceof headers_1.WhmApiTokenHeader) { throw new headers_1.WhmApiTokenMismatchError("A WhmApiTokenHeader cannot be used on a CpanelApiRequest"); } super.addHeader(header); return this; } /** * Build a fragment of the parameter list based on the list of name/value pairs. * * @param params Parameters to serialize. * @param encoder Encoder to use to serialize the each parameter. * @return Fragment with the serialized parameters */ _build(params, encoder) { let fragment = ""; params.forEach((arg, index, array) => { const isLast = index === array.length - 1; fragment += encoder.encode(arg.name, arg.value, isLast); }); return encoder.separatorStart + fragment + encoder.separatorEnd; } /** * Generates the arguments for the request. * * @param params List of parameters to adjust based on the sort rules in the Request. */ _generateArguments(params) { this.arguments.forEach((argument) => params.push(argument)); } /** * Generates the sort parameters for the request. * * @param params List of parameters to adjust based on the sort rules in the Request. */ _generateSorts(params) { this.sorts.forEach((sort, index) => { if (index === 0) { params.push({ name: "api.sort", value: Perl.fromBoolean(true), }); } params.push({ name: "api.sort_column_" + index, value: sort.column, }); params.push({ name: "api.sort_reverse_" + index, value: Perl.fromBoolean(sort.direction !== sort_1.SortDirection.Ascending), }); params.push({ name: "api.sort_method_" + index, value: (0, snakeCase_1.default)(sort_1.SortType[sort.type]), }); }); } /** * Look up the correct name for the filter operator * * @param operator Type of filter operator to use to filter the items * @returns The string counter part for the filter operator. * @throws Will throw an error if an unrecognized FilterOperator is provided. */ _lookupFilterOperator(operator) { switch (operator) { case filter_1.FilterOperator.GreaterThanUnlimited: return "gt_handle_unlimited"; case filter_1.FilterOperator.GreaterThan: return "gt"; case filter_1.FilterOperator.LessThanUnlimited: return "lt_handle_unlimited"; case filter_1.FilterOperator.LessThan: return "lt"; case filter_1.FilterOperator.NotEqual: return "ne"; case filter_1.FilterOperator.Equal: return "eq"; case filter_1.FilterOperator.Defined: return "defined"; case filter_1.FilterOperator.Undefined: return "undefined"; case filter_1.FilterOperator.Matches: return "matches"; case filter_1.FilterOperator.Ends: return "ends"; case filter_1.FilterOperator.Begins: return "begins"; case filter_1.FilterOperator.Contains: return "contains"; default: // eslint-disable-next-line no-case-declarations -- just used for readability const key = filter_1.FilterOperator[operator]; throw new Error(`Unrecognized FilterOperator ${key} for UAPI`); } } /** * Generate the filter parameters if any. * * @param params List of parameters to adjust based on the filter rules provided. */ _generateFilters(params) { this.filters.forEach((filter, index) => { params.push({ name: "api.filter_column_" + index, value: filter.column, }); params.push({ name: "api.filter_type_" + index, value: this._lookupFilterOperator(filter.operator), }); params.push({ name: "api.filter_term_" + index, value: filter.value, }); }); } /** * In UAPI, we request the starting record, not the starting page. This translates * the page and page size into the correct starting record. */ _traslatePageToStart(pager) { return (pager.page - 1) * pager.pageSize + 1; } /** * Generate the pager request parameters, if any. * * @param params List of parameters to adjust based on the pagination rules. */ _generatePagination(params) { if (!this.usePager) { return; } const allPages = this.pager.all(); params.push({ name: "api.paginate", value: Perl.fromBoolean(true), }); params.push({ name: "api.paginate_start", value: allPages ? -1 : this._traslatePageToStart(this.pager), }); if (!allPages) { params.push({ name: "api.paginate_size", value: this.pager.pageSize, }); } } /** * Generate any additional parameters from the configuration data. * * @param params List of parameters to adjust based on the configuration. */ _generateConfiguration(params) { if (this.config && this.config["analytics"]) { params.push({ name: "api.analytics", value: Perl.fromBoolean(this.config.analytics), }); } } /** * Create a new uapi request. * * @param init Optional request objects used to initialize this object. */ constructor(init) { super(init); } /** * Generate the interchange object that has the pre-encoded * request using UAPI formatting. * * @param rule Optional parameter to specify a specific Rule we want the Request to be generated for. * @return Request information ready to be used by a remoting layer */ generate(rule) { // Needed for pure JS clients, since they don't get the compiler checks if (!this.namespace) { throw new Error("You must define a namespace for the UAPI call before you generate a request"); } if (!this.method) { throw new Error("You must define a method for the UAPI call before you generate a request"); } if (!rule) { rule = { verb: verb_1.HttpVerb.POST, encoder: this.config.json ? new encoders_1.JsonArgumentEncoder() : new encoders_1.WwwFormUrlArgumentEncoder(), }; } if (!rule.encoder) { rule.encoder = this.config.json ? new encoders_1.JsonArgumentEncoder() : new encoders_1.WwwFormUrlArgumentEncoder(); } const argumentRule = argument_serializer_rules_1.argumentSerializationRules.getRule(rule.verb); const info = { headers: new headers_1.Headers([ { name: "Content-Type", value: rule.encoder.contentType, }, ]), url: ["", "execute", this.namespace, this.method] .map(encodeURIComponent) .join("/"), body: "", }; const params = []; this._generateArguments(params); this._generateSorts(params); this._generateFilters(params); this._generatePagination(params); this._generateConfiguration(params); const encoded = this._build(params, rule.encoder); if (argumentRule.dataInBody) { info["body"] = encoded; } else { if (rule.verb === verb_1.HttpVerb.GET) { info["url"] += `?${encoded}`; } else { info["url"] += encoded; } } this.headers.forEach((header) => { info.headers.push({ name: header.name, value: header.value, }); }); return info; } } exports.UapiRequest = UapiRequest; //# sourceMappingURL=request.js.map