[ACS-5845] remove Alfresco Compatibility usage (#8822)

* upgrade to latest js-api

* upgrade to latest js-api

* upgrade to latest js-api

* upgrade to latest js-api

* upgrade to latest js-api

* upgrade to latest js-api

* fix security concerns for execSync

* security fix

* fixes as per code reviews

* code fixes for attach file widget dialog

* code fixes

* code fixes

* disable ACS storage check

* add the jira to the commented out block

* remove useless logger call

* code fixes

* code fixes

* code fixes

* code and typing fixes

* fix lint

* disable the code

* try other fixes, add missing headers

* dump error to console

* replace test file with in-memory stream

* code fixes

* simplify checks

* disable upload

* remove useless test and ng-mocks dependency
This commit is contained in:
Denys Vuika 2023-08-22 00:02:39 +01:00 committed by GitHub
parent d0c35c28ee
commit 29ec2fcc96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 682 additions and 676 deletions

View File

@ -1,8 +1,8 @@
const fs = require('fs'); const { spawnSync } = require('node:child_process');
const rimraf = require('rimraf'); const fs = require('node:fs');
const path = require('path'); const path = require('node:path');
const TestConfig = require('../test.config'); const TestConfig = require('../test.config');
const AlfrescoApi = require('@alfresco/js-api').AlfrescoApiCompatibility; const { AlfrescoApi, NodesApi, UploadApi } = require('@alfresco/js-api');
function buildNumber() { function buildNumber() {
let buildNumber = process.env.GH_BUILD_NUMBER; let buildNumber = process.env.GH_BUILD_NUMBER;
@ -16,54 +16,57 @@ function buildNumber() {
async function uploadScreenshot(retryCount, suffixFileName) { async function uploadScreenshot(retryCount, suffixFileName) {
console.log(`Start uploading report ${retryCount}`); console.log(`Start uploading report ${retryCount}`);
let alfrescoJsApi = new AlfrescoApi({ const alfrescoJsApi = new AlfrescoApi({
provider: 'ECM', provider: 'ECM',
hostEcm: TestConfig.screenshot.url hostEcm: TestConfig.screenshot.url
}); });
const nodesApi = new NodesApi(alfrescoJsApi);
const uploadApi = new UploadApi(alfrescoJsApi);
await alfrescoJsApi.login(TestConfig.users.screenshot.username, TestConfig.users.screenshot.password); await alfrescoJsApi.login(TestConfig.users.screenshot.username, TestConfig.users.screenshot.password);
let folderNode; let folderNode;
try { try {
folderNode = await alfrescoJsApi.nodes.addNode('-my-', { folderNode = await nodesApi.createNode(
'name': `retry-${retryCount}`, '-my-',
'relativePath': `Builds/${buildNumber()}/`, {
'nodeType': 'cm:folder' name: `retry-${retryCount}`,
}, {}, { relativePath: `Builds/${buildNumber()}/`,
'overwrite': true nodeType: 'cm:folder'
}); },
{},
{
overwrite: true
}
);
} catch (error) { } catch (error) {
folderNode = await alfrescoJsApi.nodes.getNode('-my-', { folderNode = await nodesApi.getNode('-my-', {
'relativePath': `Builds/${buildNumber()}/retry-${retryCount}`, relativePath: `Builds/${buildNumber()}/retry-${retryCount}`
'nodeType': 'cm:folder'
}, {}, {
'overwrite': true
}); });
} }
suffixFileName = suffixFileName.replace(/\//g, '-'); suffixFileName = suffixFileName.replace(/\//g, '-');
fs.renameSync(path.resolve(__dirname, '../../e2e-output/'), path.resolve(__dirname, `../../e2e-output-${retryCount}-${process.env.GH_ACTION_RETRY_COUNT}/`)) fs.renameSync(
path.resolve(__dirname, '../../e2e-output/'),
path.resolve(__dirname, `../../e2e-output-${retryCount}-${process.env.GH_ACTION_RETRY_COUNT}/`)
);
const child_process = require("child_process"); spawnSync(` tar -czvf ../e2e-result-${suffixFileName}-${retryCount}.tar .`, {
child_process.execSync(` tar -czvf ../e2e-result-${suffixFileName}-${retryCount}.tar .`, { cwd: path.resolve(__dirname, `../../e2e-output-${retryCount}-${process.env.GH_ACTION_RETRY_COUNT}/`),
cwd: path.resolve(__dirname, `../../e2e-output-${retryCount}-${process.env.GH_ACTION_RETRY_COUNT}/`) shell: false
}); });
let pathFile = path.join(__dirname, `../../e2e-result-${suffixFileName}-${retryCount}.tar`); const pathFile = path.join(__dirname, `../../e2e-result-${suffixFileName}-${retryCount}.tar`);
let file = fs.createReadStream(pathFile); const file = fs.createReadStream(pathFile);
await alfrescoJsApi.upload.uploadFile(
file, await uploadApi.uploadFile(file, '', folderNode.entry.id, null, {
'', name: `e2e-result-${suffixFileName}-${retryCount}.tar`,
folderNode.entry.id, nodeType: 'cm:content',
null, autoRename: true
{ });
'name': `e2e-result-${suffixFileName}-${retryCount}.tar`,
'nodeType': 'cm:content',
'autoRename': true
}
);
} }
module.exports = { module.exports = {

View File

@ -1,16 +1,31 @@
/* eslint-disable */ /*!
const alfrescoApi = require('@alfresco/js-api'); * @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AlfrescoApi, NodesApi, UploadApi } from '@alfresco/js-api';
import { argv, exit } from 'node:process';
import { Buffer } from 'node:buffer';
const program = require('commander'); const program = require('commander');
const path = require('path');
const fs = require('fs');
/* eslint-enable */
import { logger } from './logger'; import { logger } from './logger';
const MAX_RETRY = 3; const MAX_RETRY = 3;
const TIMEOUT = 20000; const TIMEOUT = 20000;
let counter = 0; let counter = 0;
let alfrescoJsApi: AlfrescoApi;
export default async function main(_args: string[]) { export default async function main(_args: string[]) {
program program
.version('0.1.0') .version('0.1.0')
.description('Check Content service is up ') .description('Check Content service is up ')
@ -20,24 +35,26 @@ export default async function main(_args: string[]) {
.option('-u, --username [type]', 'username ') .option('-u, --username [type]', 'username ')
.option('-t, --time [type]', 'time ') .option('-t, --time [type]', 'time ')
.option('-r, --retry [type]', 'retry ') .option('-r, --retry [type]', 'retry ')
.parse(process.argv); .parse(argv);
await checkEnv(); await checkEnv();
await checkDiskSpaceFullEnv(); // TODO: https://alfresco.atlassian.net/browse/ACS-5873
// await checkDiskSpaceFullEnv();
} }
async function checkEnv() { async function checkEnv() {
try { try {
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({ alfrescoJsApi = new AlfrescoApi({
provider: 'ECM', provider: 'ECM',
hostEcm: program.host hostEcm: program.host,
contextRoot: 'alfresco'
}); });
await alfrescoJsApi.login(program.username, program.password); await alfrescoJsApi.login(program.username, program.password);
} catch (error) { } catch (error) {
if (error?.error?.code === 'ETIMEDOUT') { if (error?.error?.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating'); logger.error('The env is not reachable. Terminating');
process.exit(1); exit(1);
} }
logger.error('Login error environment down or inaccessible'); logger.error('Login error environment down or inaccessible');
counter++; counter++;
@ -45,63 +62,33 @@ async function checkEnv() {
const time = program.time || TIMEOUT; const time = program.time || TIMEOUT;
if (retry === counter) { if (retry === counter) {
logger.error('Give up'); logger.error('Give up');
process.exit(1); exit(1);
} else { } else {
logger.error(`Retry in 1 minute attempt N ${counter}`, error); logger.error(`Retry in 1 minute attempt N ${counter}`, error);
sleep(time); sleep(time);
checkEnv(); await checkEnv();
} }
} }
} }
// @ts-ignore
async function checkDiskSpaceFullEnv() { async function checkDiskSpaceFullEnv() {
logger.info(`Start Check disk full space`); logger.info(`Start Check disk full space`);
try { try {
const nodesApi = new NodesApi(alfrescoJsApi);
const uploadApi = new UploadApi(alfrescoJsApi);
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({ const fileContent = 'x'.repeat(1024 * 1024);
provider: 'ECM', const file = Buffer.from(fileContent, 'utf8');
hostEcm: program.host
});
await alfrescoJsApi.login(program.username, program.password); const uploadedFile = await uploadApi.uploadFile(file, '', '-my-', null, {
let folder;
try {
folder = await alfrescoJsApi.nodes.addNode('-my-', {
name: `try-env`,
relativePath: `Builds`,
nodeType: 'cm:folder'
}, {}, {
overwrite: true
});
} catch (error) {
folder = await alfrescoJsApi.nodes.getNode('-my-', {
relativePath: `Builds/try-env`,
nodeType: 'cm:folder'
}, {}, {
overwrite: true
});
}
const pathFile = path.join(__dirname, '../', 'README.md');
const file = fs.createReadStream(pathFile);
const uploadedFile = await alfrescoJsApi.upload.uploadFile(
file,
'',
folder.entry.id,
null,
{
name: 'README.md', name: 'README.md',
nodeType: 'cm:content', nodeType: 'cm:content',
autoRename: true autoRename: true
} });
);
alfrescoJsApi.node.deleteNode(uploadedFile.entry.id, {permanent: true}); await nodesApi.deleteNode(uploadedFile.entry.id, { permanent: true });
} catch (error) { } catch (error) {
counter++; counter++;
@ -112,18 +99,17 @@ async function checkDiskSpaceFullEnv() {
logger.info('================ Not able to upload a file =================='); logger.info('================ Not able to upload a file ==================');
logger.info('================ Possible cause CS is full =================='); logger.info('================ Possible cause CS is full ==================');
logger.info('============================================================='); logger.info('=============================================================');
process.exit(1); exit(1);
} else { } else {
logger.error(`Retry N ${counter} ${error?.error?.status}`); logger.error(`Retry N ${counter}`);
logger.error(JSON.stringify(error));
sleep(time); sleep(time);
checkDiskSpaceFullEnv(); await checkDiskSpaceFullEnv();
}
}
} }
} function sleep(delay: number) {
}
function sleep(delay) {
const start = new Date().getTime(); const start = new Date().getTime();
while (new Date().getTime() < start + delay) {} while (new Date().getTime() < start + delay) {}
} }

View File

@ -1,14 +1,29 @@
/* eslint-disable */ /*!
const alfrescoApi = require('@alfresco/js-api'); * @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AlfrescoApi } from '@alfresco/js-api';
import { exit, argv } from 'node:process';
const program = require('commander'); const program = require('commander');
/* eslint-enable */
import { logger } from './logger'; import { logger } from './logger';
const MAX_RETRY = 10; const MAX_RETRY = 10;
const TIMEOUT = 60000; const TIMEOUT = 60000;
let counter = 0; let counter = 0;
export default async function main(_args: string[]) { export default async function main(_args: string[]) {
program program
.version('0.1.0') .version('0.1.0')
.description('Check Process service is up ') .description('Check Process service is up ')
@ -16,38 +31,39 @@ export default async function main(_args: string[]) {
.option('--host [type]', 'Remote environment host adf.lab.com ') .option('--host [type]', 'Remote environment host adf.lab.com ')
.option('-p, --password [type]', 'password ') .option('-p, --password [type]', 'password ')
.option('-u, --username [type]', 'username ') .option('-u, --username [type]', 'username ')
.parse(process.argv); .parse(argv);
await checkEnv(); await checkEnv();
} }
async function checkEnv() { async function checkEnv() {
try { try {
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({ const alfrescoJsApi = new AlfrescoApi({
provider: 'BPM', provider: 'BPM',
hostBpm: program.host hostBpm: program.host,
contextRoot: 'alfresco'
}); });
await alfrescoJsApi.login(program.username, program.password); await alfrescoJsApi.login(program.username, program.password);
} catch (e) { } catch (e) {
if (e.error.code === 'ETIMEDOUT') { if (e.error.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating'); logger.error('The env is not reachable. Terminating');
process.exit(1); exit(1);
} }
logger.error('Login error environment down or inaccessible'); logger.error('Login error environment down or inaccessible');
counter++; counter++;
if (MAX_RETRY === counter) { if (MAX_RETRY === counter) {
logger.error('Give up'); logger.error('Give up');
process.exit(1); exit(1);
} else { } else {
logger.error(`Retry in 1 minute attempt N ${counter}`); logger.error(`Retry in 1 minute attempt N ${counter}`);
sleep(TIMEOUT); sleep(TIMEOUT);
checkEnv(); await checkEnv();
} }
} }
} }
function sleep(delay) { function sleep(delay: number) {
const start = new Date().getTime(); const start = new Date().getTime();
while (new Date().getTime() < start + delay) {} while (new Date().getTime() < start + delay) {}
} }

View File

@ -22,10 +22,11 @@ import request = require('request');
import * as fs from 'fs'; import * as fs from 'fs';
import { logger } from './logger'; import { logger } from './logger';
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
import { argv, exit } from 'node:process';
const ACTIVITI_CLOUD_APPS = require('./resources').ACTIVITI_CLOUD_APPS; const ACTIVITI_CLOUD_APPS = require('./resources').ACTIVITI_CLOUD_APPS;
let alfrescoJsApiModeler: any; let alfrescoJsApiModeler: AlfrescoApi;
let alfrescoJsApiDevops: any; let alfrescoJsApiDevops: AlfrescoApi;
let args: ConfigArgs; let args: ConfigArgs;
let isValid = true; let isValid = true;
const absentApps: any[] = []; const absentApps: any[] = [];
@ -45,11 +46,7 @@ export interface ConfigArgs {
envs: string[]; envs: string[];
} }
export const AAE_MICROSERVICES = [ export const AAE_MICROSERVICES = ['deployment-service', 'modeling-service', 'dmn-service'];
'deployment-service',
'modeling-service',
'dmn-service'
];
async function healthCheck(nameService: string) { async function healthCheck(nameService: string) {
const url = `${args.host}/${nameService}/actuator/health`; const url = `${args.host}/${nameService}/actuator/health`;
@ -63,8 +60,17 @@ async function healthCheck(nameService: string) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
const health = await alfrescoJsApiModeler.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, const health = await alfrescoJsApiModeler.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
if (health.status !== 'UP') { if (health.status !== 'UP') {
logger.error(`${nameService} is DOWN `); logger.error(`${nameService} is DOWN `);
isValid = false; isValid = false;
@ -93,11 +99,21 @@ async function getApplicationByStatus(status: string) {
try { try {
await alfrescoJsApiDevops.login(args.devopsUsername, args.devopsPassword); await alfrescoJsApiDevops.login(args.devopsUsername, args.devopsPassword);
return alfrescoJsApiDevops.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, const result = alfrescoJsApiDevops.oauth2Auth.callCustomApi(
contentTypes, accepts).on('error', (error) => { url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
result.on('error', (error) => {
logger.error(`Get application by status ${error} `); logger.error(`Get application by status ${error} `);
}); });
return result;
} catch (error) { } catch (error) {
logger.error(`Get application by status ${error.status} `); logger.error(`Get application by status ${error.status} `);
isValid = false; isValid = false;
@ -116,9 +132,17 @@ function getDescriptors() {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiDevops.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiDevops.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error(`Get Descriptors ${error.status} `); logger.error(`Get Descriptors ${error.status} `);
isValid = false; isValid = false;
@ -137,9 +161,17 @@ function getProjects() {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiModeler.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiModeler.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error('Get Projects' + error.status); logger.error('Get Projects' + error.status);
isValid = false; isValid = false;
@ -158,9 +190,17 @@ function getProjectRelease(projectId: string) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiModeler.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiModeler.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error('Get Projects Release' + error.status); logger.error('Get Projects Release' + error.status);
isValid = false; isValid = false;
@ -179,9 +219,17 @@ async function releaseProject(projectId: string) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiModeler.oauth2Auth.callCustomApi(url, 'POST', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiModeler.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'POST',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
await deleteProject(projectId); await deleteProject(projectId);
logger.error('Post Projects Release' + error.status); logger.error('Post Projects Release' + error.status);
@ -201,9 +249,17 @@ function deleteProject(projectId: string) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiModeler.oauth2Auth.callCustomApi(url, 'DELETE', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiModeler.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'DELETE',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error('Delete project error' + error.status); logger.error('Delete project error' + error.status);
isValid = false; isValid = false;
@ -211,20 +267,38 @@ function deleteProject(projectId: string) {
} }
async function importAndReleaseProject(absoluteFilePath: string) { async function importAndReleaseProject(absoluteFilePath: string) {
const fileContent = await fs.createReadStream(absoluteFilePath); const fileContent = fs.createReadStream(absoluteFilePath);
try { try {
const project = await alfrescoJsApiModeler.oauth2Auth.callCustomApi(`${args.host}/modeling-service/v1/projects/import`, 'POST', {}, {}, {}, { file: fileContent }, {}, ['multipart/form-data'], ['application/json']); const project = await alfrescoJsApiModeler.oauth2Auth.callCustomApi(
`${args.host}/modeling-service/v1/projects/import`,
'POST',
{},
{},
{},
{ file: fileContent },
{},
['multipart/form-data'],
['application/json']
);
logger.info(`Project imported`); logger.info(`Project imported`);
logger.info(`Create release`); logger.info(`Create release`);
const release = await alfrescoJsApiModeler.oauth2Auth.callCustomApi(`${args.host}/modeling-service/v1/projects/${project.entry.id}/releases`, 'POST', {}, {}, {}, {}, {},
['application/json'], ['application/json']);
return release;
return await alfrescoJsApiModeler.oauth2Auth.callCustomApi(
`${args.host}/modeling-service/v1/projects/${project.entry.id}/releases`,
'POST',
{},
{},
{},
{},
{},
['application/json'],
['application/json']
);
} catch (error) { } catch (error) {
logger.error(`Not able to import the project/create the release ${absoluteFilePath} with status: ${error}`); logger.error(`Not able to import the project/create the release ${absoluteFilePath} with status: ${error}`);
isValid = false; isValid = false;
throw(error); throw error;
} }
} }
@ -240,9 +314,17 @@ function deleteDescriptor(name: string) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiDevops.oauth2Auth.callCustomApi(url, 'DELETE', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiDevops.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'DELETE',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error('Delete descriptor' + error.status); logger.error('Delete descriptor' + error.status);
isValid = false; isValid = false;
@ -261,9 +343,17 @@ function deploy(model: any) {
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return alfrescoJsApiDevops.oauth2Auth.callCustomApi(url, 'POST', pathParams, queryParams, headerParams, formParams, bodyParam, return alfrescoJsApiDevops.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'POST',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error('Deploy post' + error.status); logger.error('Deploy post' + error.status);
isValid = false; isValid = false;
@ -275,14 +365,15 @@ function initializeDefaultToken(options) {
return options; return options;
} }
function getAlfrescoJsApiInstance(configArgs: ConfigArgs) { function getAlfrescoJsApiInstance(configArgs: ConfigArgs): AlfrescoApi {
let ssoHost = configArgs.oauth; let ssoHost = configArgs.oauth;
ssoHost = ssoHost ?? configArgs.host; ssoHost = ssoHost ?? configArgs.host;
const config = { const config: AlfrescoApiConfig = {
provider: 'BPM', provider: 'BPM',
hostBpm: `${configArgs.host}`, hostBpm: `${configArgs.host}`,
authType: 'OAUTH', authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: { oauth2: {
host: `${ssoHost}`, host: `${ssoHost}`,
tokenUrl: `${ssoHost}/${configArgs.tokenEndpoint}`, tokenUrl: `${ssoHost}/${configArgs.tokenEndpoint}`,
@ -294,7 +385,7 @@ function getAlfrescoJsApiInstance(configArgs: ConfigArgs) {
redirectUri: '/' redirectUri: '/'
} }
}; };
return new AlfrescoApi(config as unknown as AlfrescoApiConfig); return new AlfrescoApi(config);
} }
async function deployMissingApps(tag?: string, envs?: string[]) { async function deployMissingApps(tag?: string, envs?: string[]) {
@ -303,13 +394,13 @@ async function deployMissingApps(tag?: string, envs?: string[]) {
findFailingApps(deployedApps.list.entries); findFailingApps(deployedApps.list.entries);
if (failingApps.length > 0) { if (failingApps.length > 0) {
failingApps.forEach( app => { failingApps.forEach((app) => {
const reset = '\x1b[0m'; const reset = '\x1b[0m';
const bright = '\x1b[1m'; const bright = '\x1b[1m';
const red = '\x1b[31m'; const red = '\x1b[31m';
logger.error(`${red}${bright}ERROR: App ${app.entry.name} down or inaccessible ${reset}${red} with status ${app.entry.status}${reset}`); logger.error(`${red}${bright}ERROR: App ${app.entry.name} down or inaccessible ${reset}${red} with status ${app.entry.status}${reset}`);
}); });
process.exit(1); exit(1);
} else if (absentApps.length > 0) { } else if (absentApps.length > 0) {
logger.warn(`Missing apps: ${JSON.stringify(absentApps)}`); logger.warn(`Missing apps: ${JSON.stringify(absentApps)}`);
await checkIfAppIsReleased(absentApps, tag, envs); await checkIfAppIsReleased(absentApps, tag, envs);
@ -332,7 +423,6 @@ async function checkIfAppIsReleased(missingApps: any [], tag?: string, envs?: st
let projectRelease: any; let projectRelease: any;
if (project === undefined) { if (project === undefined) {
logger.warn('Missing project: Create the project for ' + currentAbsentApp.name); logger.warn('Missing project: Create the project for ' + currentAbsentApp.name);
try { try {
@ -342,15 +432,13 @@ async function checkIfAppIsReleased(missingApps: any [], tag?: string, envs?: st
if (error.status !== 409) { if (error.status !== 409) {
logger.info(`Not possible to upload the project ${currentAbsentApp.name} status : ${JSON.stringify(error)}`); logger.info(`Not possible to upload the project ${currentAbsentApp.name} status : ${JSON.stringify(error)}`);
process.exit(1); exit(1);
} else { } else {
logger.error(`Not possible to upload the project because inconsistency CS - Modelling try to delete manually the node`); logger.error(`Not possible to upload the project because inconsistency CS - Modelling try to delete manually the node`);
process.exit(1); exit(1);
} }
} }
} else { } else {
TIME += 5000; TIME += 5000;
logger.info('Project ' + project.entry.name + ' found'); logger.info('Project ' + project.entry.name + ' found');
@ -403,10 +491,9 @@ async function deployWithPayload(currentAbsentApp: any, projectRelease: any, env
logger.info(`Deploying ${currentAbsentApp.name} ${envId ? 'on env: ' + envId : ''}`); logger.info(`Deploying ${currentAbsentApp.name} ${envId ? 'on env: ' + envId : ''}`);
await deploy(deployPayload); await deploy(deployPayload);
logger.info(`Deployed ${currentAbsentApp.name} ${envId ? 'on env: ' + envId : ''}`); logger.info(`Deployed ${currentAbsentApp.name} ${envId ? 'on env: ' + envId : ''}`);
} }
async function checkDescriptorExist(name: string) { async function checkDescriptorExist(name: string): Promise<boolean> {
logger.info(`Check descriptor ${name} exist in the list `); logger.info(`Check descriptor ${name} exist in the list `);
const descriptorList = await getDescriptors(); const descriptorList = await getDescriptors();
@ -444,7 +531,9 @@ function findMissingApps(deployedApps: any []) {
function findFailingApps(deployedApps: any[]) { function findFailingApps(deployedApps: any[]) {
Object.keys(ACTIVITI_CLOUD_APPS).forEach((key) => { Object.keys(ACTIVITI_CLOUD_APPS).forEach((key) => {
const failingApp = deployedApps.filter((currentApp: any) => ACTIVITI_CLOUD_APPS[key].name === currentApp.entry.name && 'Running' !== currentApp.entry.status); const failingApp = deployedApps.filter(
(currentApp: any) => ACTIVITI_CLOUD_APPS[key].name === currentApp.entry.name && 'Running' !== currentApp.entry.status
);
if (failingApp?.length > 0) { if (failingApp?.length > 0) {
failingApps.push(...failingApp); failingApps.push(...failingApp);
@ -474,11 +563,12 @@ async function deleteLocalFile(name: string) {
async function sleep(time: number) { async function sleep(time: number) {
logger.info(`Waiting for ${time} sec...`); logger.info(`Waiting for ${time} sec...`);
await new Promise(done => setTimeout(done, time)); await new Promise((done) => setTimeout(done, time));
logger.info(`Done...`); logger.info(`Done...`);
return; return;
} }
// eslint-disable-next-line space-before-function-paren
export default async function () { export default async function () {
await main(); await main();
} }
@ -486,8 +576,10 @@ export default async function() {
async function main() { async function main() {
program program
.version('0.1.0') .version('0.1.0')
.description('The following command is in charge of Initializing the activiti cloud env with the default apps' + .description(
'adf-cli init-aae-env --host "gateway_env" --modelerUsername "modelerusername" --modelerPassword "modelerpassword" --devopsUsername "devevopsusername" --devopsPassword "devopspassword"') 'The following command is in charge of Initializing the activiti cloud env with the default apps' +
'adf-cli init-aae-env --host "gateway_env" --modelerUsername "modelerusername" --modelerPassword "modelerpassword" --devopsUsername "devevopsusername" --devopsPassword "devopspassword"'
)
.option('-h, --host [type]', 'Host gateway') .option('-h, --host [type]', 'Host gateway')
.option('--oauth [type]', 'SSO host') .option('--oauth [type]', 'SSO host')
.option('--clientId [type]', 'sso client') .option('--clientId [type]', 'sso client')
@ -500,9 +592,9 @@ async function main() {
.option('--devopsPassword [type]', 'devops password') .option('--devopsPassword [type]', 'devops password')
.option('--tag [type]', 'tag name of the codebase') .option('--tag [type]', 'tag name of the codebase')
.option('--envs [type...]', 'environment ids of the envs where to deploy the app') .option('--envs [type...]', 'environment ids of the envs where to deploy the app')
.parse(process.argv); .parse(argv);
if (process.argv.includes('-h') || process.argv.includes('--help')) { if (argv.includes('-h') || argv.includes('--help')) {
program.outputHelp(); program.outputHelp();
return; return;
} }
@ -530,31 +622,36 @@ async function main() {
await healthCheck(serviceName); await healthCheck(serviceName);
}); });
await alfrescoJsApiModeler.login(args.modelerUsername, args.modelerPassword).then(() => { await alfrescoJsApiModeler.login(args.modelerUsername, args.modelerPassword).then(
() => {
const reset = '\x1b[0m'; const reset = '\x1b[0m';
const green = '\x1b[32m'; const green = '\x1b[32m';
logger.info(`${green}login SSO ok${reset}`); logger.info(`${green}login SSO ok${reset}`);
}, (error) => { },
(error) => {
logger.error(`login SSO error ${JSON.stringify(error)} ${args.modelerUsername}`); logger.error(`login SSO error ${JSON.stringify(error)} ${args.modelerUsername}`);
process.exit(1); exit(1);
}); }
);
if (isValid) { if (isValid) {
const reset = '\x1b[0m'; const reset = '\x1b[0m';
const green = '\x1b[32m'; const green = '\x1b[32m';
logger.info(`${green}The environment is up and running ${reset}`); logger.info(`${green}The environment is up and running ${reset}`);
alfrescoJsApiDevops = getAlfrescoJsApiInstance(args); alfrescoJsApiDevops = getAlfrescoJsApiInstance(args);
await alfrescoJsApiDevops.login(args.devopsUsername, args.devopsPassword).then(() => { await alfrescoJsApiDevops.login(args.devopsUsername, args.devopsPassword).then(
() => {
logger.info('login SSO ok devopsUsername'); logger.info('login SSO ok devopsUsername');
}, (error) => { },
(error) => {
logger.error(`login SSO error ${JSON.stringify(error)} ${args.devopsUsername}`); logger.error(`login SSO error ${JSON.stringify(error)} ${args.devopsUsername}`);
process.exit(1); exit(1);
}); }
);
await deployMissingApps(args.tag, args.envs); await deployMissingApps(args.tag, args.envs);
} else { } else {
logger.error('The environment is not up'); logger.error('The environment is not up');
process.exit(1); exit(1);
} }
} }

View File

@ -15,39 +15,37 @@
* limitations under the License. * limitations under the License.
*/ */
const alfrescoApi = require('@alfresco/js-api'); import { AlfrescoApi, SharedlinksApi, FavoritesApi, NodesApi, UploadApi, NodeEntry } from '@alfresco/js-api';
import { exit, argv } from 'node:process';
const program = require('commander'); const program = require('commander');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
import { logger } from './logger'; import { logger } from './logger';
// eslint-disable-next-line @typescript-eslint/naming-convention
const { SharedlinksApi, FavoritesApi, NodesApi } = require('@alfresco/js-api');
const MAX_RETRY = 10; const MAX_RETRY = 10;
let counter = 0; let counter = 0;
const TIMEOUT = 6000; const TIMEOUT = 6000;
const ACS_DEFAULT = require('./resources').ACS_DEFAULT; const ACS_DEFAULT = require('./resources').ACS_DEFAULT;
let alfrescoJsApi; let alfrescoJsApi: AlfrescoApi;
// eslint-disable-next-line space-before-function-paren
export default async function () { export default async function () {
await main(); await main();
} }
async function main() { async function main() {
program program
.version('0.1.0') .version('0.1.0')
.option('--host [type]', 'Remote environment host') .option('--host [type]', 'Remote environment host')
.option('--clientId [type]', 'sso client', 'alfresco') .option('--clientId [type]', 'sso client', 'alfresco')
.option('-p, --password [type]', 'password ') .option('-p, --password [type]', 'password ')
.option('-u, --username [type]', 'username ') .option('-u, --username [type]', 'username ')
.parse(process.argv); .parse(argv);
await checkEnv(); await checkEnv();
logger.info(`***** Step initialize ACS *****`); logger.info(`***** Step initialize ACS *****`);
await initializeDefaultFiles(); await initializeDefaultFiles();
} }
async function initializeDefaultFiles() { async function initializeDefaultFiles() {
@ -81,7 +79,7 @@ async function initializeDefaultFiles() {
} }
async function createFolder(folderName: string, parentId: string) { async function createFolder(folderName: string, parentId: string) {
let createdFolder: any; let createdFolder: NodeEntry;
const body = { const body = {
name: folderName, name: folderName,
nodeType: 'cm:folder' nodeType: 'cm:folder'
@ -99,23 +97,17 @@ async function createFolder(folderName: string, parentId: string) {
return createdFolder; return createdFolder;
} }
async function uploadFile(fileName: string, fileDestination: string) { async function uploadFile(fileName: string, fileDestination: string): Promise<NodeEntry> {
const filePath = `../resources/content/${fileName}`; const filePath = `../resources/content/${fileName}`;
const file = fs.createReadStream(path.join(__dirname, filePath)); const file = fs.createReadStream(path.join(__dirname, filePath));
let uploadedFile: any; let uploadedFile: NodeEntry;
try { try {
uploadedFile = await alfrescoJsApi.upload.uploadFile( uploadedFile = await new UploadApi(alfrescoJsApi).uploadFile(file, '', fileDestination, null, {
file,
'',
fileDestination,
null,
{
name: fileName, name: fileName,
nodeType: 'cm:content', nodeType: 'cm:content',
renditions: 'doclib', renditions: 'doclib',
overwrite: true overwrite: true
} });
);
logger.info(`File ${fileName} was uploaded`); logger.info(`File ${fileName} was uploaded`);
} catch (err) { } catch (err) {
logger.error(`Failed to upload file with error: `, err.stack); logger.error(`Failed to upload file with error: `, err.stack);
@ -123,19 +115,20 @@ async function uploadFile(fileName: string, fileDestination: string) {
return uploadedFile; return uploadedFile;
} }
async function lockFile(nodeId) { async function lockFile(nodeId: string): Promise<NodeEntry> {
const data = { const data = {
type: 'ALLOW_OWNER_CHANGES' type: 'ALLOW_OWNER_CHANGES'
}; };
try { try {
await alfrescoJsApi.nodes.lockNode(nodeId, data); const result = new NodesApi(alfrescoJsApi).lockNode(nodeId, data);
logger.info('File was locked'); logger.info('File was locked');
return result;
} catch (error) { } catch (error) {
logger.error('Failed to lock file with error: ', error.stack); logger.error('Failed to lock file with error: ', error.stack);
} }
} }
async function shareFile(nodeId) { async function shareFile(nodeId: string) {
const data = { const data = {
nodeId nodeId
}; };
@ -147,7 +140,7 @@ async function shareFile(nodeId) {
} }
} }
async function favoriteFile(nodeId) { async function favoriteFile(nodeId: string) {
const data = { const data = {
target: { target: {
['file']: { ['file']: {
@ -165,8 +158,7 @@ async function favoriteFile(nodeId) {
async function checkEnv() { async function checkEnv() {
try { try {
alfrescoJsApi = new AlfrescoApi({
alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({
provider: 'ALL', provider: 'ALL',
hostBpm: program.host, hostBpm: program.host,
hostEcm: program.host, hostEcm: program.host,
@ -174,31 +166,33 @@ async function checkEnv() {
oauth2: { oauth2: {
host: `${program.host}/auth/realms/alfresco`, host: `${program.host}/auth/realms/alfresco`,
clientId: `${program.clientId}`, clientId: `${program.clientId}`,
scope: 'openid' scope: 'openid',
} redirectUri: '/'
},
contextRoot: 'alfresco'
}); });
await alfrescoJsApi.login(program.username, program.password); await alfrescoJsApi.login(program.username, program.password);
} catch (e) { } catch (e) {
if (e.error.code === 'ETIMEDOUT') { if (e.error.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating'); logger.error('The env is not reachable. Terminating');
process.exit(1); exit(1);
} }
logger.error('Login error environment down or inaccessible'); logger.error('Login error environment down or inaccessible');
counter++; counter++;
if (MAX_RETRY === counter) { if (MAX_RETRY === counter) {
logger.error('Give up'); logger.error('Give up');
process.exit(1); exit(1);
} else { } else {
logger.error(`Retry in 1 minute attempt N ${counter}`); logger.error(`Retry in 1 minute attempt N ${counter}`);
sleep(TIMEOUT); sleep(TIMEOUT);
checkEnv(); await checkEnv();
} }
} }
} }
/* eslint-enable */ /* eslint-enable */
function sleep(delay) { function sleep(delay: number) {
const start = new Date().getTime(); const start = new Date().getTime();
while (new Date().getTime() < start + delay) {} while (new Date().getTime() < start + delay) {}
} }

View File

@ -15,14 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
const alfrescoApi = require('@alfresco/js-api'); import { AdminTenantsApi, AdminUsersApi, AlfrescoApi, TenantRepresentation, AppDefinitionsApi, RuntimeAppDefinitionsApi, UserRepresentation } from '@alfresco/js-api';
import { argv, exit } from 'node:process';
import { spawnSync } from 'node:child_process';
import { createReadStream } from 'node:fs';
const program = require('commander'); const program = require('commander');
const fs = require ('fs');
const path = require('path'); const path = require('path');
import { logger } from './logger'; import { logger } from './logger';
const { throwError } = require('rxjs'); const { throwError } = require('rxjs');
// eslint-disable-next-line @typescript-eslint/naming-convention
const { AppDefinitionsApi, RuntimeAppDefinitionsApi } = require('@alfresco/js-api');
const MAX_RETRY = 10; const MAX_RETRY = 10;
let counter = 0; let counter = 0;
const TIMEOUT = 6000; const TIMEOUT = 6000;
@ -31,8 +31,7 @@ const TENANT_DEFAULT_NAME = 'default';
const CONTENT_DEFAULT_NAME = 'adw-content'; const CONTENT_DEFAULT_NAME = 'adw-content';
const ACTIVITI_APPS = require('./resources').ACTIVITI_APPS; const ACTIVITI_APPS = require('./resources').ACTIVITI_APPS;
let alfrescoJsApi; let alfrescoJsApi: AlfrescoApi;
let alfrescoJsApiRepo;
export default async function() { export default async function() {
await main(); await main();
@ -47,7 +46,7 @@ async function main() {
.option('-p, --password [type]', 'password ') .option('-p, --password [type]', 'password ')
.option('-u, --username [type]', 'username ') .option('-u, --username [type]', 'username ')
.option('--license [type]', 'APS license S3 path ') .option('--license [type]', 'APS license S3 path ')
.parse(process.argv); .parse(argv);
await checkEnv(); await checkEnv();
@ -68,16 +67,16 @@ async function main() {
let tenantId; let tenantId;
if (licenceUploaded) { if (licenceUploaded) {
logger.info(`***** Step 2 - Check Tenant *****`); logger.info(`***** Step 2 - Check Tenant *****`);
logger.info(`is tenandId:${TENANT_DEFAULT_ID} with name:${TENANT_DEFAULT_NAME} present?`); logger.info(`is tenantId:${TENANT_DEFAULT_ID} with name:${TENANT_DEFAULT_NAME} present?`);
try { try {
const hasDefault = await hasDefaultTenant(TENANT_DEFAULT_ID, TENANT_DEFAULT_NAME); const hasDefault = await hasDefaultTenant(TENANT_DEFAULT_ID, TENANT_DEFAULT_NAME);
tenantId = TENANT_DEFAULT_ID; tenantId = TENANT_DEFAULT_ID;
if (!hasDefault) { if (!hasDefault) {
// the tenandId should be equal to TENANT_DEFAULT_ID if we choose 1 as id. // the tenantId should be equal to TENANT_DEFAULT_ID if we choose 1 as id.
tenantId = await createDefaultTenant(TENANT_DEFAULT_NAME); tenantId = await createDefaultTenant(TENANT_DEFAULT_NAME);
} }
logger.info(`***** Step 3 - Add Content Repo *****`); logger.info(`***** Step 3 - Add Content Repo *****`);
const isContentPresent = await isContenRepoPresent(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME); const isContentPresent = await isContentRepoPresent(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME);
if (!isContentPresent) { if (!isContentPresent) {
logger.info(`No content repo with name ${CONTENT_DEFAULT_NAME} found`); logger.info(`No content repo with name ${CONTENT_DEFAULT_NAME} found`);
await addContentRepoWithBasic(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME); await addContentRepoWithBasic(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME);
@ -90,7 +89,7 @@ async function main() {
} }
for (let i = 0; i < users.length; i++) { for (let i = 0; i < users.length; i++) {
logger.info('Impersonate user: ' + users[i].username); logger.info('Impersonate user: ' + users[i].username);
await alfrescoJsApiRepo.login(users[i].username, 'password'); await alfrescoJsApi.login(users[i].username, 'password');
await authorizeUserToContentRepo(users[i]); await authorizeUserToContentRepo(users[i]);
const defaultUser = 'hruser'; const defaultUser = 'hruser';
@ -106,11 +105,11 @@ async function main() {
} catch (error) { } catch (error) {
logger.info(`Aps something went wrong. Tenant id ${tenantId}`); logger.info(`Aps something went wrong. Tenant id ${tenantId}`);
process.exit(1); exit(1);
} }
} else { } else {
logger.info('APS license error: check the configuration'); logger.info('APS license error: check the configuration');
process.exit(1); exit(1);
} }
} }
@ -129,47 +128,49 @@ async function initializeDefaultApps() {
} }
async function checkEnv() { async function checkEnv() {
try { try {
alfrescoJsApi = new AlfrescoApi({
alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({
provider: 'ALL', provider: 'ALL',
hostBpm: program.host, hostBpm: program.host,
hostEcm: program.host, hostEcm: program.host,
authType: 'OAUTH', authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: { oauth2: {
host: `${program.host}/auth/realms/alfresco`, host: `${program.host}/auth/realms/alfresco`,
clientId: `${program.clientId}`, clientId: `${program.clientId}`,
scope: 'openid' scope: 'openid',
redirectUri: '/'
} }
}); });
alfrescoJsApiRepo = alfrescoJsApi;
await alfrescoJsApi.login(program.username, program.password); await alfrescoJsApi.login(program.username, program.password);
} catch (e) { } catch (e) {
if (e.error.code === 'ETIMEDOUT') { if (e.error.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating'); logger.error('The env is not reachable. Terminating');
process.exit(1); exit(1);
} }
logger.info('Login error environment down or inaccessible'); logger.info('Login error environment down or inaccessible');
counter++; counter++;
if (MAX_RETRY === counter) { if (MAX_RETRY === counter) {
logger.error('Give up'); logger.error('Give up');
process.exit(1); exit(1);
} else { } else {
logger.error(`Retry in 1 minute attempt N ${counter}`); logger.error(`Retry in 1 minute attempt N ${counter}`);
sleep(TIMEOUT); sleep(TIMEOUT);
checkEnv(); await checkEnv();
} }
} }
} }
async function hasDefaultTenant(tenantId, tenantName) { async function hasDefaultTenant(tenantId: number, tenantName: string) {
let tenant; let tenant: TenantRepresentation;
try { try {
tenant = await alfrescoJsApi.activiti.adminTenantsApi.getTenant(tenantId); const adminTenantsApi = new AdminTenantsApi(alfrescoJsApi);
tenant = await adminTenantsApi.getTenant(tenantId);
} catch (error) { } catch (error) {
logger.info(`Aps: does not have tenant with id: ${tenantId}`); logger.info(`Aps: does not have tenant with id: ${tenantId}`);
return false; return false;
} }
if (tenant.name === tenantName) { if (tenant.name === tenantName) {
logger.info(`Aps: has default tenantId: ${tenantId} and name ${tenantName}`); logger.info(`Aps: has default tenantId: ${tenantId} and name ${tenantName}`);
return true; return true;
@ -179,7 +180,7 @@ async function hasDefaultTenant(tenantId, tenantName) {
} }
} }
async function createDefaultTenant(tenantName) { async function createDefaultTenant(tenantName: string) {
const tenantPost = { const tenantPost = {
active: true, active: true,
maxUsers: 10000, maxUsers: 10000,
@ -187,7 +188,8 @@ async function createDefaultTenant(tenantName) {
}; };
try { try {
const tenant = await alfrescoJsApi.activiti.adminTenantsApi.createTenant(tenantPost); const adminTenantsApi = new AdminTenantsApi(alfrescoJsApi);
const tenant = await adminTenantsApi.createTenant(tenantPost);
logger.info(`APS: Tenant ${tenantName} created with id: ${tenant.id}`); logger.info(`APS: Tenant ${tenantName} created with id: ${tenant.id}`);
return tenant.id; return tenant.id;
} catch (error) { } catch (error) {
@ -195,21 +197,22 @@ async function createDefaultTenant(tenantName) {
} }
} }
async function createUsers(tenandId, user) { async function createUsers(tenantId: number, user: any) {
logger.info(`Create user ${user.email} on tenant: ${tenandId}`); logger.info(`Create user ${user.email} on tenant: ${tenantId}`);
const passwordCamelCase = 'Password'; const passwordCamelCase = 'Password';
const userJson = { const userJson = new UserRepresentation({
email: user.email, email: user.email,
firstName: user.firstName, firstName: user.firstName,
lastName: user.lastName, lastName: user.lastName,
status: 'active', status: 'active',
type: 'enterprise', type: 'enterprise',
password: passwordCamelCase, password: passwordCamelCase,
tenantId: tenandId tenantId
}; });
try { try {
const userInfo = await alfrescoJsApi.activiti.adminUsersApi.createNewUser(userJson); const adminUsersApi = new AdminUsersApi(alfrescoJsApi);
const userInfo = await adminUsersApi.createNewUser(userJson);
logger.info(`APS: User ${userInfo.email} created with id: ${userInfo.id}`); logger.info(`APS: User ${userInfo.email} created with id: ${userInfo.id}`);
return user; return user;
} catch (error) { } catch (error) {
@ -218,7 +221,7 @@ async function createUsers(tenandId, user) {
} }
async function updateLicense() { async function updateLicense() {
const fileContent = fs.createReadStream(path.join(__dirname, '/activiti.lic')); const fileContent = createReadStream(path.join(__dirname, '/activiti.lic'));
try { try {
await alfrescoJsApi.oauth2Auth.callCustomApi( await alfrescoJsApi.oauth2Auth.callCustomApi(
@ -243,7 +246,7 @@ async function updateLicense() {
async function isDefaultAppDeployed(appName: string) { async function isDefaultAppDeployed(appName: string) {
logger.info(`Verify ${appName} already deployed`); logger.info(`Verify ${appName} already deployed`);
try { try {
const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApiRepo); const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi);
const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions(); const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions();
const defaultApp = availableApps.data && availableApps.data.filter(app => app.name && app.name.includes(appName)); const defaultApp = availableApps.data && availableApps.data.filter(app => app.name && app.name.includes(appName));
return defaultApp && defaultApp.length > 0; return defaultApp && defaultApp.length > 0;
@ -256,10 +259,10 @@ async function importPublishApp(appName: string) {
const appNameExtension = `../resources/${appName}.zip`; const appNameExtension = `../resources/${appName}.zip`;
logger.info(`Import app ${appNameExtension}`); logger.info(`Import app ${appNameExtension}`);
const pathFile = path.join(__dirname, appNameExtension); const pathFile = path.join(__dirname, appNameExtension);
const fileContent = fs.createReadStream(pathFile); const fileContent = createReadStream(pathFile);
try { try {
const appdefinitionsApi = new AppDefinitionsApi(alfrescoJsApiRepo); const appdefinitionsApi = new AppDefinitionsApi(alfrescoJsApi);
const result = await appdefinitionsApi.importAndPublishApp(fileContent, {renewIdmEntries: true}); const result = await appdefinitionsApi.importAndPublishApp(fileContent, {renewIdmEntries: true});
logger.info(`Aps app imported and published!`); logger.info(`Aps app imported and published!`);
return result; return result;
@ -268,14 +271,14 @@ async function importPublishApp(appName: string) {
} }
} }
async function deployApp(appDefinitioId) { async function deployApp(appDefinitionId: number) {
logger.info(`Deploy app with id ${appDefinitioId}`); logger.info(`Deploy app with id ${appDefinitionId}`);
const body = { const body = {
appDefinitions: [{id: appDefinitioId}] appDefinitions: [{id: appDefinitionId}]
}; };
try { try {
const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApiRepo); const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi);
await runtimeAppDefinitionsApi.deployAppDefinitions(body); await runtimeAppDefinitionsApi.deployAppDefinitions(body);
logger.info(`Aps app deployed`); logger.info(`Aps app deployed`);
} catch (error) { } catch (error) {
@ -283,7 +286,7 @@ async function deployApp(appDefinitioId) {
} }
} }
async function hasLicense() { async function hasLicense(): Promise<boolean> {
try { try {
const license = await alfrescoJsApi.oauth2Auth.callCustomApi( const license = await alfrescoJsApi.oauth2Auth.callCustomApi(
`${program.host}/activiti-app/app/rest/license`, `${program.host}/activiti-app/app/rest/license`,
@ -308,9 +311,8 @@ async function hasLicense() {
} }
async function getDefaultApsUsersFromRealm() { async function getDefaultApsUsersFromRealm() {
try { try {
const users = await alfrescoJsApi.oauth2Auth.callCustomApi( const users: any[] = await alfrescoJsApi.oauth2Auth.callCustomApi(
`${program.host}/auth/admin/realms/alfresco/users`, `${program.host}/auth/admin/realms/alfresco/users`,
'GET', 'GET',
{}, {},
@ -330,8 +332,7 @@ async function getDefaultApsUsersFromRealm() {
} }
} }
async function isContenRepoPresent(tenantId, contentName) { async function isContentRepoPresent(tenantId: number, contentName: string): Promise<boolean> {
try { try {
const contentRepos = await alfrescoJsApi.oauth2Auth.callCustomApi( const contentRepos = await alfrescoJsApi.oauth2Auth.callCustomApi(
`${program.host}/activiti-app/app/rest/integration/alfresco?tenantId=${tenantId}`, `${program.host}/activiti-app/app/rest/integration/alfresco?tenantId=${tenantId}`,
@ -350,8 +351,9 @@ async function isContenRepoPresent(tenantId, contentName) {
} }
} }
async function addContentRepoWithBasic(tenantId, name) { async function addContentRepoWithBasic(tenantId: number, name: string) {
logger.info(`Create Content with name ${name} and basic auth`); logger.info(`Create Content with name ${name} and basic auth`);
const body = { const body = {
alfrescoTenantId: '', alfrescoTenantId: '',
authenticationType: 'basic', authenticationType: 'basic',
@ -382,10 +384,10 @@ async function addContentRepoWithBasic(tenantId, name) {
} }
} }
async function authorizeUserToContentRepo(user) { async function authorizeUserToContentRepo(user: any) {
logger.info(`Authorize user ${user.email}`); logger.info(`Authorize user ${user.email}`);
try { try {
const content = await alfrescoJsApiRepo.oauth2Auth.callCustomApi( const content = await alfrescoJsApi.oauth2Auth.callCustomApi(
`${program.host}/activiti-app/app/rest/integration/alfresco`, `${program.host}/activiti-app/app/rest/integration/alfresco`,
'GET', 'GET',
{}, {},
@ -410,11 +412,11 @@ async function authorizeUserToContentRepo(user) {
} }
} }
async function authorizeUserToContentWithBasic(username, contentId) { async function authorizeUserToContentWithBasic(username: string, contentId: string) {
logger.info(`Authorize ${username} on contentId: ${contentId} in basic auth`); logger.info(`Authorize ${username} on contentId: ${contentId} in basic auth`);
try { try {
const body = {username, password: 'password'}; const body = {username, password: 'password'};
const content = await alfrescoJsApiRepo.oauth2Auth.callCustomApi( const content = await alfrescoJsApi.oauth2Auth.callCustomApi(
`${program.host}/activiti-app/app/rest/integration/alfresco/${contentId}/account`, `${program.host}/activiti-app/app/rest/integration/alfresco/${contentId}/account`,
'POST', 'POST',
{}, {},
@ -432,13 +434,11 @@ async function authorizeUserToContentWithBasic(username, contentId) {
} }
} }
/* eslint-disable */ async function downloadLicenseFile(apsLicensePath: string) {
async function downloadLicenseFile(apsLicensePath) {
try { try {
const child_process = require("child_process"); spawnSync(` aws s3 cp ${apsLicensePath} ./ `, {
child_process.execSync(` aws s3 cp ${apsLicensePath} ./ `, { cwd: path.resolve(__dirname, `./`),
cwd: path.resolve(__dirname, `./`) shell: false
}); });
logger.info(`Aps license file download from S3 bucket`); logger.info(`Aps license file download from S3 bucket`);
return true; return true;
@ -447,9 +447,8 @@ async function downloadLicenseFile(apsLicensePath) {
return false; return false;
} }
} }
/* eslint-enable */
function sleep(delay) { function sleep(delay: number) {
const start = new Date().getTime(); const start = new Date().getTime();
while (new Date().getTime() < start + delay) { } while (new Date().getTime() < start + delay) { }
} }

View File

@ -17,6 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { argv, exit } from 'node:process';
import program from 'commander'; import program from 'commander';
import moment from 'moment'; import moment from 'moment';
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
@ -40,11 +41,12 @@ export interface ConfigArgs {
intervalTime: string; intervalTime: string;
} }
function getAlfrescoJsApiInstance(args: ConfigArgs) { function getAlfrescoJsApiInstance(args: ConfigArgs): AlfrescoApi {
const config = { const config: AlfrescoApiConfig = {
provider: 'BPM', provider: 'BPM',
hostBpm: `${args.host}`, hostBpm: `${args.host}`,
authType: 'OAUTH', authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: { oauth2: {
host: `${args.oauth}/auth/realms/alfresco`, host: `${args.oauth}/auth/realms/alfresco`,
clientId: `${args.clientId}`, clientId: `${args.clientId}`,
@ -55,21 +57,21 @@ function getAlfrescoJsApiInstance(args: ConfigArgs) {
redirectUri: '/' redirectUri: '/'
} }
}; };
return new AlfrescoApi(config as unknown as AlfrescoApiConfig); return new AlfrescoApi(config);
} }
async function login(username: string, password: string, alfrescoJsApi: any) { async function login(username: string, password: string, alfrescoJsApi: AlfrescoApi) {
logger.info(`Perform login...`); logger.info(`Perform login...`);
try { try {
await alfrescoJsApi.login(username, password); await alfrescoJsApi.login(username, password);
} catch (error) { } catch (error) {
logger.error(`Not able to login. Credentials ${username}:${password} are not valid`); logger.error(`Not able to login. Credentials ${username}:${password} are not valid`);
process.exit(1); exit(1);
} }
logger.info(`Perform done...`); logger.info(`Perform done...`);
} }
async function deleteDescriptor(args: ConfigArgs, apiService: any, name: string) { async function deleteDescriptor(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
logger.warn(`Delete the descriptor ${name}`); logger.warn(`Delete the descriptor ${name}`);
const url = `${args.host}/deployment-service/v1/descriptors/${name}`; const url = `${args.host}/deployment-service/v1/descriptors/${name}`;
@ -84,13 +86,25 @@ async function deleteDescriptor(args: ConfigArgs, apiService: any, name: string)
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return await apiService.oauth2Auth.callCustomApi(url, 'DELETE', pathParams, queryParams, headerParams, formParams, bodyParam, contentTypes, accepts); return await apiService.oauth2Auth.callCustomApi(
url,
'DELETE',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error(`Not possible to delete the descriptor ${name} status : ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`); logger.error(
`Not possible to delete the descriptor ${name} status: ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`
);
} }
} }
async function deleteProject(args: ConfigArgs, apiService: any, projectId: string) { async function deleteProject(args: ConfigArgs, apiService: AlfrescoApi, projectId: string) {
logger.warn(`Delete the project ${projectId}`); logger.warn(`Delete the project ${projectId}`);
const url = `${args.host}/modeling-service/v1/projects/${projectId}`; const url = `${args.host}/modeling-service/v1/projects/${projectId}`;
@ -105,13 +119,25 @@ async function deleteProject(args: ConfigArgs, apiService: any, projectId: strin
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return await apiService.oauth2Auth.callCustomApi(url, 'DELETE', pathParams, queryParams, headerParams, formParams, bodyParam, contentTypes, accepts); return await apiService.oauth2Auth.callCustomApi(
url,
'DELETE',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error(`Not possible to delete the project ${projectId} status : ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`); logger.error(
`Not possible to delete the project ${projectId} status : ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`
);
} }
} }
async function deleteProjectByName(args: ConfigArgs, apiService: any, name: string) { async function deleteProjectByName(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
logger.warn(`Get the project by name ${name}`); logger.warn(`Get the project by name ${name}`);
const url = `${args.host}/modeling-service/v1/projects?name=${name}`; const url = `${args.host}/modeling-service/v1/projects?name=${name}`;
@ -124,8 +150,17 @@ async function deleteProjectByName(args: ConfigArgs, apiService: any, name: stri
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
const data = await apiService.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, const data = await apiService.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
for (let i = 0; i < data.list.entries.length; i++) { for (let i = 0; i < data.list.entries.length; i++) {
if (data.list.entries[i].entry.name === name) { if (data.list.entries[i].entry.name === name) {
await deleteProject(args, apiService, data.list.entries[i].entry.id); await deleteProject(args, apiService, data.list.entries[i].entry.id);
@ -133,11 +168,11 @@ async function deleteProjectByName(args: ConfigArgs, apiService: any, name: stri
} }
} catch (error) { } catch (error) {
logger.error(`Not possible to get the project with name ${name} ` + JSON.stringify(error)); logger.error(`Not possible to get the project with name ${name} ` + JSON.stringify(error));
process.exit(1); exit(1);
} }
} }
async function getApplicationsByName(args: ConfigArgs, apiService: any, name: string) { async function getApplicationsByName(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
logger.warn(`Get the applications by name ${name}`); logger.warn(`Get the applications by name ${name}`);
const url = `${args.host}/deployment-service/v1/applications?name=${name}`; const url = `${args.host}/deployment-service/v1/applications?name=${name}`;
@ -150,8 +185,17 @@ async function getApplicationsByName(args: ConfigArgs, apiService: any, name: st
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
const apps = await apiService.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam, const apps = await apiService.oauth2Auth.callCustomApi(
contentTypes, accepts); url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
return apps ? apps.list.entries : []; return apps ? apps.list.entries : [];
} catch (error) { } catch (error) {
logger.error(`Not possible to get the applications with name ${name} ` + JSON.stringify(error)); logger.error(`Not possible to get the applications with name ${name} ` + JSON.stringify(error));
@ -159,7 +203,7 @@ async function getApplicationsByName(args: ConfigArgs, apiService: any, name: st
} }
} }
async function undeployApplication(args: ConfigArgs, apiService: any, name: string) { async function undeployApplication(args: ConfigArgs, apiService: AlfrescoApi, name: string) {
logger.warn(`Undeploy the application ${name}`); logger.warn(`Undeploy the application ${name}`);
const url = `${args.host}/deployment-service/v1/applications/${name}`; const url = `${args.host}/deployment-service/v1/applications/${name}`;
@ -174,13 +218,25 @@ async function undeployApplication(args: ConfigArgs, apiService: any, name: stri
const accepts = ['application/json']; const accepts = ['application/json'];
try { try {
return await apiService.oauth2Auth.callCustomApi(url, 'DELETE', pathParams, queryParams, headerParams, formParams, bodyParam, contentTypes, accepts); return await apiService.oauth2Auth.callCustomApi(
url,
'DELETE',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
} catch (error) { } catch (error) {
logger.error(`Not possible to undeploy the applications ${name} status : ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`); logger.error(
`Not possible to undeploy the applications ${name} status: ${JSON.stringify(error.status)} ${JSON.stringify(error?.response?.text)}`
);
} }
} }
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions // eslint-disable-next-line prefer-arrow/prefer-arrow-functions,space-before-function-paren
export default async function (args: ConfigArgs) { export default async function (args: ConfigArgs) {
await main(args); await main(args);
} }
@ -188,8 +244,10 @@ export default async function(args: ConfigArgs) {
const main = async (args: ConfigArgs) => { const main = async (args: ConfigArgs) => {
program program
.version('0.1.0') .version('0.1.0')
.description('The following command is in charge of cleaning the releases/application/descriptor related to an app passed as input' + .description(
'adf-cli kubectl-clean-app --host "gateway_env" --modelerUsername "modelerusername" --modelerPassword "modelerpassword" --oauth "identity_env" --username "username" --password "password"') 'The following command is in charge of cleaning the releases/application/descriptor related to an app passed as input' +
'adf-cli kubectl-clean-app --host "gateway_env" --modelerUsername "modelerusername" --modelerPassword "modelerpassword" --oauth "identity_env" --username "username" --password "password"'
)
.option('-h, --host [type]', 'Host gateway') .option('-h, --host [type]', 'Host gateway')
.option('-o, --oauth [type]', 'Host sso server') .option('-o, --oauth [type]', 'Host sso server')
.option('--clusterEnv [type]', 'cluster Envirorment') .option('--clusterEnv [type]', 'cluster Envirorment')
@ -204,28 +262,34 @@ const main = async (args: ConfigArgs) => {
.option('--apps [type]', 'Application prefix') .option('--apps [type]', 'Application prefix')
.option('--enableLike [boolean]', 'Enable the like for app name') .option('--enableLike [boolean]', 'Enable the like for app name')
.option('--intervalTime [string]', 'In case of enableLike it specify the time related to the createDate') .option('--intervalTime [string]', 'In case of enableLike it specify the time related to the createDate')
.parse(process.argv); .parse(argv);
if (process.argv.includes('-h') || process.argv.includes('--help')) { if (argv.includes('-h') || argv.includes('--help')) {
program.outputHelp(); program.outputHelp();
return; return;
} }
const alfrescoJsApiModeler = getAlfrescoJsApiInstance(args); const alfrescoJsApiModeler = getAlfrescoJsApiInstance(args);
await login(args.modelerUsername, args.modelerPassword, alfrescoJsApiModeler).then(() => { await login(args.modelerUsername, args.modelerPassword, alfrescoJsApiModeler).then(
() => {
logger.info('login SSO ok'); logger.info('login SSO ok');
}, (error) => { },
(error) => {
logger.info(`login SSO error ${JSON.stringify(error)}`); logger.info(`login SSO error ${JSON.stringify(error)}`);
process.exit(1); exit(1);
}); }
);
const alfrescoJsApiDevops = getAlfrescoJsApiInstance(args); const alfrescoJsApiDevops = getAlfrescoJsApiInstance(args);
await login(args.devopsUsername, args.devopsPassword, alfrescoJsApiDevops).then(() => { await login(args.devopsUsername, args.devopsPassword, alfrescoJsApiDevops).then(
() => {
logger.info('login SSO ok'); logger.info('login SSO ok');
}, (error) => { },
(error) => {
logger.info(`login SSO error ${JSON.stringify(error)}`); logger.info(`login SSO error ${JSON.stringify(error)}`);
process.exit(1); exit(1);
}); }
);
if (args.apps !== undefined) { if (args.apps !== undefined) {
kube.setCluster(args.clusterEnv, args.clusterUrl); kube.setCluster(args.clusterEnv, args.clusterUrl);

View File

@ -15,65 +15,61 @@
* limitations under the License. * limitations under the License.
*/ */
import { AlfrescoApi } from '@alfresco/js-api';
import { exit } from 'node:process';
import { logger } from './../logger'; import { logger } from './../logger';
import alfrescoApi = require('@alfresco/js-api');
const TIMEOUT = 6000; const TIMEOUT = 6000;
const MAX_RETRY = 10; const MAX_RETRY = 10;
export class CheckEnv { export class CheckEnv {
_alfrescoJsApi: any; _alfrescoJsApi: AlfrescoApi;
counter = 0; counter = 0;
constructor( constructor(private host: string, private username: string, private password: string, private clientId: string = 'alfresco') {}
private host: string,
private username: string,
private password: string,
private clientId: string = 'alfresco'
) {}
async checkEnv() { async checkEnv() {
try { try {
this.alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({ this.alfrescoJsApi = new AlfrescoApi({
provider: 'ALL', provider: 'ALL',
hostBpm: this.host, hostBpm: this.host,
hostEcm: this.host, hostEcm: this.host,
authType: 'OAUTH', authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: { oauth2: {
host: `${this.host}/auth/realms/alfresco`, host: `${this.host}/auth/realms/alfresco`,
clientId: `${this.clientId}`, clientId: `${this.clientId}`,
scope: 'openid' scope: 'openid',
redirectUri: '/'
} }
} as any); });
await this.alfrescoJsApi.login(this.username, this.password); await this.alfrescoJsApi.login(this.username, this.password);
} catch (e) { } catch (e) {
if (e.error.code === 'ETIMEDOUT') { if (e.error.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating'); logger.error('The env is not reachable. Terminating');
process.exit(1); exit(1);
} }
logger.error('Login error environment down or inaccessible'); logger.error('Login error environment down or inaccessible');
this.counter++; this.counter++;
if (MAX_RETRY === this.counter) { if (MAX_RETRY === this.counter) {
logger.error('Give up'); logger.error('Give up');
process.exit(1); exit(1);
} else { } else {
logger.error( logger.error(`Retry in 1 minute at main();tempt N ${this.counter}`);
`Retry in 1 minute at main();tempt N ${this.counter}`
);
this.sleep(TIMEOUT); this.sleep(TIMEOUT);
this.checkEnv(); await this.checkEnv();
} }
} }
} }
public get alfrescoJsApi() { public get alfrescoJsApi(): AlfrescoApi {
return this._alfrescoJsApi; return this._alfrescoJsApi;
} }
public set alfrescoJsApi(alfrescoJsApi: any) { public set alfrescoJsApi(alfrescoJsApi: AlfrescoApi) {
this._alfrescoJsApi = alfrescoJsApi; this._alfrescoJsApi = alfrescoJsApi;
} }
sleep(delay) { sleep(delay: number) {
const start = new Date().getTime(); const start = new Date().getTime();
while (new Date().getTime() < start + delay) {} while (new Date().getTime() < start + delay) {}
} }

View File

@ -17,13 +17,11 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { GovernanceHealth } from './governance-health'; import { GovernanceHealth } from './governance-health';
import { AlfrescoApi } from '@alfresco/js-api';
export class GovernanceCheckPlugin { export class GovernanceCheckPlugin {
governanceHealth: GovernanceHealth; governanceHealth: GovernanceHealth;
constructor( constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
private pluginInfo: PluginInterface,
private alfrescoJsApi: any
) {
this.governanceHealth = new GovernanceHealth(this.pluginInfo, this.alfrescoJsApi); this.governanceHealth = new GovernanceHealth(this.pluginInfo, this.alfrescoJsApi);
} }

View File

@ -19,47 +19,37 @@
import { logger } from '../logger'; import { logger } from '../logger';
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { AlfrescoApi, GsSitesApi } from '@alfresco/js-api';
export class GovernanceHealth { export class GovernanceHealth {
constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: any) {} constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {}
async isRecordManagementAvailable() { async isRecordManagementAvailable(): Promise<boolean> {
try { try {
const site = await this.alfrescoJsApi.gsCore.gsSitesApi.getRMSite(); const gsSitesApi = new GsSitesApi(this.alfrescoJsApi);
logger.info( const site = await gsSitesApi.getRMSite();
`Record Management site is present: ${site.entry.title}` logger.info(`Record Management site is present: ${site.entry.title}`);
);
console.table([{ PluginName: this.pluginInfo.name, Status: 'Active', RecordManagement: 'Available' }]); console.table([{ PluginName: this.pluginInfo.name, Status: 'Active', RecordManagement: 'Available' }]);
return true; return true;
} catch (error) { } catch (error) {
logger.error( logger.error(`Record Management site get failed: ${JSON.parse(error.message).error.errorKey}`);
`Record Management site get failed: ${
JSON.parse(error.message).error.errorKey
}`
);
console.table([{ PluginName: this.pluginInfo.name, Status: 'Inactive', RecordManagement: 'Not available' }]); console.table([{ PluginName: this.pluginInfo.name, Status: 'Inactive', RecordManagement: 'Not available' }]);
return false; return false;
} }
} }
async createRecordManagementSite() { async createRecordManagementSite(): Promise<void> {
const body = { title: 'Records Management' }; const body = { title: 'Records Management' };
const opts = { skipAddToFavorites: false }; // | Flag to indicate whether the RM site should not be added to the user's site favorites. const opts = { skipAddToFavorites: false }; // | Flag to indicate whether the RM site should not be added to the user's site favorites.
try { try {
logger.info('Trying to create Record Management site...'); logger.info('Trying to create Record Management site...');
const site = await this.alfrescoJsApi.gsCore.gsSitesApi.createRMSite( const gsSitesApi = new GsSitesApi(this.alfrescoJsApi);
body, const site = await gsSitesApi.createRMSite(body, opts);
opts
);
logger.info('Record Management site: created' + site); logger.info('Record Management site: created' + site);
console.table([{ PluginName: this.pluginInfo.name, Status: 'Active', RecordManagement: 'Created' }]); console.table([{ PluginName: this.pluginInfo.name, Status: 'Active', RecordManagement: 'Created' }]);
} catch (error) { } catch (error) {
logger.error( logger.error(`Record Management site creation failed: ${JSON.parse(error.message).error.errorKey}`);
`Record Management site creation failed: ${
JSON.parse(error.message).error.errorKey
}`
);
console.table([{ PluginName: this.pluginInfo.name, Status: 'Inactive', RecordManagement: 'Not created' }]); console.table([{ PluginName: this.pluginInfo.name, Status: 'Inactive', RecordManagement: 'Not created' }]);
} }
} }

View File

@ -17,12 +17,10 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { logger } from '../logger'; import { logger } from '../logger';
import { AlfrescoApi } from '@alfresco/js-api';
export class PluginConfiguration { export class PluginConfiguration {
constructor( constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {}
private plugInInfo: PluginInterface,
private alfrescoJsApi: any
) {}
async getAppConfig(url: string) { async getAppConfig(url: string) {
return this.callCustomApi(url); return this.callCustomApi(url);
@ -52,10 +50,7 @@ export class PluginConfiguration {
return response; return response;
} catch (error) { } catch (error) {
logger.error( logger.error(`${this.plugInInfo.host} is not reachable error: `, error);
`${this.plugInInfo.host} is not reachable error: `,
error
);
return {}; return {};
} }
} }

View File

@ -20,55 +20,49 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { logger } from '../logger'; import { logger } from '../logger';
import { ProcessAutomationHealth } from './process-automation-health'; import { ProcessAutomationHealth } from './process-automation-health';
import { AlfrescoApi } from '@alfresco/js-api';
import { exit } from 'node:process';
export class ProcessAutomationCheckPlugin { export class ProcessAutomationCheckPlugin {
processAutomationHealth: ProcessAutomationHealth; processAutomationHealth: ProcessAutomationHealth;
constructor( constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
private plugInInfo: PluginInterface, this.processAutomationHealth = new ProcessAutomationHealth(this.plugInInfo, this.alfrescoJsApi);
private alfrescoJsApi: any
) {
this.processAutomationHealth = new ProcessAutomationHealth(
this.plugInInfo,
this.alfrescoJsApi
);
} }
async checkProcessAutomationPlugin() { async checkProcessAutomationPlugin(): Promise<void> {
let pluginStatus; let pluginStatus;
try { try {
const isPluginEnabled = await this.processAutomationHealth.isPluginEnabledFromAppConfiguration(); const isPluginEnabled = await this.processAutomationHealth.isPluginEnabledFromAppConfiguration();
const isBackendActive = await this.processAutomationHealth.checkBackendHealth(); const isBackendActive = await this.processAutomationHealth.checkBackendHealth();
if (isPluginEnabled && isBackendActive) { if (isPluginEnabled && isBackendActive) {
logger.info( logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured`);
`The plugin ${
this.plugInInfo.name
} has been correctly configured`
);
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Active', BE: 'UP', FE: 'Enabled' }]; pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Active', BE: 'UP', FE: 'Enabled' }];
console.table(pluginStatus); console.table(pluginStatus);
} else { } else {
this.logConfigurationError(); this.logConfigurationError();
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Inactive', BE: isBackendActive ? 'UP' : 'DOWN', FE: isPluginEnabled ? 'Enabled' : 'Disabled' }]; pluginStatus = [
{
PluginName: this.plugInInfo.name,
Status: 'Inactive',
BE: isBackendActive ? 'UP' : 'DOWN',
FE: isPluginEnabled ? 'Enabled' : 'Disabled'
}
];
console.table(pluginStatus); console.table(pluginStatus);
process.exit(1); exit(1);
} }
} catch (e) { } catch (e) {
this.logConfigurationError(e); this.logConfigurationError(e);
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Inactive', BE: 'DOWN', FE: 'Disabled' }]; pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Inactive', BE: 'DOWN', FE: 'Disabled' }];
console.table(pluginStatus); console.table(pluginStatus);
process.exit(1); exit(1);
} }
} }
private logConfigurationError(error?: any) { private logConfigurationError(error?: any): void {
logger.error( logger.error(`The plugin ${this.plugInInfo.name} has not been correctly configured`, error);
`The plugin ${
this.plugInInfo.name
} has not been correctly configured`,
error
);
} }
} }

View File

@ -18,31 +18,22 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { logger } from '../logger'; import { logger } from '../logger';
import { PluginConfiguration } from './plugin-config'; import { PluginConfiguration } from './plugin-config';
import { AlfrescoApi } from '@alfresco/js-api';
export class ProcessAutomationHealth { export class ProcessAutomationHealth {
config: PluginConfiguration; config: PluginConfiguration;
constructor( constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
private plugInInfo: PluginInterface, this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi);
private alfrescoJsApi: any
) {
this.config = new PluginConfiguration(
this.plugInInfo,
this.alfrescoJsApi
);
} }
async isPluginEnabledFromAppConfiguration() { async isPluginEnabledFromAppConfiguration(): Promise<boolean> {
try { try {
const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/ui/${this.plugInInfo.uiName}/app.config.json`; const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/ui/${this.plugInInfo.uiName}/app.config.json`;
const appConfig = await this.config.getAppConfig(url); const appConfig = await this.config.getAppConfig(url);
let isEnabled = true; let isEnabled = true;
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) { if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
logger.info( logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
`The plugin ${
this.plugInInfo.name
} has been correctly configured in app.config.json`
);
} else { } else {
this.logConfigurationError(); this.logConfigurationError();
isEnabled = false; isEnabled = false;
@ -55,7 +46,7 @@ export class ProcessAutomationHealth {
} }
} }
async checkBackendHealth() { async checkBackendHealth(): Promise<boolean> {
const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/rb/actuator/health`; const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/rb/actuator/health`;
let isBackendActive = true; let isBackendActive = true;
try { try {
@ -68,20 +59,12 @@ export class ProcessAutomationHealth {
} }
return isBackendActive; return isBackendActive;
} catch (error) { } catch (error) {
logger.error( logger.error(`${this.plugInInfo.host} is not reachable error: `, error);
`${this.plugInInfo.host} is not reachable error: `,
error
);
return false; return false;
} }
} }
private logConfigurationError(error?: any) { private logConfigurationError(error?: any): void {
logger.error( logger.error(`The plugin ${this.plugInInfo.name} has not been correctly configured in app.config.json`, error);
`The plugin ${
this.plugInInfo.name
} has not been correctly configured in app.config.json`,
error
);
} }
} }

View File

@ -20,37 +20,35 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { logger } from '../logger'; import { logger } from '../logger';
import { ProcessServiceHealth } from './process-services-health'; import { ProcessServiceHealth } from './process-services-health';
import { AlfrescoApi } from '@alfresco/js-api';
export class ProcessServiceCheckPlugin { export class ProcessServiceCheckPlugin {
processServiceHealth: ProcessServiceHealth; processServiceHealth: ProcessServiceHealth;
constructor( constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
private plugInInfo: PluginInterface, this.processServiceHealth = new ProcessServiceHealth(this.plugInInfo, this.alfrescoJsApi);
private alfrescoJsApi: any
) {
this.processServiceHealth = new ProcessServiceHealth(
this.plugInInfo,
this.alfrescoJsApi
);
} }
async checkProcessServicesPlugin() { async checkProcessServicesPlugin(): Promise<void> {
let pluginStatus; let pluginStatus;
try { try {
const isPluginEnabled = await this.processServiceHealth.isPluginEnabledFromAppConfiguration(); const isPluginEnabled = await this.processServiceHealth.isPluginEnabledFromAppConfiguration();
const isBackendActive = await this.processServiceHealth.checkBackendHealth(); const isBackendActive = await this.processServiceHealth.checkBackendHealth();
if (isPluginEnabled && isBackendActive) { if (isPluginEnabled && isBackendActive) {
logger.info( logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured`);
`The plugin ${
this.plugInInfo.name
} has been correctly configured`
);
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: `${'Active'}`, BE: 'UP', FE: 'Enabled' }]; pluginStatus = [{ PluginName: this.plugInInfo.name, Status: `${'Active'}`, BE: 'UP', FE: 'Enabled' }];
console.table(pluginStatus); console.table(pluginStatus);
} else { } else {
this.logConfigurationError(); this.logConfigurationError();
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: 'Inactive', BE: isBackendActive ? 'UP' : 'DOWN', FE: isPluginEnabled ? 'Enabled' : 'Disabled' }]; pluginStatus = [
{
PluginName: this.plugInInfo.name,
Status: 'Inactive',
BE: isBackendActive ? 'UP' : 'DOWN',
FE: isPluginEnabled ? 'Enabled' : 'Disabled'
}
];
console.table(pluginStatus); console.table(pluginStatus);
process.exit(1); process.exit(1);
} }
@ -62,12 +60,7 @@ export class ProcessServiceCheckPlugin {
} }
} }
private logConfigurationError(error?: any) { private logConfigurationError(error?: any): void {
logger.error( logger.error(`The plugin ${this.plugInInfo.name} has not been correctly configured`, error);
`The plugin ${
this.plugInInfo.name
} has not been correctly configured`,
error
);
} }
} }

View File

@ -18,26 +18,22 @@
import { PluginInterface } from './plugin-model'; import { PluginInterface } from './plugin-model';
import { logger } from '../logger'; import { logger } from '../logger';
import { PluginConfiguration } from './plugin-config'; import { PluginConfiguration } from './plugin-config';
import { AlfrescoApi, SystemPropertiesApi } from '@alfresco/js-api';
export class ProcessServiceHealth { export class ProcessServiceHealth {
config: PluginConfiguration; config: PluginConfiguration;
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: any) { constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi); this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi);
} }
async isPluginEnabledFromAppConfiguration() { async isPluginEnabledFromAppConfiguration(): Promise<boolean> {
try { try {
const url = `${this.plugInInfo.host}/app.config.json`; const url = `${this.plugInInfo.host}/app.config.json`;
const appConfig = await this.config.getAppConfig(url); const appConfig = await this.config.getAppConfig(url);
let isEnabled = true; let isEnabled = true;
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) { if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
logger.info( logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
`The plugin ${
this.plugInInfo.name
} has been correctly configured in app.config.json`
);
} else { } else {
this.logConfigurationError(); this.logConfigurationError();
return (isEnabled = false); return (isEnabled = false);
@ -50,9 +46,10 @@ export class ProcessServiceHealth {
} }
} }
async checkBackendHealth() { async checkBackendHealth(): Promise<boolean> {
try { try {
const systemProperties = await this.alfrescoJsApi.activiti.systemPropertiesApi.getProperties(); const systemPropertiesApi = new SystemPropertiesApi(this.alfrescoJsApi);
const systemProperties = await systemPropertiesApi.getProperties();
let isBackendActive = true; let isBackendActive = true;
if (systemProperties) { if (systemProperties) {
logger.info(`${this.plugInInfo.host} is UP!`); logger.info(`${this.plugInInfo.host} is UP!`);
@ -62,20 +59,12 @@ export class ProcessServiceHealth {
} }
return isBackendActive; return isBackendActive;
} catch (error) { } catch (error) {
logger.error( logger.error(`${this.plugInInfo.host} is not reachable error: `, error);
`${this.plugInInfo.host} is not reachable error: `,
error
);
return false; return false;
} }
} }
private logConfigurationError(error?: any) { private logConfigurationError(error?: any): void {
logger.error( logger.error(`The plugin ${this.plugInInfo.name} has not been correctly configured in app.config.json`, error);
`The plugin ${
this.plugInInfo.name
} has not been correctly configured in app.config.json`,
error
);
} }
} }

View File

@ -15,12 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { AlfrescoApi, PeopleApi, NodesApi, GroupsApi, SitesApi, SearchApi, AlfrescoApiConfig } from '@alfresco/js-api'; import { AlfrescoApi, PeopleApi, NodesApi, GroupsApi, SitesApi, SearchApi } from '@alfresco/js-api';
import { argv, exit } from 'node:process';
import program from 'commander'; import program from 'commander';
import { logger } from './logger'; import { logger } from './logger';
interface PeopleTally { enabled: number; disabled: number } interface PeopleTally {
interface RowToPrint { label: string; value: number } enabled: number;
disabled: number;
}
interface RowToPrint {
label: string;
value: number;
}
const MAX_ATTEMPTS = 1; const MAX_ATTEMPTS = 1;
const TIMEOUT = 180000; const TIMEOUT = 180000;
@ -35,11 +42,10 @@ const bright = '\x1b[1m';
const red = '\x1b[31m'; const red = '\x1b[31m';
const green = '\x1b[32m'; const green = '\x1b[32m';
let jsApiConnection: any; let alfrescoApi: AlfrescoApi;
let loginAttempts: number = 0; let loginAttempts: number = 0;
export default async function main(_args: string[]) { export default async function main(_args: string[]) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log = () => {}; console.log = () => {};
@ -49,7 +55,7 @@ export default async function main(_args: string[]) {
.option('--clientId [type]', 'sso client', 'alfresco') .option('--clientId [type]', 'sso client', 'alfresco')
.option('-p, --password <type>', 'password ') .option('-p, --password <type>', 'password ')
.option('-u, --username <type>', 'username ') .option('-u, --username <type>', 'username ')
.parse(process.argv); .parse(argv);
logger.info(`${cyan}${bright}Initiating environment scan...${reset}`); logger.info(`${cyan}${bright}Initiating environment scan...${reset}`);
await attemptLogin(); await attemptLogin();
@ -67,20 +73,26 @@ export default async function main(_args: string[]) {
} }
function generateTable(rowsToPrint: Array<RowToPrint>) { function generateTable(rowsToPrint: Array<RowToPrint>) {
const columnWidths = rowsToPrint.reduce((maxWidths, row: RowToPrint) => ({ const columnWidths = rowsToPrint.reduce(
(maxWidths, row: RowToPrint) => ({
labelColumn: Math.max(maxWidths.labelColumn, row.label.length), labelColumn: Math.max(maxWidths.labelColumn, row.label.length),
valueColumn: Math.max(maxWidths.valueColumn, row.value.toString().length) valueColumn: Math.max(maxWidths.valueColumn, row.value.toString().length)
}), { labelColumn: 12, valueColumn: 1 }); }),
{ labelColumn: 12, valueColumn: 1 }
);
const horizontalLine = ''.padEnd(columnWidths.labelColumn + columnWidths.valueColumn + 5, '═'); const horizontalLine = ''.padEnd(columnWidths.labelColumn + columnWidths.valueColumn + 5, '═');
const headerText = 'ENVIRONM'.padStart(Math.floor((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' ') const headerText =
+ 'ENT SCAN'.padEnd(Math.ceil((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' '); 'ENVIRONM'.padStart(Math.floor((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' ') +
'ENT SCAN'.padEnd(Math.ceil((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' ');
let tableString = `${grey}${horizontalLine}${reset} let tableString = `${grey}${horizontalLine}${reset}
${grey} ${bright}${cyan}${headerText} ${grey}${reset} ${grey} ${bright}${cyan}${headerText} ${grey}${reset}
${grey}${horizontalLine}${reset}`; ${grey}${horizontalLine}${reset}`;
rowsToPrint.forEach(row => { rowsToPrint.forEach((row) => {
tableString += `\n${grey}${reset} ${row.label.padEnd(columnWidths.labelColumn, ' ')} ${yellow}${row.value.toString().padEnd(columnWidths.valueColumn, ' ')} ${grey}${reset}`; tableString += `\n${grey}${reset} ${row.label.padEnd(columnWidths.labelColumn, ' ')} ${yellow}${row.value
.toString()
.padEnd(columnWidths.valueColumn, ' ')} ${grey}${reset}`;
}); });
tableString += `\n${grey}${horizontalLine}${reset}`; tableString += `\n${grey}${horizontalLine}${reset}`;
@ -90,11 +102,12 @@ ${grey}╞${horizontalLine}╡${reset}`;
async function attemptLogin() { async function attemptLogin() {
logger.info(` Logging into ${yellow}${program.host}${reset} with user ${yellow}${program.username}${reset}`); logger.info(` Logging into ${yellow}${program.host}${reset} with user ${yellow}${program.username}${reset}`);
try { try {
jsApiConnection = new AlfrescoApi({ alfrescoApi = new AlfrescoApi({
provider: 'ALL', provider: 'ALL',
hostBpm: program.host, hostBpm: program.host,
hostEcm: program.host, hostEcm: program.host,
authType: 'OAUTH', authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: { oauth2: {
host: `${program.host}/auth/realms/alfresco`, host: `${program.host}/auth/realms/alfresco`,
clientId: `${program.clientId}`, clientId: `${program.clientId}`,
@ -102,8 +115,8 @@ async function attemptLogin() {
redirectUri: '/', redirectUri: '/',
implicitFlow: false implicitFlow: false
} }
} as unknown as AlfrescoApiConfig); });
await jsApiConnection.login(program.username, program.password); await alfrescoApi.login(program.username, program.password);
logger.info(` ${green}Login SSO successful${reset}`); logger.info(` ${green}Login SSO successful${reset}`);
} catch (err) { } catch (err) {
await handleLoginError(err); await handleLoginError(err);
@ -117,7 +130,7 @@ async function handleLoginError(loginError) {
checkEnvReachable(loginError); checkEnvReachable(loginError);
loginAttempts++; loginAttempts++;
if (MAX_ATTEMPTS === loginAttempts) { if (MAX_ATTEMPTS === loginAttempts) {
if (loginError && loginError.response && loginError?.response?.text) { if (loginError?.response?.text) {
try { try {
const parsedJson = JSON.parse(loginError?.response?.text); const parsedJson = JSON.parse(loginError?.response?.text);
if (typeof parsedJson === 'object' && parsedJson.error) { if (typeof parsedJson === 'object' && parsedJson.error) {
@ -150,20 +163,23 @@ async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
logger.info(` Fetching number of users`); logger.info(` Fetching number of users`);
} }
try { try {
const peopleApi = new PeopleApi(jsApiConnection); const peopleApi = new PeopleApi(alfrescoApi);
const apiResult = await peopleApi.listPeople({ const apiResult = await peopleApi.listPeople({
fields: ['enabled'], fields: ['enabled'],
maxItems: MAX_PEOPLE_PER_PAGE, maxItems: MAX_PEOPLE_PER_PAGE,
skipCount skipCount
}); });
const result: PeopleTally = apiResult.list.entries.reduce((peopleTally: PeopleTally, currentPerson) => { const result: PeopleTally = apiResult.list.entries.reduce(
(peopleTally: PeopleTally, currentPerson) => {
if (currentPerson.entry.enabled) { if (currentPerson.entry.enabled) {
peopleTally.enabled++; peopleTally.enabled++;
} else { } else {
peopleTally.disabled++; peopleTally.disabled++;
} }
return peopleTally; return peopleTally;
}, { enabled: 0, disabled: 0 }); },
{ enabled: 0, disabled: 0 }
);
if (apiResult.list.pagination.hasMoreItems) { if (apiResult.list.pagination.hasMoreItems) {
const more = await getPeopleCount(apiResult.list.pagination.skipCount + MAX_PEOPLE_PER_PAGE); const more = await getPeopleCount(apiResult.list.pagination.skipCount + MAX_PEOPLE_PER_PAGE);
result.enabled += more.enabled; result.enabled += more.enabled;
@ -178,7 +194,7 @@ async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
async function getHomeFoldersCount(): Promise<number> { async function getHomeFoldersCount(): Promise<number> {
logger.info(` Fetching number of home folders`); logger.info(` Fetching number of home folders`);
try { try {
const nodesApi = new NodesApi(jsApiConnection); const nodesApi = new NodesApi(alfrescoApi);
const homesFolderApiResult = await nodesApi.listNodeChildren('-root-', { const homesFolderApiResult = await nodesApi.listNodeChildren('-root-', {
maxItems: 1, maxItems: 1,
relativePath: USERS_HOME_RELATIVE_PATH relativePath: USERS_HOME_RELATIVE_PATH
@ -192,7 +208,7 @@ async function getHomeFoldersCount(): Promise<number> {
async function getGroupsCount(): Promise<number> { async function getGroupsCount(): Promise<number> {
logger.info(` Fetching number of groups`); logger.info(` Fetching number of groups`);
try { try {
const groupsApi = new GroupsApi(jsApiConnection); const groupsApi = new GroupsApi(alfrescoApi);
const groupsApiResult = await groupsApi.listGroups({ maxItems: 1 }); const groupsApiResult = await groupsApi.listGroups({ maxItems: 1 });
return groupsApiResult.list.pagination.totalItems; return groupsApiResult.list.pagination.totalItems;
} catch (error) { } catch (error) {
@ -203,7 +219,7 @@ async function getGroupsCount(): Promise<number> {
async function getSitesCount(): Promise<number> { async function getSitesCount(): Promise<number> {
logger.info(` Fetching number of sites`); logger.info(` Fetching number of sites`);
try { try {
const sitesApi = new SitesApi(jsApiConnection); const sitesApi = new SitesApi(alfrescoApi);
const sitesApiResult = await sitesApi.listSites({ maxItems: 1 }); const sitesApiResult = await sitesApi.listSites({ maxItems: 1 });
return sitesApiResult.list.pagination.totalItems; return sitesApiResult.list.pagination.totalItems;
} catch (error) { } catch (error) {
@ -214,7 +230,7 @@ async function getSitesCount(): Promise<number> {
async function getFilesCount(): Promise<number> { async function getFilesCount(): Promise<number> {
logger.info(` Fetching number of files`); logger.info(` Fetching number of files`);
try { try {
const searchApi = new SearchApi(jsApiConnection); const searchApi = new SearchApi(alfrescoApi);
const searchApiResult = await searchApi.search({ const searchApiResult = await searchApi.search({
query: { query: {
query: 'select * from cmis:document', query: 'select * from cmis:document',
@ -248,11 +264,11 @@ function handleError(error) {
function failScript() { function failScript() {
logger.error(`${red}${bright}Environment scan failed. Exiting${reset}`); logger.error(`${red}${bright}Environment scan failed. Exiting${reset}`);
process.exit(0); exit(0);
} }
async function wait(ms: number) { async function wait(ms: number) {
return new Promise(resolve => { return new Promise((resolve) => {
setTimeout(resolve, ms); setTimeout(resolve, ms);
}); });
} }

View File

@ -23,13 +23,13 @@ import { zipNode, downloadEntry } from './download-zip-data.mock';
export class AlfrescoApiServiceMock { export class AlfrescoApiServiceMock {
nodeUpdated = new Subject<Node>(); nodeUpdated = new Subject<Node>();
alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1); alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1);
alfrescoApi = new AlfrescoApiCompatibilityMock(); alfrescoApi = new AlfrescoApiMock();
load() {} load() {}
getInstance = () => this.alfrescoApi; getInstance = () => this.alfrescoApi;
} }
class AlfrescoApiCompatibilityMock { class AlfrescoApiMock {
core = new CoreMock(); core = new CoreMock();
content = new ContentApiMock(); content = new ContentApiMock();

View File

@ -1,51 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { MockProvider } from 'ng-mocks';
import { AuthService } from '../../auth.service';
import { AuthenticationConfirmationComponent } from './authentication-confirmation.component';
describe('AuthenticationConfirmationComponent', () => {
let component: AuthenticationConfirmationComponent;
let fixture: ComponentFixture<AuthenticationConfirmationComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AuthenticationConfirmationComponent],
providers: [
MockProvider(AuthService, {
loginCallback() {
return Promise.resolve(undefined);
}
})
],
imports: [RouterTestingModule]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AuthenticationConfirmationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -16,43 +16,12 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { import { AlfrescoApi } from '@alfresco/js-api';
AlfrescoApiCompatibility, import { AlfrescoApiService } from '@alfresco/adf-core';
ContentApi,
Node, NodesApi
} from '@alfresco/js-api';
import { ReplaySubject, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ExternalAlfrescoApiService {
/**
* Publish/subscribe to events related to node updates.
*/
nodeUpdated = new Subject<Node>();
alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1);
protected alfrescoApi: AlfrescoApiCompatibility;
_nodesApi: NodesApi;
getInstance(): AlfrescoApiCompatibility {
return this.alfrescoApi;
}
get contentApi(): ContentApi {
return this.getInstance().content;
}
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.getInstance());
return this._nodesApi;
}
@Injectable({ providedIn: 'root' })
export class ExternalAlfrescoApiService extends AlfrescoApiService {
init(ecmHost: string, contextRoot: string) { init(ecmHost: string, contextRoot: string) {
const domainPrefix = this.createPrefixFromHost(ecmHost); const domainPrefix = this.createPrefixFromHost(ecmHost);
const config = { const config = {
@ -62,15 +31,15 @@ export class ExternalAlfrescoApiService {
contextRoot, contextRoot,
domainPrefix domainPrefix
}; };
this.initAlfrescoApi(config); this.setup(config);
this.alfrescoApiInitialized.next(true); this.alfrescoApiInitialized.next(true);
} }
protected initAlfrescoApi(config) { private setup(config) {
if (this.alfrescoApi) { if (this.alfrescoApi) {
this.alfrescoApi.configureJsApi(config); this.alfrescoApi.setConfig(config);
} else { } else {
this.alfrescoApi = new AlfrescoApiCompatibility(config); this.alfrescoApi = new AlfrescoApi(config);
} }
} }

View File

@ -17,12 +17,7 @@
import { Component, Inject, ViewEncapsulation, ViewChild } from '@angular/core'; import { Component, Inject, ViewEncapsulation, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { import { AlfrescoApiService, LoginDialogPanelComponent, TranslationService, AuthenticationService } from '@alfresco/adf-core';
AlfrescoApiService,
LoginDialogPanelComponent,
TranslationService,
AuthenticationService
} from '@alfresco/adf-core';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface'; import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { DocumentListService, SitesService, SearchService } from '@alfresco/adf-content-services'; import { DocumentListService, SitesService, SearchService } from '@alfresco/adf-content-services';
import { ExternalAlfrescoApiService } from '../../services/external-alfresco-api.service'; import { ExternalAlfrescoApiService } from '../../services/external-alfresco-api.service';
@ -38,10 +33,10 @@ import { Node } from '@alfresco/js-api';
DocumentListService, DocumentListService,
SitesService, SitesService,
SearchService, SearchService,
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService } ] { provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService }
]
}) })
export class AttachFileWidgetDialogComponent { export class AttachFileWidgetDialogComponent {
@ViewChild('adfLoginPanel') @ViewChild('adfLoginPanel')
loginPanel: LoginDialogPanelComponent; loginPanel: LoginDialogPanelComponent;
@ -50,12 +45,14 @@ export class AttachFileWidgetDialogComponent {
buttonActionName: string; buttonActionName: string;
chosenNode: Node[]; chosenNode: Node[];
constructor(private translation: TranslationService, constructor(
private translation: TranslationService,
@Inject(MAT_DIALOG_DATA) public data: AttachFileWidgetDialogComponentData, @Inject(MAT_DIALOG_DATA) public data: AttachFileWidgetDialogComponentData,
private externalApiService: AlfrescoApiService, private externalApiService: AlfrescoApiService,
private authenticationService: AuthenticationService, private authenticationService: AuthenticationService,
private matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>) { private matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>
(externalApiService as any).init(data.ecmHost, data.context); ) {
(externalApiService as ExternalAlfrescoApiService).init(data.ecmHost, data.context);
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE'; this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
this.buttonActionName = `ATTACH-FILE.ACTIONS.${this.action}`; this.buttonActionName = `ATTACH-FILE.ACTIONS.${this.action}`;
this.updateTitle('DROPDOWN.MY_FILES_OPTION'); this.updateTitle('DROPDOWN.MY_FILES_OPTION');
@ -64,13 +61,13 @@ export class AttachFileWidgetDialogComponent {
updateExternalHost() { updateExternalHost() {
this.authenticationService.onLogin.subscribe(() => this.registerAndClose()); this.authenticationService.onLogin.subscribe(() => this.registerAndClose());
if (this.externalApiService.getInstance().isLoggedIn()) { if (this.isLoggedIn()) {
this.registerAndClose(); this.registerAndClose();
} }
} }
isLoggedIn() { isLoggedIn(): boolean {
return this.externalApiService.getInstance().isLoggedIn(); return !!this.externalApiService.getInstance()?.isLoggedIn();
} }
performLogin() { performLogin() {

View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { UrlService, LogService, ContentLinkModel, FormService, DownloadService } from '@alfresco/adf-core'; import { UrlService, ContentLinkModel, FormService, DownloadService } from '@alfresco/adf-core';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ProcessContentService } from '../../services/process-content.service'; import { ProcessContentService } from '../../services/process-content.service';
@ -27,7 +27,6 @@ import { ProcessContentService } from '../../services/process-content.service';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ContentWidgetComponent implements OnChanges { export class ContentWidgetComponent implements OnChanges {
/** The content id to show. */ /** The content id to show. */
@Input() @Input()
id: string; id: string;
@ -54,12 +53,12 @@ export class ContentWidgetComponent implements OnChanges {
content: ContentLinkModel; content: ContentLinkModel;
constructor(protected formService: FormService, constructor(
private logService: LogService, protected formService: FormService,
private downloadService: DownloadService, private downloadService: DownloadService,
private urlService: UrlService, private urlService: UrlService,
private processContentService: ProcessContentService) { private processContentService: ProcessContentService
} ) {}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
const contentId = changes['id']; const contentId = changes['id'];
@ -69,9 +68,7 @@ export class ContentWidgetComponent implements OnChanges {
} }
loadContent(id: number) { loadContent(id: number) {
this.processContentService this.processContentService.getFileContent(id).subscribe(
.getFileContent(id)
.subscribe(
(response: ContentLinkModel) => { (response: ContentLinkModel) => {
this.content = new ContentLinkModel(response); this.content = new ContentLinkModel(response);
this.contentLoaded.emit(this.content); this.contentLoaded.emit(this.content);
@ -101,7 +98,6 @@ export class ContentWidgetComponent implements OnChanges {
}, },
(error) => { (error) => {
this.error.emit(error); this.error.emit(error);
} }
); );
} }
@ -117,7 +113,6 @@ export class ContentWidgetComponent implements OnChanges {
(blob: Blob) => { (blob: Blob) => {
content.contentBlob = blob; content.contentBlob = blob;
this.contentClick.emit(content); this.contentClick.emit(content);
this.logService.info('Content clicked' + content.id);
this.formService.formContentClicked.next(content); this.formService.formContentClicked.next(content);
}, },
(error) => { (error) => {

15
package-lock.json generated
View File

@ -124,7 +124,6 @@
"lite-server": "^2.6.1", "lite-server": "^2.6.1",
"mini-css-extract-plugin": "^1.6.0", "mini-css-extract-plugin": "^1.6.0",
"nconf": "^0.12.0", "nconf": "^0.12.0",
"ng-mocks": "^14.8.0",
"ng-packagr": "14.0.3", "ng-packagr": "14.0.3",
"nx": "14.4.2", "nx": "14.4.2",
"postcss": "^8.4.5", "postcss": "^8.4.5",
@ -39760,20 +39759,6 @@
"version": "1.1.0", "version": "1.1.0",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ng-mocks": {
"version": "14.10.0",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/satanTime"
},
"peerDependencies": {
"@angular/common": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16",
"@angular/core": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16",
"@angular/forms": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16",
"@angular/platform-browser": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16"
}
},
"node_modules/ng-packagr": { "node_modules/ng-packagr": {
"version": "14.0.3", "version": "14.0.3",
"dev": true, "dev": true,

View File

@ -168,7 +168,6 @@
"lite-server": "^2.6.1", "lite-server": "^2.6.1",
"mini-css-extract-plugin": "^1.6.0", "mini-css-extract-plugin": "^1.6.0",
"nconf": "^0.12.0", "nconf": "^0.12.0",
"ng-mocks": "^14.8.0",
"ng-packagr": "14.0.3", "ng-packagr": "14.0.3",
"nx": "14.4.2", "nx": "14.4.2",
"postcss": "^8.4.5", "postcss": "^8.4.5",
@ -226,4 +225,3 @@
"module": "./index.js", "module": "./index.js",
"typings": "./index.d.ts" "typings": "./index.d.ts"
} }