let alfrescoApi = require('@alfresco/js-api'); let program = require('commander'); let fs = require ('fs'); const path = require('path'); const { throwError } = require('rxjs'); const { AppDefinitionsApi, RuntimeAppDefinitionsApi } = require('@alfresco/js-api'); let MAX_RETRY = 10; let counter = 0; let TIMEOUT = 6000; const TENANT_DEFAULT_ID = 1; const TENANT_DEFAULT_NAME = 'default'; const CONTENT_DEFAULT_NAME = 'adw-content'; const APS_DEFAULT_APP_NAME = 'e2e-Application'; let alfrescoJsApi; export default async function () { await main(); } async function main() { program .version('0.1.0') .option('--host [type]', 'Remote environment host') .option('-p, --password [type]', 'password ') .option('-u, --username [type]', 'username ') .option('--license [type]', 'APS license S3 path ') .parse(process.argv); await checkEnv(); console.log(`***** Step 1 - Check License *****`); let licenceUploaded = false; const hasValidLicense = await hasLicense() ; if (!hasValidLicense) { console.log(`Aps License missing`); const isLicenseFileDownloaded = await downloadLicenseFile(program.license); if (isLicenseFileDownloaded) { licenceUploaded = await updateLicense(); } } else { licenceUploaded = true; console.log(`Aps License present`); } let tenantId; if (licenceUploaded) { console.log(`***** Step 2 - Check Tenant *****`); console.log(`is tenandId:${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. tenantId = await createDefaultTenant(TENANT_DEFAULT_NAME); } console.log(`***** Step 3 - Add Content Repo *****`); const isContentPresent = await isContenRepoPresent(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME); if (!isContentPresent) { console.log(`No content repo with name ${CONTENT_DEFAULT_NAME} found`); await addContentRepoWithBasic(TENANT_DEFAULT_ID, CONTENT_DEFAULT_NAME) } console.log(`***** Step 4 - Create users *****`); const users = await getUserFromRealm(); if (tenantId && users && users.length > 0) { for (let i = 0; i < users.length; i++) { await createUsers(tenantId, users[i]); } for (let i = 0; i < users.length; i++) { console.log('Impersonate user: '+ users[i].username); await this.alfrescoJsApiRepo.login(users[i].username, 'password'); await authorizeUserToContentRepo(users[i]); const defaultUser = 'hruser'; if (users[i].username.includes(defaultUser)) { console.log(`***** Step verify default app already imported for ${defaultUser} *****`); const isDefaultAppDepl = await isDefaultAppDeployed(); if (isDefaultAppDepl !== undefined && !isDefaultAppDepl) { const appDefinition = await importPublishApp(); await deployApp(appDefinition.appDefinition.id); } else { console.log(`***** Default app already deployed *****`); } } } } else { console.log('Something went wrong. Was not able to create the users'); } } catch (error) { console.log(`Aps something went wrong. Tenant id ${tenantId}`); } } else { console.log('APS license error: check the configuration'); } } async function checkEnv() { try { alfrescoJsApi = new alfrescoApi.AlfrescoApiCompatibility({ provider: 'ALL', hostBpm: program.host, hostEcm: program.host, authType: 'OAUTH', oauth2: { host: `${program.host}/auth/realms/alfresco`, clientId: "alfresco", scope: "openid" } }); await alfrescoJsApi.login(program.username, program.password); } catch (e) { console.log('Login error environment down or inaccessible'); counter++; if (MAX_RETRY === counter) { console.log('Give up'); process.exit(1); } else { console.log(`Retry in 1 minute attempt N ${counter}`); sleep(TIMEOUT); checkEnv(); } } } async function hasDefaultTenant(tenantId, tenantName) { let tenant; try { tenant = await alfrescoJsApi.activiti.adminTenantsApi.getTenant(tenantId); } catch (error) { console.log(`Aps: does not have tenant with id: ${tenantId}`); return false; } if (tenant.name === tenantName) { console.log(`Aps: has default tenantId: ${tenantId} and name ${tenantName}`); return true; } else { console.log(`Wrong configuration. Another tenant has been created with id ${tenant.id} and name ${tenant.name}`); throwError(`Wrong configuration. Another tenant has been created with id ${tenant.id} and name ${tenant.name}`); } } async function createDefaultTenant(tenantName) { let tenantPost = { 'active': true, 'maxUsers': 10000, 'name' : tenantName }; try { const tenant = await alfrescoJsApi.activiti.adminTenantsApi.createTenant(tenantPost); console.log(`APS: Tenant ${tenantName} created with id: ${tenant.id}`); return tenant.id; } catch (error) { console.log(`APS: not able to create the default tenant: ${JSON.parse(error.message)}` ); } } async function createUsers(tenandId, user) { console.log(`Create user ${user.email} on tenant: ${tenandId}`); const passwordCamelCase = 'Password'; const userJson = { 'email': user.email, 'firstName': user.firstName, 'lastName': user.lastName, 'status': 'active', 'type': 'enterprise', 'password': passwordCamelCase, 'tenantId': tenandId }; try { const user = await alfrescoJsApi.activiti.adminUsersApi.createNewUser(userJson); console.log(`APS: User ${user.email} created with id: ${user.id}`); return user; } catch (error) { console.log(`APS: not able to create the default user: ${error.message}` ); } } async function updateLicense() { const fileContent = fs.createReadStream(path.join(__dirname, "/activiti.lic")); try { await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/license`, 'POST', {}, {}, {}, { file: fileContent }, {}, ['multipart/form-data'], ['application/json'] ); console.log(`Aps License uploaded!`); return true; } catch (error) { console.log(`Aps License failed!` ); return false; } } async function isDefaultAppDeployed() { console.log(`Verify ${APS_DEFAULT_APP_NAME} already deployed`); try { let runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi); const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions(); const defaultApp = availableApps.data && availableApps.data.filter( app => app.name && app.name.includes(APS_DEFAULT_APP_NAME)); return defaultApp && defaultApp.length > 0; } catch (error) { console.log(`Aps app failed to import/Publish!`); } } async function importPublishApp() { const appName = `${APS_DEFAULT_APP_NAME}.zip`; console.log(`Import app ${appName}`); const fileContent = fs.createReadStream(path.join(__dirname, `../../../apps/process-services-extension-e2e/src/resources/${appName}`)); try { let appdefinitionsApi = new AppDefinitionsApi(alfrescoJsApi); const result = await appdefinitionsApi.importAndPublishApp(fileContent, {renewIdmEntries: true}); console.log(`Aps app imported and published!`); return result; } catch (error) { console.log(`Aps app failed to import/Publish!`); } } async function deployApp(appDefinitioId) { console.log(`Deploy app with id ${appDefinitioId}`); const body = { appDefinitions: [{id: appDefinitioId}] }; try { let runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi); await runtimeAppDefinitionsApi.deployAppDefinitions(body); console.log(`Aps app deployed`); } catch (error) { console.log(`Aps app failed to deploy!`); } } async function hasLicense() { try { const license = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/license`, 'GET', {}, {}, {}, {}, {}, ['application/json'], ['application/json'] ); if (license && license.status === 'valid') { console.log(`Aps has a valid License!`); return true } console.log(`Aps does NOT have a valid License!`); return false } catch (error) { console.log(`Aps not able to check the license` ); } } async function getUserFromRealm() { try { const users = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/auth/admin/realms/alfresco/users`, 'GET', {}, {}, {}, {}, {}, ['application/json'], ['application/json'] ); let usersExample = users.filter(user => user.email.includes('@example.com')); let usersWithoutAdmin = usersExample.filter(user => (user.username !== program.username && user.username !== "client")); console.log(`Keycloak found ${usersWithoutAdmin.length} users`); return usersWithoutAdmin; } catch (error) { console.log(`APS: not able to fetch user: ${error.message}` ); } } async function isContenRepoPresent(tenantId, contentName) { try { const contentRepos = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/integration/alfresco?tenantId=${tenantId}`, 'GET', {}, {}, {}, {}, {}, ['application/json'], ['application/json'] ); return !!contentRepos.data.find(repo => repo.name === contentName); } catch (error) { console.log(`APS: not able to create content: ${error.message}` ); } } async function addContentRepoWithBasic(tenantId, name) { console.log(`Create Content with name ${name} and basic auth`); const body = { alfrescoTenantId: '', authenticationType: "basic", name: name, repositoryUrl: `${program.host}/alfresco`, shareUrl: `${program.host}/share`, // sitesFolder: '', not working on activiti 1.11.1.1 tenantId: tenantId, version: "6.1.1" }; try { const content = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/integration/alfresco`, 'POST', {}, {}, {}, {}, body, ['application/json'], ['application/json'] ); console.log(`Content created!`); return content; } catch (error) { console.log(`APS: not able to create content: ${error.message}` ); } } async function authorizeUserToContentRepo(user) { console.log(`Authorize user ${user.email}`); try { const content = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/integration/alfresco`, 'GET', {}, {}, {}, {}, {}, ['application/json'], ['application/json'] ); console.log(`Found ${content.data && content.data.length} contents`); if (content.data) { for (let i = 0; i < content.data.length; i++) { if (content.data[i].authenticationType === 'basic') { await authorizeUserToContentWithBasic(user.username, content.data[i].id); } } } return; } catch (error) { console.log(`APS: not able to authorize content: ${error.message}` ); } } async function authorizeUserToContentWithBasic(username, contentId) { console.log(`Authorize ${username} on contentId: ${contentId} in basic auth`); try { const body = {username, password: 'password'}; const content = await alfrescoJsApi.oauth2Auth.callCustomApi( `${program.host}/activiti-app/app/rest/integration/alfresco/${contentId}/account`, 'POST', {}, {}, {}, {}, body, ['application/json'], ['application/json'] ); console.log(`User authorized!`); return content; } catch (error) { console.log(`APS: not able to authorize content: ${error.message}` ); } } async function downloadLicenseFile(apsLicensePath) { try { const child_process = require("child_process"); child_process.execSync(` aws s3 cp ${apsLicensePath} ./ `, { cwd: path.resolve(__dirname, `./`) }); console.log(`Aps license file download from S3 bucket`); return true; } catch (error) { console.log(`Not able to download the APS license from S3 bucket` ); return false; } } function sleep(delay) { let start = new Date().getTime(); while (new Date().getTime() < start + delay) ; }