UNPKG

@dxatscale/sfprofiles

Version:
326 lines (292 loc) 12.8 kB
/* eslint-disable @typescript-eslint/no-array-constructor */ import Profile, { ProfileObjectPermissions, ProfileUserPermission } from '../schema'; import { Connection } from 'jsforce'; import { MetadataInfo } from '../metadataInfo'; import * as _ from 'lodash'; import MetadataRetriever from './metadataRetriever'; import QueryExecutor from '@utils/queryExecutor'; import MetadataOperation from '@utils/metadataOperation'; const unsuportedObjects = ['PersonAccount']; /** * * Used to track Unsupported Userpermission per Licence * Update this list when Salesforce change supported permission per licence */ const userLicenceMap = [ { name: 'Guest User License', unsupportedPermissions: ['PasswordNeverExpires'], }, ]; export default class ProfileRetriever { static supportedMetadataTypes = [ 'ApexClass', 'CustomApplication', 'CustomObject', 'CustomField', 'Layout', 'ApexPage', 'CustomTab', 'RecordType', 'SystemPermissions', ]; public constructor(private conn: Connection) {} public async loadProfiles(profileNames: string[]): Promise<MetadataInfo[]> { let profilePermissions = await this.fetchPermissionsWithValue(profileNames); let profiles = (await this.conn.metadata.read('Profile', profileNames)) as any; if (Array.isArray(profiles)) { for (let i = 0; i < profiles.length; i++) { await this.handlePermissions(profiles[i], profilePermissions); profiles[i] = await this.completeObjects(profiles[i], false); } return profiles; } else if (profiles !== null) { await this.handlePermissions(profiles, profilePermissions); profiles = await this.completeObjects(profiles, false); return [profiles]; } else { return []; } } public async handlePermissions(profileObj: Profile, permissions): Promise<Profile> { await this.handleViewAllDataPermission(profileObj); await this.handleInstallPackagingPermission(profileObj); this.handleQueryAllFilesPermission(profileObj); //Check if the permission QueryAllFiles is true and give read access to objects profileObj = await this.completeUserPermissions(profileObj, permissions); return profileObj; } private async completeUserPermissions(profileObj: Profile, profilePermissions): Promise<Profile> { let supportedPermissions = await this.fetchPermissions(); // remove unsupported userLicence let unsupportedLicencePermissions = this.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; }); } let notRetrievedPermissions = supportedPermissions.filter((permission) => { let found = null; if (profileObj.userPermissions != null && profileObj.userPermissions.length > 0) { found = profileObj.userPermissions.find((element) => { return element.name === permission; }); } return found === null || found === undefined; }); let isCustom = '' + profileObj.custom; if (isCustom == 'false') { //Remove System permission for standard profile as Salesforce does not support edition on those profile delete profileObj.userPermissions; } else { for (let i = 0; i < notRetrievedPermissions.length; i++) { let profileName = decodeURIComponent(profileObj.fullName); let profilePermission = profilePermissions.find((record) => { return record.Name == profileName; }); let permissionField = 'Permissions' + notRetrievedPermissions[i]; let permissionValue = false; if (profilePermission) { permissionValue = profilePermission[permissionField]; if (permissionValue == undefined) { permissionValue = false; } } let newPermission: ProfileUserPermission = { enabled: permissionValue, name: notRetrievedPermissions[i], }; if (profileObj.userPermissions === undefined) { profileObj.userPermissions = new Array(); } if (!Array.isArray(profileObj.userPermissions)) { profileObj.userPermissions = [profileObj.userPermissions]; } profileObj.userPermissions.push(newPermission); } } if (profileObj.userPermissions !== undefined) { profileObj.userPermissions.sort((perm1, perm2) => { let order = 0; if (perm1.name < perm2.name) { order = -1; } else if (perm1.name > perm2.name) { order = 1; } return order; }); } return profileObj; } private hasPermission(profileObj: Profile, permissionName: string): boolean { let found = false; if ( profileObj.userPermissions !== null && profileObj.userPermissions !== undefined && profileObj.userPermissions.length > 0 ) { for (let i = 0; i < profileObj.userPermissions.length; i++) { let element = profileObj.userPermissions[i]; if (element.name === permissionName) { found = element.enabled; break; } } } return found; } private async completeObjects(profileObj: Profile, access = true): Promise<Profile> { let objPerm = ProfileRetriever.filterObjects(profileObj); if (objPerm === undefined) { objPerm = new Array(); } else if (!Array.isArray(objPerm)) { objPerm = [objPerm]; } let objectPermissionsRetriever = new MetadataRetriever(this.conn, 'ObjectPermissions'); let objectPermissions = await objectPermissionsRetriever.getComponents(); objectPermissions.forEach((obj) => { let name = obj.fullName; if (unsuportedObjects.includes(name)) { return; } let objectIsPresent = false; for (let i = 0; i < objPerm.length; i++) { if (objPerm[i].object === name) { objectIsPresent = true; break; } else { objectIsPresent = false; } } if (objectIsPresent === false) { let objToInsert = ProfileRetriever.buildObjPermArray(name, access); if (profileObj.objectPermissions === undefined) { profileObj.objectPermissions = new Array(); } else if (!Array.isArray(profileObj.objectPermissions)) { profileObj.objectPermissions = [profileObj.objectPermissions]; } profileObj.objectPermissions.push(objToInsert); } }); if (profileObj.objectPermissions !== undefined) { profileObj.objectPermissions.sort((obj1, obj2) => { let order = 0; if (obj1.object < obj2.object) { order = -1; } else if (obj1.object > obj2.object) { order = 1; } return order; }); } return profileObj; } private static buildObjPermArray(objectName: string, access = true): ProfileObjectPermissions { let newObjPerm = { allowCreate: access, allowDelete: access, allowEdit: access, allowRead: access, modifyAllRecords: access, object: objectName, viewAllRecords: access, }; return newObjPerm; } private static filterObjects(profileObj: Profile): ProfileObjectPermissions[] { return profileObj.objectPermissions; } private async enablePermission(profileObj: Profile, permissionName: string) { let found = false; if (profileObj.userPermissions !== null && profileObj.userPermissions.length > 0) { for (let i = 0; i < profileObj.userPermissions.length; i++) { let element = profileObj.userPermissions[i]; if (element.name === permissionName) { element.enabled = true; found = true; break; } } } if (!found) { if (profileObj.userPermissions === null || profileObj.userPermissions === undefined) { profileObj.userPermissions = []; } let supportedPermissions = await this.fetchPermissions(); if (supportedPermissions.includes(permissionName)) { let permission = { name: permissionName, enabled: true, } as ProfileUserPermission; profileObj.userPermissions.push(permission); } } } private handleQueryAllFilesPermission(profileObj: Profile) { let isQueryAllFilesPermission = this.hasPermission(profileObj, 'QueryAllFiles'); if ( isQueryAllFilesPermission && profileObj.objectPermissions !== undefined && profileObj.objectPermissions.length > 0 ) { for (let i = 0; i < profileObj.objectPermissions.length; i++) { profileObj.objectPermissions[i].allowRead = true; profileObj.objectPermissions[i].viewAllRecords = true; } } } private async handleViewAllDataPermission(profileObj: Profile): Promise<void> { let isViewAllData = this.hasPermission(profileObj, 'ViewAllData'); if (isViewAllData && profileObj.objectPermissions !== undefined && profileObj.objectPermissions.length > 0) { for (let i = 0; i < profileObj.objectPermissions.length; i++) { profileObj.objectPermissions[i].allowRead = true; profileObj.objectPermissions[i].viewAllRecords = true; } } if (isViewAllData) { await this.enablePermission(profileObj, 'ViewPlatformEvents'); await this.enablePermission(profileObj, 'ViewDataLeakageEvents'); } } private async handleInstallPackagingPermission(profileObj: Profile): Promise<void> { let hasPermission = this.hasPermission(profileObj, 'InstallPackaging'); if (hasPermission) { await this.enablePermission(profileObj, 'ViewDataLeakageEvents'); } } public getUnsupportedLicencePermissions(licence: string): any { if (!_.isNil(licence)) { for (let i = 0; i < userLicenceMap.length; i++) { if (userLicenceMap[i].name.trim().toLocaleLowerCase() === licence.trim().toLocaleLowerCase()) { return userLicenceMap[i].unsupportedPermissions; } } } return []; } 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 fetchPermissionsWithValue(profileNames: string[]) { let describeResult = await new MetadataOperation(this.conn).describeAnObject('Profile'); let permissions = []; describeResult.fields.forEach((field) => { let fieldName = field['name'] as string; if (fieldName.startsWith('Permissions')) { permissions.push(fieldName.trim()); } }); let permissionStr = permissions.join(', '); let query = `SELECT Name, ${permissionStr} FROM Profile WHERE Name IN ('${profileNames.join("','")}')`; query = decodeURIComponent(query); let executor = new QueryExecutor(this.conn); let profiles = await executor.executeQuery(query, false); return profiles; } }