cx-client
Version:
Cloudonix CLI tool for managing accounts and resources
252 lines (211 loc) • 9.2 kB
JavaScript
const { loadConfig } = require('../utils/config');
const { getDomainInfo, getSubscriberInfo, getApplicationInfo, getTrunkInfo, getDnidInfo } = require('../utils/api');
const { debug } = require('../utils/debug');
const yaml = require('yaml');
const chalk = require('chalk');
/**
* Helper to format nested objects for display
* @param {Object} obj - The object to format
* @param {number} indent - Current indentation level
* @returns {string} Formatted string representation
*/
const formatObject = (obj, indent = 0) => {
const indentStr = ' '.repeat(indent);
let output = '';
for (const [key, value] of Object.entries(obj)) {
if (value === null) {
output += `${indentStr}${key}: null\n`;
} else if (Array.isArray(value)) {
if (value.length === 0) {
output += `${indentStr}${key}: []\n`;
} else if (typeof value[0] === 'object' && value[0] !== null) {
output += `${indentStr}${key}:\n`;
value.forEach((item, index) => {
output += `${indentStr} [${index}]:\n${formatObject(item, indent + 2)}`;
});
} else {
output += `${indentStr}${key}: ${JSON.stringify(value)}\n`;
}
} else if (typeof value === 'object') {
output += `${indentStr}${key}:\n${formatObject(value, indent + 1)}`;
} else {
output += `${indentStr}${key}: ${value}\n`;
}
}
return output;
};
/**
* Formats domain information in a human-readable way
* @param {Object} domainInfo - The domain information
* @returns {string} Formatted domain information
*/
const formatDomainInfo = (domainInfo) => {
// Ensure we have something to display
if (!domainInfo) {
return 'No domain information available';
}
let output = '\n=== Domain Information ===\n\n';
return output + formatObject(domainInfo);
};
/**
* Format data as YAML with highlighting (similar to call.js)
* @param {Object} data - The data to format
* @param {string} title - Title to display
* @returns {string} Formatted YAML with colors
*/
const formatYaml = (data, title) => {
if (!data) {
return 'No data available';
}
// Add a title
let output = chalk.bold.blue(`\n=== ${title} ===\n\n`);
// Convert to YAML
const yamlString = yaml.stringify(data);
// Add basic color highlighting
const coloredLines = yamlString.split('\n').map(line => {
// Handle key: value lines
if (line.includes(':')) {
const colonPos = line.indexOf(':');
const key = line.substring(0, colonPos);
const value = line.substring(colonPos + 1);
return chalk.cyan(key + ':') + processValue(value);
}
// Handle list items
if (line.trim().startsWith('-')) {
return line.replace('-', chalk.yellow('-'));
}
return line;
});
return output + coloredLines.join('\n');
};
/**
* Process and color a YAML value (copied from call.js for consistency)
* @param {string} value - The YAML value to process
* @returns {string} Colored value
*/
function processValue(value) {
// Empty or null values
if (!value.trim() || value.trim() === 'null') {
return value;
}
// Numbers
if (value.trim().match(/^-?\d+(\.\d+)?$/)) {
return value.replace(/(-?\d+(\.\d+)?)/, chalk.yellow('$1'));
}
// Booleans
if (value.trim() === 'true' || value.trim() === 'false') {
return value.replace(/(true|false)/, chalk.yellow('$1'));
}
// Dates (ISO format)
if (value.trim().match(/\d{4}-\d{2}-\d{2}T/)) {
return value.replace(/(\d{4}-\d{2}-\d{2}T[\d:.Z+-]+)/, chalk.green('$1'));
}
// Strings in quotes
if (value.trim().match(/^".*"$/) || value.trim().match(/^'.*'$/)) {
return value.replace(/(["']).*\1/, chalk.green('$&'));
}
return value;
}
/**
* Gets and displays information about a domain
* @param {Object} options - Command options
* @param {string} options.domain - The domain name
* @param {string} options.subscriber - Optional subscriber ID
* @param {string} options.application - Optional application ID
* @param {string} options.trunk - Optional trunk ID
* @param {string} options.dnid - Optional DNID ID
*/
const getDomain = async (options) => {
const { domain, subscriber, application, trunk, dnid } = options;
if (!domain) {
console.error('The --domain option is required');
process.exit(1);
}
try {
debug(`Getting information for domain '${domain}'`);
// Load the configuration
const config = await loadConfig();
// Check if the domain exists in configuration
if (!config.domains || !config.domains[domain]) {
console.error(`Domain '${domain}' not found in configuration. Use 'cx-cli configure' to add it.`);
process.exit(1);
}
const apiKey = config.domains[domain].apiKey;
// Count how many resource options are specified
const resourceOptionsCount = [subscriber, application, trunk, dnid].filter(option => option !== undefined).length;
// Determine which type of information to get based on the options
if (resourceOptionsCount > 1) {
// If multiple resource options are specified, display an error
console.error('Error: Cannot specify multiple resource options (--subscriber, --application, --trunk, --dnid) simultaneously');
process.exit(1);
} else if (subscriber !== undefined) {
// If subscriber is true, it means the --subscriber flag was used without a value
// In this case, we want to get all subscribers (pass null as subscriberId)
const subscriberId = subscriber === true ? null : subscriber;
// Get subscriber information
debug(`Retrieving subscriber information${subscriberId ? ` for subscriber '${subscriberId}'` : ' (all subscribers)'}`);
const subscriberInfo = await getSubscriberInfo(domain, apiKey, subscriberId);
// Format title based on whether we're getting one subscriber or all subscribers
const title = subscriberId
? `Subscriber Information for ${subscriberId}`
: `All Subscribers for Domain ${domain}`;
// Format and display subscriber information
const formattedInfo = formatYaml(subscriberInfo, title);
console.log(formattedInfo);
} else if (application !== undefined) {
// If application is true, it means the --application flag was used without a value
// In this case, we want to get all applications (pass null as applicationId)
const applicationId = application === true ? null : application;
// Get application information
debug(`Retrieving application information${applicationId ? ` for application '${applicationId}'` : ' (all applications)'}`);
const applicationInfo = await getApplicationInfo(domain, apiKey, applicationId);
// Format title based on whether we're getting one application or all applications
const title = applicationId
? `Application Information for ${applicationId}`
: `All Applications for Domain ${domain}`;
// Format and display application information
const formattedInfo = formatYaml(applicationInfo, title);
console.log(formattedInfo);
} else if (trunk !== undefined) {
// If trunk is true, it means the --trunk flag was used without a value
// In this case, we want to get all trunks (pass null as trunkId)
const trunkId = trunk === true ? null : trunk;
// Get trunk information
debug(`Retrieving trunk information${trunkId ? ` for trunk '${trunkId}'` : ' (all trunks)'}`);
const trunkInfo = await getTrunkInfo(domain, apiKey, trunkId);
// Format title based on whether we're getting one trunk or all trunks
const title = trunkId
? `Trunk Information for ${trunkId}`
: `All Trunks for Domain ${domain}`;
// Format and display trunk information
const formattedInfo = formatYaml(trunkInfo, title);
console.log(formattedInfo);
} else if (dnid !== undefined) {
// If dnid is true, it means the --dnid flag was used without a value
// In this case, we want to get all DNIDs (pass null as dnidId)
const dnidId = dnid === true ? null : dnid;
// Get DNID information
debug(`Retrieving DNID information${dnidId ? ` for DNID '${dnidId}'` : ' (all DNIDs)'}`);
const dnidInfo = await getDnidInfo(domain, apiKey, dnidId);
// Format title based on whether we're getting one DNID or all DNIDs
const title = dnidId
? `DNID Information for ${dnidId}`
: `All DNIDs for Domain ${domain}`;
// Format and display DNID information
const formattedInfo = formatYaml(dnidInfo, title);
console.log(formattedInfo);
} else {
// Get domain information from API
const domainInfo = await getDomainInfo(domain, apiKey);
// Format and display domain information using the new YAML formatter
const formattedInfo = formatYaml(domainInfo, `Domain Information for ${domain}`);
console.log(formattedInfo);
}
} catch (error) {
console.error(`Error getting information: ${error.message}`);
process.exit(1);
}
};
module.exports = {
getDomain
};