[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 rimraf = require('rimraf');
const path = require('path');
const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const TestConfig = require('../test.config');
const AlfrescoApi = require('@alfresco/js-api').AlfrescoApiCompatibility;
const { AlfrescoApi, NodesApi, UploadApi } = require('@alfresco/js-api');
function buildNumber() {
let buildNumber = process.env.GH_BUILD_NUMBER;
@ -16,54 +16,57 @@ function buildNumber() {
async function uploadScreenshot(retryCount, suffixFileName) {
console.log(`Start uploading report ${retryCount}`);
let alfrescoJsApi = new AlfrescoApi({
const alfrescoJsApi = new AlfrescoApi({
provider: 'ECM',
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);
let folderNode;
try {
folderNode = await alfrescoJsApi.nodes.addNode('-my-', {
'name': `retry-${retryCount}`,
'relativePath': `Builds/${buildNumber()}/`,
'nodeType': 'cm:folder'
}, {}, {
'overwrite': true
});
folderNode = await nodesApi.createNode(
'-my-',
{
name: `retry-${retryCount}`,
relativePath: `Builds/${buildNumber()}/`,
nodeType: 'cm:folder'
},
{},
{
overwrite: true
}
);
} catch (error) {
folderNode = await alfrescoJsApi.nodes.getNode('-my-', {
'relativePath': `Builds/${buildNumber()}/retry-${retryCount}`,
'nodeType': 'cm:folder'
}, {}, {
'overwrite': true
folderNode = await nodesApi.getNode('-my-', {
relativePath: `Builds/${buildNumber()}/retry-${retryCount}`
});
}
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");
child_process.execSync(` tar -czvf ../e2e-result-${suffixFileName}-${retryCount}.tar .`, {
cwd: path.resolve(__dirname, `../../e2e-output-${retryCount}-${process.env.GH_ACTION_RETRY_COUNT}/`)
spawnSync(` tar -czvf ../e2e-result-${suffixFileName}-${retryCount}.tar .`, {
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`);
let file = fs.createReadStream(pathFile);
await alfrescoJsApi.upload.uploadFile(
file,
'',
folderNode.entry.id,
null,
{
'name': `e2e-result-${suffixFileName}-${retryCount}.tar`,
'nodeType': 'cm:content',
'autoRename': true
}
);
const pathFile = path.join(__dirname, `../../e2e-result-${suffixFileName}-${retryCount}.tar`);
const file = fs.createReadStream(pathFile);
await uploadApi.uploadFile(file, '', folderNode.entry.id, null, {
name: `e2e-result-${suffixFileName}-${retryCount}.tar`,
nodeType: 'cm:content',
autoRename: true
});
}
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 path = require('path');
const fs = require('fs');
/* eslint-enable */
import { logger } from './logger';
const MAX_RETRY = 3;
const TIMEOUT = 20000;
let counter = 0;
let alfrescoJsApi: AlfrescoApi;
export default async function main(_args: string[]) {
program
.version('0.1.0')
.description('Check Content service is up ')
@ -20,24 +35,26 @@ export default async function main(_args: string[]) {
.option('-u, --username [type]', 'username ')
.option('-t, --time [type]', 'time ')
.option('-r, --retry [type]', 'retry ')
.parse(process.argv);
.parse(argv);
await checkEnv();
await checkDiskSpaceFullEnv();
// TODO: https://alfresco.atlassian.net/browse/ACS-5873
// await checkDiskSpaceFullEnv();
}
async function checkEnv() {
try {
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({
alfrescoJsApi = new AlfrescoApi({
provider: 'ECM',
hostEcm: program.host
hostEcm: program.host,
contextRoot: 'alfresco'
});
await alfrescoJsApi.login(program.username, program.password);
} catch (error) {
if (error?.error?.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating');
process.exit(1);
exit(1);
}
logger.error('Login error environment down or inaccessible');
counter++;
@ -45,63 +62,33 @@ async function checkEnv() {
const time = program.time || TIMEOUT;
if (retry === counter) {
logger.error('Give up');
process.exit(1);
exit(1);
} else {
logger.error(`Retry in 1 minute attempt N ${counter}`, error);
sleep(time);
checkEnv();
await checkEnv();
}
}
}
// @ts-ignore
async function checkDiskSpaceFullEnv() {
logger.info(`Start Check disk full space`);
try {
const nodesApi = new NodesApi(alfrescoJsApi);
const uploadApi = new UploadApi(alfrescoJsApi);
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({
provider: 'ECM',
hostEcm: program.host
});
const fileContent = 'x'.repeat(1024 * 1024);
const file = Buffer.from(fileContent, 'utf8');
await alfrescoJsApi.login(program.username, program.password);
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,
{
const uploadedFile = await uploadApi.uploadFile(file, '', '-my-', null, {
name: 'README.md',
nodeType: 'cm:content',
autoRename: true
}
);
});
alfrescoJsApi.node.deleteNode(uploadedFile.entry.id, {permanent: true});
await nodesApi.deleteNode(uploadedFile.entry.id, { permanent: true });
} catch (error) {
counter++;
@ -112,18 +99,17 @@ async function checkDiskSpaceFullEnv() {
logger.info('================ Not able to upload a file ==================');
logger.info('================ Possible cause CS is full ==================');
logger.info('=============================================================');
process.exit(1);
exit(1);
} else {
logger.error(`Retry N ${counter} ${error?.error?.status}`);
logger.error(`Retry N ${counter}`);
logger.error(JSON.stringify(error));
sleep(time);
checkDiskSpaceFullEnv();
await checkDiskSpaceFullEnv();
}
}
}
}
}
function sleep(delay) {
function sleep(delay: number) {
const start = new Date().getTime();
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');
/* eslint-enable */
import { logger } from './logger';
const MAX_RETRY = 10;
const TIMEOUT = 60000;
let counter = 0;
export default async function main(_args: string[]) {
program
.version('0.1.0')
.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('-p, --password [type]', 'password ')
.option('-u, --username [type]', 'username ')
.parse(process.argv);
.parse(argv);
await checkEnv();
}
async function checkEnv() {
try {
const alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({
const alfrescoJsApi = new AlfrescoApi({
provider: 'BPM',
hostBpm: program.host
hostBpm: program.host,
contextRoot: 'alfresco'
});
await alfrescoJsApi.login(program.username, program.password);
} catch (e) {
if (e.error.code === 'ETIMEDOUT') {
logger.error('The env is not reachable. Terminating');
process.exit(1);
exit(1);
}
logger.error('Login error environment down or inaccessible');
counter++;
if (MAX_RETRY === counter) {
logger.error('Give up');
process.exit(1);
exit(1);
} else {
logger.error(`Retry in 1 minute attempt N ${counter}`);
sleep(TIMEOUT);
checkEnv();
await checkEnv();
}
}
}
function sleep(delay) {
function sleep(delay: number) {
const start = new Date().getTime();
while (new Date().getTime() < start + delay) {}
}

View File

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

View File

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

View File

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

View File

@ -17,6 +17,7 @@
* limitations under the License.
*/
import { argv, exit } from 'node:process';
import program from 'commander';
import moment from 'moment';
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
@ -40,11 +41,12 @@ export interface ConfigArgs {
intervalTime: string;
}
function getAlfrescoJsApiInstance(args: ConfigArgs) {
const config = {
function getAlfrescoJsApiInstance(args: ConfigArgs): AlfrescoApi {
const config: AlfrescoApiConfig = {
provider: 'BPM',
hostBpm: `${args.host}`,
authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: {
host: `${args.oauth}/auth/realms/alfresco`,
clientId: `${args.clientId}`,
@ -55,21 +57,21 @@ function getAlfrescoJsApiInstance(args: ConfigArgs) {
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...`);
try {
await alfrescoJsApi.login(username, password);
} catch (error) {
logger.error(`Not able to login. Credentials ${username}:${password} are not valid`);
process.exit(1);
exit(1);
}
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}`);
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'];
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) {
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}`);
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'];
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) {
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}`);
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'];
try {
const data = await apiService.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam,
contentTypes, accepts);
const data = await apiService.oauth2Auth.callCustomApi(
url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
for (let i = 0; i < data.list.entries.length; i++) {
if (data.list.entries[i].entry.name === name) {
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) {
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}`);
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'];
try {
const apps = await apiService.oauth2Auth.callCustomApi(url, 'GET', pathParams, queryParams, headerParams, formParams, bodyParam,
contentTypes, accepts);
const apps = await apiService.oauth2Auth.callCustomApi(
url,
'GET',
pathParams,
queryParams,
headerParams,
formParams,
bodyParam,
contentTypes,
accepts
);
return apps ? apps.list.entries : [];
} catch (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}`);
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'];
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) {
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) {
await main(args);
}
@ -188,8 +244,10 @@ export default async function(args: ConfigArgs) {
const main = async (args: ConfigArgs) => {
program
.version('0.1.0')
.description('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"')
.description(
'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('-o, --oauth [type]', 'Host sso server')
.option('--clusterEnv [type]', 'cluster Envirorment')
@ -204,28 +262,34 @@ const main = async (args: ConfigArgs) => {
.option('--apps [type]', 'Application prefix')
.option('--enableLike [boolean]', 'Enable the like for app name')
.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();
return;
}
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');
}, (error) => {
},
(error) => {
logger.info(`login SSO error ${JSON.stringify(error)}`);
process.exit(1);
});
exit(1);
}
);
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');
}, (error) => {
},
(error) => {
logger.info(`login SSO error ${JSON.stringify(error)}`);
process.exit(1);
});
exit(1);
}
);
if (args.apps !== undefined) {
kube.setCluster(args.clusterEnv, args.clusterUrl);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,31 +18,22 @@
import { PluginInterface } from './plugin-model';
import { logger } from '../logger';
import { PluginConfiguration } from './plugin-config';
import { AlfrescoApi } from '@alfresco/js-api';
export class ProcessAutomationHealth {
config: PluginConfiguration;
constructor(
private plugInInfo: PluginInterface,
private alfrescoJsApi: any
) {
this.config = new PluginConfiguration(
this.plugInInfo,
this.alfrescoJsApi
);
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi);
}
async isPluginEnabledFromAppConfiguration() {
async isPluginEnabledFromAppConfiguration(): Promise<boolean> {
try {
const url = `${this.plugInInfo.host}/${this.plugInInfo.appName}/ui/${this.plugInInfo.uiName}/app.config.json`;
const appConfig = await this.config.getAppConfig(url);
let isEnabled = true;
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
logger.info(
`The plugin ${
this.plugInInfo.name
} has been correctly configured in app.config.json`
);
logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
} else {
this.logConfigurationError();
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`;
let isBackendActive = true;
try {
@ -68,20 +59,12 @@ export class ProcessAutomationHealth {
}
return isBackendActive;
} catch (error) {
logger.error(
`${this.plugInInfo.host} is not reachable error: `,
error
);
logger.error(`${this.plugInInfo.host} is not reachable error: `, error);
return false;
}
}
private logConfigurationError(error?: any) {
logger.error(
`The plugin ${
this.plugInInfo.name
} has not been correctly configured in app.config.json`,
error
);
private logConfigurationError(error?: any): void {
logger.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 { logger } from '../logger';
import { ProcessServiceHealth } from './process-services-health';
import { AlfrescoApi } from '@alfresco/js-api';
export class ProcessServiceCheckPlugin {
processServiceHealth: ProcessServiceHealth;
constructor(
private plugInInfo: PluginInterface,
private alfrescoJsApi: any
) {
this.processServiceHealth = new ProcessServiceHealth(
this.plugInInfo,
this.alfrescoJsApi
);
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
this.processServiceHealth = new ProcessServiceHealth(this.plugInInfo, this.alfrescoJsApi);
}
async checkProcessServicesPlugin() {
async checkProcessServicesPlugin(): Promise<void> {
let pluginStatus;
try {
const isPluginEnabled = await this.processServiceHealth.isPluginEnabledFromAppConfiguration();
const isBackendActive = await this.processServiceHealth.checkBackendHealth();
if (isPluginEnabled && isBackendActive) {
logger.info(
`The plugin ${
this.plugInInfo.name
} has been correctly configured`
);
logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured`);
pluginStatus = [{ PluginName: this.plugInInfo.name, Status: `${'Active'}`, BE: 'UP', FE: 'Enabled' }];
console.table(pluginStatus);
} else {
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);
process.exit(1);
}
@ -62,12 +60,7 @@ export class ProcessServiceCheckPlugin {
}
}
private logConfigurationError(error?: any) {
logger.error(
`The plugin ${
this.plugInInfo.name
} has not been correctly configured`,
error
);
private logConfigurationError(error?: any): void {
logger.error(`The plugin ${this.plugInInfo.name} has not been correctly configured`, error);
}
}

View File

@ -18,26 +18,22 @@
import { PluginInterface } from './plugin-model';
import { logger } from '../logger';
import { PluginConfiguration } from './plugin-config';
import { AlfrescoApi, SystemPropertiesApi } from '@alfresco/js-api';
export class ProcessServiceHealth {
config: PluginConfiguration;
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: any) {
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
this.config = new PluginConfiguration(this.plugInInfo, this.alfrescoJsApi);
}
async isPluginEnabledFromAppConfiguration() {
async isPluginEnabledFromAppConfiguration(): Promise<boolean> {
try {
const url = `${this.plugInInfo.host}/app.config.json`;
const appConfig = await this.config.getAppConfig(url);
let isEnabled = true;
if (appConfig && appConfig.plugins && appConfig.plugins[this.plugInInfo.name]) {
logger.info(
`The plugin ${
this.plugInInfo.name
} has been correctly configured in app.config.json`
);
logger.info(`The plugin ${this.plugInInfo.name} has been correctly configured in app.config.json`);
} else {
this.logConfigurationError();
return (isEnabled = false);
@ -50,9 +46,10 @@ export class ProcessServiceHealth {
}
}
async checkBackendHealth() {
async checkBackendHealth(): Promise<boolean> {
try {
const systemProperties = await this.alfrescoJsApi.activiti.systemPropertiesApi.getProperties();
const systemPropertiesApi = new SystemPropertiesApi(this.alfrescoJsApi);
const systemProperties = await systemPropertiesApi.getProperties();
let isBackendActive = true;
if (systemProperties) {
logger.info(`${this.plugInInfo.host} is UP!`);
@ -62,20 +59,12 @@ export class ProcessServiceHealth {
}
return isBackendActive;
} catch (error) {
logger.error(
`${this.plugInInfo.host} is not reachable error: `,
error
);
logger.error(`${this.plugInInfo.host} is not reachable error: `, error);
return false;
}
}
private logConfigurationError(error?: any) {
logger.error(
`The plugin ${
this.plugInInfo.name
} has not been correctly configured in app.config.json`,
error
);
private logConfigurationError(error?: any): void {
logger.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.
*/
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 { logger } from './logger';
interface PeopleTally { enabled: number; disabled: number }
interface RowToPrint { label: string; value: number }
interface PeopleTally {
enabled: number;
disabled: number;
}
interface RowToPrint {
label: string;
value: number;
}
const MAX_ATTEMPTS = 1;
const TIMEOUT = 180000;
@ -35,11 +42,10 @@ const bright = '\x1b[1m';
const red = '\x1b[31m';
const green = '\x1b[32m';
let jsApiConnection: any;
let alfrescoApi: AlfrescoApi;
let loginAttempts: number = 0;
export default async function main(_args: string[]) {
// eslint-disable-next-line no-console
console.log = () => {};
@ -49,7 +55,7 @@ export default async function main(_args: string[]) {
.option('--clientId [type]', 'sso client', 'alfresco')
.option('-p, --password <type>', 'password ')
.option('-u, --username <type>', 'username ')
.parse(process.argv);
.parse(argv);
logger.info(`${cyan}${bright}Initiating environment scan...${reset}`);
await attemptLogin();
@ -67,20 +73,26 @@ export default async function main(_args: string[]) {
}
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),
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 headerText = 'ENVIRONM'.padStart(Math.floor((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' ')
+ 'ENT SCAN'.padEnd(Math.ceil((columnWidths.labelColumn + columnWidths.valueColumn + 3) / 2), ' ');
const headerText =
'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}
${grey} ${bright}${cyan}${headerText} ${grey}${reset}
${grey}${horizontalLine}${reset}`;
rowsToPrint.forEach(row => {
tableString += `\n${grey}${reset} ${row.label.padEnd(columnWidths.labelColumn, ' ')} ${yellow}${row.value.toString().padEnd(columnWidths.valueColumn, ' ')} ${grey}${reset}`;
rowsToPrint.forEach((row) => {
tableString += `\n${grey}${reset} ${row.label.padEnd(columnWidths.labelColumn, ' ')} ${yellow}${row.value
.toString()
.padEnd(columnWidths.valueColumn, ' ')} ${grey}${reset}`;
});
tableString += `\n${grey}${horizontalLine}${reset}`;
@ -90,11 +102,12 @@ ${grey}╞${horizontalLine}╡${reset}`;
async function attemptLogin() {
logger.info(` Logging into ${yellow}${program.host}${reset} with user ${yellow}${program.username}${reset}`);
try {
jsApiConnection = new AlfrescoApi({
alfrescoApi = new AlfrescoApi({
provider: 'ALL',
hostBpm: program.host,
hostEcm: program.host,
authType: 'OAUTH',
contextRoot: 'alfresco',
oauth2: {
host: `${program.host}/auth/realms/alfresco`,
clientId: `${program.clientId}`,
@ -102,8 +115,8 @@ async function attemptLogin() {
redirectUri: '/',
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}`);
} catch (err) {
await handleLoginError(err);
@ -117,7 +130,7 @@ async function handleLoginError(loginError) {
checkEnvReachable(loginError);
loginAttempts++;
if (MAX_ATTEMPTS === loginAttempts) {
if (loginError && loginError.response && loginError?.response?.text) {
if (loginError?.response?.text) {
try {
const parsedJson = JSON.parse(loginError?.response?.text);
if (typeof parsedJson === 'object' && parsedJson.error) {
@ -150,20 +163,23 @@ async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
logger.info(` Fetching number of users`);
}
try {
const peopleApi = new PeopleApi(jsApiConnection);
const peopleApi = new PeopleApi(alfrescoApi);
const apiResult = await peopleApi.listPeople({
fields: ['enabled'],
maxItems: MAX_PEOPLE_PER_PAGE,
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) {
peopleTally.enabled++;
} else {
peopleTally.disabled++;
}
return peopleTally;
}, { enabled: 0, disabled: 0 });
},
{ enabled: 0, disabled: 0 }
);
if (apiResult.list.pagination.hasMoreItems) {
const more = await getPeopleCount(apiResult.list.pagination.skipCount + MAX_PEOPLE_PER_PAGE);
result.enabled += more.enabled;
@ -178,7 +194,7 @@ async function getPeopleCount(skipCount: number = 0): Promise<PeopleTally> {
async function getHomeFoldersCount(): Promise<number> {
logger.info(` Fetching number of home folders`);
try {
const nodesApi = new NodesApi(jsApiConnection);
const nodesApi = new NodesApi(alfrescoApi);
const homesFolderApiResult = await nodesApi.listNodeChildren('-root-', {
maxItems: 1,
relativePath: USERS_HOME_RELATIVE_PATH
@ -192,7 +208,7 @@ async function getHomeFoldersCount(): Promise<number> {
async function getGroupsCount(): Promise<number> {
logger.info(` Fetching number of groups`);
try {
const groupsApi = new GroupsApi(jsApiConnection);
const groupsApi = new GroupsApi(alfrescoApi);
const groupsApiResult = await groupsApi.listGroups({ maxItems: 1 });
return groupsApiResult.list.pagination.totalItems;
} catch (error) {
@ -203,7 +219,7 @@ async function getGroupsCount(): Promise<number> {
async function getSitesCount(): Promise<number> {
logger.info(` Fetching number of sites`);
try {
const sitesApi = new SitesApi(jsApiConnection);
const sitesApi = new SitesApi(alfrescoApi);
const sitesApiResult = await sitesApi.listSites({ maxItems: 1 });
return sitesApiResult.list.pagination.totalItems;
} catch (error) {
@ -214,7 +230,7 @@ async function getSitesCount(): Promise<number> {
async function getFilesCount(): Promise<number> {
logger.info(` Fetching number of files`);
try {
const searchApi = new SearchApi(jsApiConnection);
const searchApi = new SearchApi(alfrescoApi);
const searchApiResult = await searchApi.search({
query: {
query: 'select * from cmis:document',
@ -248,11 +264,11 @@ function handleError(error) {
function failScript() {
logger.error(`${red}${bright}Environment scan failed. Exiting${reset}`);
process.exit(0);
exit(0);
}
async function wait(ms: number) {
return new Promise(resolve => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

View File

@ -23,13 +23,13 @@ import { zipNode, downloadEntry } from './download-zip-data.mock';
export class AlfrescoApiServiceMock {
nodeUpdated = new Subject<Node>();
alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1);
alfrescoApi = new AlfrescoApiCompatibilityMock();
alfrescoApi = new AlfrescoApiMock();
load() {}
getInstance = () => this.alfrescoApi;
}
class AlfrescoApiCompatibilityMock {
class AlfrescoApiMock {
core = new CoreMock();
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 {
AlfrescoApiCompatibility,
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;
}
import { AlfrescoApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '@alfresco/adf-core';
@Injectable({ providedIn: 'root' })
export class ExternalAlfrescoApiService extends AlfrescoApiService {
init(ecmHost: string, contextRoot: string) {
const domainPrefix = this.createPrefixFromHost(ecmHost);
const config = {
@ -62,15 +31,15 @@ export class ExternalAlfrescoApiService {
contextRoot,
domainPrefix
};
this.initAlfrescoApi(config);
this.setup(config);
this.alfrescoApiInitialized.next(true);
}
protected initAlfrescoApi(config) {
private setup(config) {
if (this.alfrescoApi) {
this.alfrescoApi.configureJsApi(config);
this.alfrescoApi.setConfig(config);
} 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 { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {
AlfrescoApiService,
LoginDialogPanelComponent,
TranslationService,
AuthenticationService
} from '@alfresco/adf-core';
import { AlfrescoApiService, LoginDialogPanelComponent, TranslationService, AuthenticationService } from '@alfresco/adf-core';
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
import { DocumentListService, SitesService, SearchService } from '@alfresco/adf-content-services';
import { ExternalAlfrescoApiService } from '../../services/external-alfresco-api.service';
@ -38,10 +33,10 @@ import { Node } from '@alfresco/js-api';
DocumentListService,
SitesService,
SearchService,
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService } ]
{ provide: AlfrescoApiService, useClass: ExternalAlfrescoApiService }
]
})
export class AttachFileWidgetDialogComponent {
@ViewChild('adfLoginPanel')
loginPanel: LoginDialogPanelComponent;
@ -50,12 +45,14 @@ export class AttachFileWidgetDialogComponent {
buttonActionName: string;
chosenNode: Node[];
constructor(private translation: TranslationService,
constructor(
private translation: TranslationService,
@Inject(MAT_DIALOG_DATA) public data: AttachFileWidgetDialogComponentData,
private externalApiService: AlfrescoApiService,
private authenticationService: AuthenticationService,
private matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>) {
(externalApiService as any).init(data.ecmHost, data.context);
private matDialogRef: MatDialogRef<AttachFileWidgetDialogComponent>
) {
(externalApiService as ExternalAlfrescoApiService).init(data.ecmHost, data.context);
this.action = data.actionName ? data.actionName.toUpperCase() : 'CHOOSE';
this.buttonActionName = `ATTACH-FILE.ACTIONS.${this.action}`;
this.updateTitle('DROPDOWN.MY_FILES_OPTION');
@ -64,13 +61,13 @@ export class AttachFileWidgetDialogComponent {
updateExternalHost() {
this.authenticationService.onLogin.subscribe(() => this.registerAndClose());
if (this.externalApiService.getInstance().isLoggedIn()) {
if (this.isLoggedIn()) {
this.registerAndClose();
}
}
isLoggedIn() {
return this.externalApiService.getInstance().isLoggedIn();
isLoggedIn(): boolean {
return !!this.externalApiService.getInstance()?.isLoggedIn();
}
performLogin() {

View File

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

15
package-lock.json generated
View File

@ -124,7 +124,6 @@
"lite-server": "^2.6.1",
"mini-css-extract-plugin": "^1.6.0",
"nconf": "^0.12.0",
"ng-mocks": "^14.8.0",
"ng-packagr": "14.0.3",
"nx": "14.4.2",
"postcss": "^8.4.5",
@ -39760,20 +39759,6 @@
"version": "1.1.0",
"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": {
"version": "14.0.3",
"dev": true,

View File

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