Skip to content

Commit

Permalink
--wip-- [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
hsablonniere committed Oct 4, 2024
1 parent 4bfdcb0 commit 945efba
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 5 deletions.
13 changes: 9 additions & 4 deletions bin/clever.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ if (hasParam('--autocomplete-index')) {
const colors = require('colors');
const colorExplicitFalse = hasParam('--no-color') || hasParam('--color', 'false');
const colorExplicitTrue = hasParam('--color', 'true');
if (colorExplicitFalse || (!process.stdout.isTTY && !colorExplicitTrue)) {
colors.disable();
}
// if (colorExplicitFalse || (!process.stdout.isTTY && !colorExplicitTrue)) {
// colors.disable();
// }

// These need to be set before Logger and other stuffs
const pkg = require('../package.json');
Expand Down Expand Up @@ -158,6 +158,7 @@ function run () {
logsFormat: getOutputFormatOption(['json-stream']),
activityFormat: getOutputFormatOption(['json-stream']),
envFormat: getOutputFormatOption(['shell']),
domainListFormat: getOutputFormatOption(['csv']),
accesslogsFollow: cliparse.flag('follow', {
aliases: ['f'],
description: 'Display access logs continuously (ignores before/until, after/since)',
Expand Down Expand Up @@ -754,10 +755,14 @@ function run () {
description: 'Manage the favourite domain name for an application',
commands: [domainSetFavouriteCommand, domainUnsetFavouriteCommand],
}, domain('getFavourite'));
const domainListAllCommand = cliparse.command('list-all', {
description: 'TODO',
options: [opts.domainListFormat],
}, domain('listAll'));
const domainCommands = cliparse.command('domain', {
description: 'Manage domain names for an application',
options: [opts.alias, opts.appIdOrName],
commands: [domainCreateCommand, domainFavouriteCommands, domainRemoveCommand],
commands: [domainCreateCommand, domainFavouriteCommands, domainRemoveCommand, domainListAllCommand],
}, domain('list'));

// DRAIN COMMANDS
Expand Down
41 changes: 41 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"cliparse": "0.4.0",
"colors": "1.4.0",
"common-env": "6.4.0",
"csv-stringify": "6.5.1",
"curlconverter": "3.21.0",
"duration-js": "4.0.0",
"eventsource": "1.1.0",
Expand All @@ -43,6 +44,7 @@
"string-length": "4.0.2",
"superagent": "6.1.0",
"text-table": "0.2.0",
"tldts": "6.1.46",
"update-notifier": "5.1.0",
"uuid": "8.3.2",
"ws": "7.4.6",
Expand Down
146 changes: 145 additions & 1 deletion src/commands/domain.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ const {
removeDomain,
} = require('@clevercloud/client/cjs/api/v2/application.js');
const { sendToApi } = require('../models/send-to-api.js');
const { getSummary } = require('@clevercloud/client/cjs/api/v2/user.js');
const { getAllDomains } = require('@clevercloud/client/cjs/api/v2/application.js');
const { parse: parseDomain } = require('tldts');
const _ = require('lodash');
const colors = require('colors/safe.js');
const { stringify: stringifyCsv } = require('csv-stringify/sync');

function getFavouriteDomain ({ ownerId, appId }) {
return getFavouriteDomainWithError({ id: ownerId, appId })
Expand Down Expand Up @@ -89,4 +95,142 @@ async function rm (params) {
Logger.println('Your domain has been successfully removed');
}

module.exports = { list, add, getFavourite, setFavourite, unsetFavourite, rm };
async function listAll (params) {

const { format } = params.options;
const filter = '';

const summary = await getSummary().then(sendToApi);
const consoleUrl = summary.user.partnerConsoleUrl;

const applications = [
...summary.user.applications.map((app) => {
return { ownerName: summary.user.name, ownerId: summary.user.id, ...app };
}),
...summary.organisations.flatMap((o) => {
return o.applications.map((app) => {
return { ownerName: o.name, ownerId: o.id, ...app };
});
}),
];

const applicationsWithDomains = await Promise.all(
applications.map(async (app) => {
const domains = await getAllDomains({ id: app.ownerId, appId: app.id }).then(sendToApi);
return { app, domains };
}),
);

const applicationsWithParsedDomain = applicationsWithDomains
.flatMap(({ app, domains }) => {
return domains
.filter((domain) => domain.fqdn.includes(filter))
.map((domain) => {

const parsedDomain = parseDomain(domain.fqdn);
const pathname = new URL('https://' + domain.fqdn).pathname;
const subdomains = parsedDomain.subdomain !== '' ? parsedDomain.subdomain.split('.') : [];

// We're trying to create an propertyPath for lodash to create a tree structure object,
// the propertyPath for `aaa.bbb.ccc.example.com/the-path` would be:
// ["example.com", "example.com.ccc", "example.com.ccc.bbb", "example.com.ccc.bbb.aaa", "/path-aaa"]",

const sortSegments = [parsedDomain.domain, ...subdomains.reverse()];
const propetyPath = sortSegments.map((item, i, all) => {
return all.slice(0, i + 1).reverse().join('.');
});
propetyPath.push(pathname);

return {
ownerId: app.ownerId,
ownerName: app.ownerName,
appId: app.id,
appName: app.name,
appConsoleUrl: `${consoleUrl}/${app.id}`,
appVariantSlug: app.variantSlug,
domain: domain.fqdn,
propetyPath,
};
});
});

const applicationsWithParsedDomainAsTree = {};
for (const { propetyPath, ...appWithDomain } of applicationsWithParsedDomain) {
_.set(applicationsWithParsedDomainAsTree, propetyPath, appWithDomain);
}

const applicationsWithParsedDomainAsSortedTree = recursiveSort(applicationsWithParsedDomainAsTree);

switch (format) {
case 'json':
Logger.printJson(applicationsWithParsedDomainAsSortedTree);
break;
case 'csv':

// TODO improve
const applicationsWithParsedDomainCsv = stringifyCsv(recursiveFlatten(applicationsWithParsedDomainAsSortedTree)
.map((app) => {
return [
app.ownerId,
app.ownerName,
app.appId,
app.appName,
app.domain,
];
}));

Logger.println(applicationsWithParsedDomainCsv);
break;
case 'human':
default:
// TODO empty message (with filter)
recursiveDisplay(applicationsWithParsedDomainAsSortedTree);
break;
}
}

function recursiveFlatten (obj) {
if (typeof obj === 'object' && obj.appId != null) {
return [obj];
}
return Object.values(obj).flatMap((value) => {
return recursiveFlatten(value);
});
}

function recursiveSort (obj) {

if (typeof obj === 'object' && obj.appId != null) {
return obj;
}

const sortedObj = {};
Object.keys(obj).sort((a, b) => a.localeCompare(b)).forEach((key) => {
sortedObj[key] = recursiveSort(obj[key]);
});

return sortedObj;
}

function recursiveDisplay (obj, indentLevel = 0, isLast) {

if (typeof obj === 'object' && obj.appId != null) {
Logger.println(' '.repeat(indentLevel) + `${obj.ownerName} / ${obj.appName} / ${obj.appVariantSlug}`);
// TODO implement this console route
Logger.println(' '.repeat(indentLevel) + colors.blue(obj.appConsoleUrl));
return;
}

for (const [propertyPath, subObj] of Object.entries(obj)) {
if (propertyPath !== '/') {
Logger.println('');
Logger.println(' '.repeat(indentLevel) + colors.yellow(propertyPath));
recursiveDisplay(subObj, indentLevel + 2);
}
else {
recursiveDisplay(subObj, indentLevel);
}
}
}

module.exports = { list, add, getFavourite, setFavourite, unsetFavourite, rm, listAll };
1 change: 1 addition & 0 deletions src/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function formatLines (prefixLength, lines) {
}

function consoleErrorWithoutColor (line) {
console.error(line);
process.stderr.write(line + '\n');
}

Expand Down

0 comments on commit 945efba

Please sign in to comment.