UNPKG

@dxatscale/sfprofiles

Version:
490 lines (444 loc) 22.9 kB
import { Connection } from '@salesforce/core'; import { registry } from '@salesforce/source-deploy-retrieve'; import MetadataFiles from '@impl/metadata/metadataFiles'; import SFPLogger, {LoggerLevel } from '@dxatscale/sfp-logger'; import { Sfpowerkit } from '@utils/sfpowerkit'; import UserPermissionBuilder from '@impl/metadata/builder/userPermissionBuilder'; import MetadataRetriever from '@impl/metadata/retriever/metadataRetriever'; import ProfileRetriever from '@impl/metadata/retriever/profileRetriever'; import Profile, { ProfileFieldLevelSecurity } from '@impl/metadata/schema'; export default class ProfileComponentReconciler { //rivate profileRetriever; public constructor(private conn: Connection, private isSourceOnly: boolean) {} public async reconcileProfileComponents(profileObj: Profile, profileName: string): Promise<Profile> { SFPLogger.log(`Reconciling App: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileApp(profileObj); SFPLogger.log(`Reconciling Classes: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileClasses(profileObj); SFPLogger.log(`Reconciling Fields: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileFields(profileObj); SFPLogger.log(`Reconciling Objects: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileObjects(profileObj); SFPLogger.log(`Reconciling Pages: ${profileName}`, LoggerLevel.DEBUG); await this.reconcilePages(profileObj); SFPLogger.log(`Reconciling Layouts: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileLayouts(profileObj); SFPLogger.log(`Reconciling Record Types: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileRecordTypes(profileObj); SFPLogger.log(`Reconciling Tabs: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileTabs(profileObj); SFPLogger.log(`Reconciling ExternalDataSources: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileExternalDataSource(profileObj); SFPLogger.log(`Reconciling CustomPermissions: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileCustomPermission(profileObj); SFPLogger.log(`Reconciling CustomMetadata: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileCustomMetadata(profileObj); SFPLogger.log(`Reconciling CustomSettings: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileCustomSettings(profileObj); SFPLogger.log(`Reconciling Flow: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileFlow(profileObj); SFPLogger.log(`Reconciling Login Flows: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileLoginFlow(profileObj); SFPLogger.log(`Reconciling User Licenses: ${profileName}`, LoggerLevel.DEBUG); await this.cleanupUserLicenses(profileObj); SFPLogger.log(`Reconciling User Permissions: ${profileName}`, LoggerLevel.DEBUG); await this.reconcileUserPermissions(profileObj); SFPLogger.log(`All Components for ${profileName} reconciled`, LoggerLevel.DEBUG); return profileObj; } private async removeUserPermissionNotAvailableInOrg(profileObj: Profile, supportedPermissions: string[]) { if (profileObj.userPermissions !== undefined && profileObj.userPermissions.length > 0) { //Remove permission that are not present in the target org profileObj.userPermissions = profileObj.userPermissions.filter((permission) => { let supported = supportedPermissions.includes(permission.name); return supported; }); } } private async removePermissionsBasedOnProjectConfig(profileObj: Profile) { let pluginConfig = await Sfpowerkit.getConfig(); let ignorePermissions = pluginConfig.ignoredPermissions || []; if (profileObj.userPermissions !== undefined && profileObj.userPermissions.length > 0) { profileObj.userPermissions = profileObj.userPermissions.filter((permission) => { let supported = !ignorePermissions.includes(permission.name); return supported; }); } } private removeUnsupportedUserPermissions(profileObj: Profile) { let profileRetriever: ProfileRetriever; //if sourceonly mode load profileRetriever if (MetadataFiles.sourceOnly) { profileRetriever = new ProfileRetriever(null); } else { profileRetriever = new ProfileRetriever(this.conn); } let unsupportedLicencePermissions = profileRetriever.getUnsupportedLicencePermissions(profileObj.userLicense); if (profileObj.userPermissions != null && profileObj.userPermissions.length > 0) { profileObj.userPermissions = profileObj.userPermissions.filter((permission) => { let supported = !unsupportedLicencePermissions.includes(permission.name); return supported; }); } } private async cleanupUserLicenses(profileObj: Profile) { if (!this.isSourceOnly) { //Manage licences let userLicenseRetriever = new MetadataRetriever(this.conn, 'UserLicense'); const isSupportedLicence = await userLicenseRetriever.isComponentExistsInTheOrg(profileObj.userLicense); if (!isSupportedLicence) { delete profileObj.userLicense; } } } private async reconcileApp(profileObj: Profile): Promise<void> { let customApplications = new MetadataRetriever(this.conn, registry.types.customapplication.name); if (profileObj.applicationVisibilities !== undefined) { let validArray = []; for (let i = 0; i < profileObj.applicationVisibilities.length; i++) { let cmpObj = profileObj.applicationVisibilities[i]; let exist = await customApplications.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.application); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Application Visiblitilties reduced from ${profileObj.applicationVisibilities.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.applicationVisibilities = validArray; } } private async reconcileClasses(profileObj: Profile): Promise<void> { let apexClasses = new MetadataRetriever(this.conn, registry.types.apexclass.name); if (profileObj.classAccesses !== undefined) { if (!Array.isArray(profileObj.classAccesses)) { profileObj.classAccesses = [profileObj.classAccesses]; } let validArray = []; for (let i = 0; i < profileObj.classAccesses.length; i++) { let cmpObj = profileObj.classAccesses[i]; let exists = await apexClasses.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.apexClass); if (exists) { validArray.push(cmpObj); } } SFPLogger.log( `Class Access reduced from ${profileObj.classAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.classAccesses = validArray; } } private async reconcileFields(profileObj: Profile): Promise<void> { if (profileObj.fieldPermissions) { if (!Array.isArray(profileObj.fieldPermissions)) { profileObj.fieldPermissions = [profileObj.fieldPermissions]; } let validArray: ProfileFieldLevelSecurity[] = []; for (let i = 0; i < profileObj.fieldPermissions.length; i++) { let fieldRetriever = new MetadataRetriever( this.conn, registry.types.customobject.children.types.customfield.name ); let cmpObj = profileObj.fieldPermissions[i]; let parent = cmpObj.field.split('.')[0]; let exists = await fieldRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.field, parent); if (exists) { validArray.push(cmpObj); } } SFPLogger.log( `Fields Level Permissions reduced from ${profileObj.fieldPermissions.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.fieldPermissions = validArray; } } private async reconcileLayouts(profileObj: Profile): Promise<void> { let layoutRetreiver = new MetadataRetriever(this.conn, registry.types.layout.name); let recordTypeRetriever = new MetadataRetriever( this.conn, registry.types.customobject.children.types.recordtype.name ); if (profileObj.layoutAssignments !== undefined) { let validArray = []; for (let count = 0; count < profileObj.layoutAssignments.length; count++) { let cmpObj = profileObj.layoutAssignments[count]; let exist = (await layoutRetreiver.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.layout)) && (cmpObj.recordType == null || cmpObj.recordType == undefined || (await recordTypeRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.recordType))); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Layout Assignnments reduced from ${profileObj.layoutAssignments.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.layoutAssignments = validArray; } } private async reconcileObjects(profileObj: Profile): Promise<void> { let objectPermissionRetriever = new MetadataRetriever(this.conn, 'ObjectPermissions'); let objectRetriever = new MetadataRetriever(this.conn, registry.types.customobject.name); if (profileObj.objectPermissions !== undefined) { if (!Array.isArray(profileObj.objectPermissions)) { profileObj.objectPermissions = [profileObj.objectPermissions]; } let validArray = []; for (let i = 0; i < profileObj.objectPermissions.length; i++) { let cmpObj = profileObj.objectPermissions[i]; //Check Object exist in Source Directory let exist = await objectRetriever.isComponentExistsInProjectDirectory(cmpObj.object); if (!exist) exist = await objectPermissionRetriever.isComponentExistsInTheOrg(cmpObj.object); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Object Permissions reduced from ${profileObj.objectPermissions.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.objectPermissions = validArray; } } private async reconcileCustomMetadata(profileObj: Profile): Promise<void> { let objectRetriever = new MetadataRetriever(this.conn, registry.types.customobject.name); if (profileObj.customMetadataTypeAccesses !== undefined) { if (!Array.isArray(profileObj.customMetadataTypeAccesses)) { profileObj.customMetadataTypeAccesses = [profileObj.customMetadataTypeAccesses]; } let validArray = []; for (let i = 0; i < profileObj.customMetadataTypeAccesses.length; i++) { let cmpCM = profileObj.customMetadataTypeAccesses[i]; let exist = await objectRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpCM.name); if (exist) { validArray.push(cmpCM); } } SFPLogger.log( `CustomMetadata Access reduced from ${profileObj.customMetadataTypeAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.customMetadataTypeAccesses = validArray; } } private async reconcileCustomSettings(profileObj: Profile): Promise<void> { let objectRetriever = new MetadataRetriever(this.conn, registry.types.customobject.name); if (profileObj.customSettingAccesses !== undefined) { if (!Array.isArray(profileObj.customSettingAccesses)) { profileObj.customSettingAccesses = [profileObj.customSettingAccesses]; } let validArray = []; for (let i = 0; i < profileObj.customSettingAccesses.length; i++) { let cmpCS = profileObj.customSettingAccesses[i]; let exist = await objectRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpCS.name); if (exist) { validArray.push(cmpCS); } } SFPLogger.log( `CustomSettings Access reduced from ${profileObj.customSettingAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.customSettingAccesses = validArray; } } private async reconcileExternalDataSource(profileObj: Profile): Promise<void> { let externalDataSourceRetriever = new MetadataRetriever(this.conn, registry.types.externaldatasource.name); if (profileObj.externalDataSourceAccesses !== undefined) { if (!Array.isArray(profileObj.externalDataSourceAccesses)) { profileObj.externalDataSourceAccesses = [profileObj.externalDataSourceAccesses]; } let validArray = []; for (let i = 0; i < profileObj.externalDataSourceAccesses.length; i++) { let dts = profileObj.externalDataSourceAccesses[i]; let exist = await externalDataSourceRetriever.isComponentExistsInProjectDirectoryOrInOrg( dts.externalDataSource ); if (exist) { validArray.push(dts); } } SFPLogger.log( `ExternalDataSource Access reduced from ${profileObj.externalDataSourceAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.externalDataSourceAccesses = validArray; } } private async reconcileFlow(profileObj: Profile): Promise<void> { let flowRetreiver = new MetadataRetriever(this.conn, registry.types.flow.name); if (profileObj.flowAccesses !== undefined) { if (!Array.isArray(profileObj.flowAccesses)) { profileObj.flowAccesses = [profileObj.flowAccesses]; } let validArray = []; for (let i = 0; i < profileObj.flowAccesses.length; i++) { let flow = profileObj.flowAccesses[i]; let exist = await flowRetreiver.isComponentExistsInProjectDirectoryOrInOrg(flow.flow); if (exist) { validArray.push(flow); } } SFPLogger.log( `Flow Access reduced from ${profileObj.flowAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.flowAccesses = validArray; } } private async reconcileLoginFlow(profileObj: Profile): Promise<void> { let apexPageRetriver = new MetadataRetriever(this.conn, registry.types.apexpage.name); let flowRetreiver = new MetadataRetriever(this.conn, registry.types.flow.name); if (profileObj.loginFlows !== undefined) { if (!Array.isArray(profileObj.loginFlows)) { profileObj.loginFlows = [profileObj.loginFlows]; } let validArray = []; for (let i = 0; i < profileObj.loginFlows.length; i++) { let loginFlow = profileObj.loginFlows[i]; if (loginFlow.flow !== undefined) { let exist = await flowRetreiver.isComponentExistsInProjectDirectoryOrInOrg(loginFlow.flow); if (exist) { validArray.push(loginFlow); } } else if (loginFlow.vfFlowPage !== undefined) { let exist = await apexPageRetriver.isComponentExistsInProjectDirectoryOrInOrg(loginFlow.vfFlowPage); if (exist) { validArray.push(loginFlow); } } } SFPLogger.log( `LoginFlows reduced from ${profileObj.loginFlows.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.loginFlows = validArray; } } private async reconcileCustomPermission(profileObj: Profile): Promise<void> { let customPermissionsRetriever = new MetadataRetriever(this.conn, registry.types.custompermission.name); if (profileObj.customPermissions !== undefined) { if (!Array.isArray(profileObj.customPermissions)) { profileObj.customPermissions = [profileObj.customPermissions]; } let validArray = []; for (let i = 0; i < profileObj.customPermissions.length; i++) { let customPermission = profileObj.customPermissions[i]; let exist = await customPermissionsRetriever.isComponentExistsInProjectDirectoryOrInOrg( customPermission.name ); if (exist) { validArray.push(customPermission); } } SFPLogger.log( `CustomPermission reduced from ${profileObj.customPermissions.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.customPermissions = validArray; } } private async reconcilePages(profileObj: Profile): Promise<void> { let apexPageRetriver = new MetadataRetriever(this.conn, registry.types.apexpage.name); if (profileObj.pageAccesses !== undefined) { if (!Array.isArray(profileObj.pageAccesses)) { profileObj.pageAccesses = [profileObj.pageAccesses]; } let validArray = []; for (let i = 0; i < profileObj.pageAccesses.length; i++) { let cmpObj = profileObj.pageAccesses[i]; let exist = await apexPageRetriver.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.apexPage); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Page Access Permissions reduced from ${profileObj.pageAccesses.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.pageAccesses = validArray; } } private async reconcileRecordTypes(profileObj: Profile): Promise<void> { let recordTypeRetriever = new MetadataRetriever( this.conn, registry.types.customobject.children.types.recordtype.name ); if (profileObj.recordTypeVisibilities !== undefined) { if (!Array.isArray(profileObj.recordTypeVisibilities)) { profileObj.recordTypeVisibilities = [profileObj.recordTypeVisibilities]; } let validArray = []; for (let i = 0; i < profileObj.recordTypeVisibilities.length; i++) { let cmpObj = profileObj.recordTypeVisibilities[i]; let exist = await recordTypeRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.recordType); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Record Type Visibilities reduced from ${profileObj.recordTypeVisibilities.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.recordTypeVisibilities = validArray; } } private async reconcileTabs(profileObj: Profile): Promise<void> { let tabRetriever = new MetadataRetriever(this.conn, registry.types.customtab.name); if (profileObj.tabVisibilities !== undefined) { if (!Array.isArray(profileObj.tabVisibilities)) { profileObj.tabVisibilities = [profileObj.tabVisibilities]; } let validArray = []; for (let i = 0; i < profileObj.tabVisibilities.length; i++) { let cmpObj = profileObj.tabVisibilities[i]; let exist = await tabRetriever.isComponentExistsInProjectDirectoryOrInOrg(cmpObj.tab); if (exist) { validArray.push(cmpObj); } } SFPLogger.log( `Tab Visibilities reduced from ${profileObj.tabVisibilities.length} to ${validArray.length}`, LoggerLevel.DEBUG ); profileObj.tabVisibilities = validArray; } } private async fetchPermissions() { let permissionRetriever = new MetadataRetriever(this.conn, 'UserPermissions'); let permissionSets = await permissionRetriever.getComponents(); let supportedPermissions = permissionSets.map((elem) => { return elem.fullName; }); return supportedPermissions; } private async reconcileUserPermissions(profileObj: Profile) { if (profileObj.userPermissions == null || profileObj.userPermissions.length === 0) { return; } //Delete all user Permissions if the profile is standard one let isCustom = profileObj.custom; if (!isCustom) { delete profileObj.userPermissions; return; } //Remove unsupported userPermission this.removeUnsupportedUserPermissions(profileObj); SFPLogger.log('Removed Unsupported User Pemrmisions ', LoggerLevel.TRACE); let userPermissionBuilder: UserPermissionBuilder = new UserPermissionBuilder(); //IS sourceonly, use ignorePermission set in sfdxProject.json file if (MetadataFiles.sourceOnly) { await this.removePermissionsBasedOnProjectConfig(profileObj); await userPermissionBuilder.handlePermissionDependency(profileObj, []); } else { let supportedPermissions = await this.fetchPermissions(); await this.removeUserPermissionNotAvailableInOrg(profileObj, supportedPermissions); await userPermissionBuilder.handlePermissionDependency(profileObj, supportedPermissions); } } }