Skip to content

Instantly share code, notes, and snippets.

@boxfoot
Created December 23, 2014 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boxfoot/79350b7ccb561dc731a9 to your computer and use it in GitHub Desktop.
Save boxfoot/79350b7ccb561dc731a9 to your computer and use it in GitHub Desktop.
use `gulp cleanProfiles` to remove all negative (false) permissions from Salesforce permission files.
/* By Benj Kamm, bkamm@healthleadsusa.org */
// Look for the value of the first text node within the current node.
// Returns 'false' if not found, otherwise the value of the first text node in the subnode.
function getXMLNodeValue(el, key) {
var matches = el.getElementsByTagName(key);
if (!matches.length) {
return 'false';
}
return matches[0].childNodes[0].nodeValue;
}
// Look for all permissions of type <tagName>, return as an array
function getXMLTags(doc, tagName) {
return Array.prototype.slice.call(doc.getElementsByTagName(tagName));
}
module.exports = {
getXMLNodeValue: getXMLNodeValue,
getXMLTags: getXMLTags
};
/* By Benj Kamm, bkamm@healthleadsusa.org */
var gulp = require('gulp'),
profileCleaner = require('./profileCleaner.js');
gulp.task('cleanProfiles', function() {
var SRC_URLS = [
'src/profiles/*.profile',
'src/permissionsets/*.permissionset'
];
return gulp.src(SRC_URLS, {base: './'})
.pipe(profileCleaner())
.pipe(gulp.dest('./'));
});
// through2 is a thin wrapper around node transform streams
var through = require('through2');
var DOMParser = require('xmldom').DOMParser;
var pd = require('pretty-data').pd;
var gutil = require('gulp-util');
var getPermissionValue = require('./common').getXMLNodeValue;
var getXMLTags = require('./common').getXMLTags;
// Removes all empty permission nodes from metadata xml files for Profile and PermissionSet
function removeEmptyPermissions(content) {
content = content.toString();
var doc = new DOMParser().parseFromString(content);
// Remove empty <applicationVisibilities>
// - Profiles must have visible=false and default=false.
// - PermisisionSets must have visible=false (no default tag)
getXMLTags(doc, 'applicationVisibilities').forEach(function(el) {
if (getPermissionValue(el, 'visible') === 'false' && getPermissionValue(el, 'default') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <classAccesses> - enabled=false
getXMLTags(doc, 'classAccesses').forEach(function(el) {
if (getPermissionValue(el, 'enabled') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <fieldPermissions> - editable=false and readable=false.
getXMLTags(doc, 'fieldPermissions').forEach(function(el) {
if (getPermissionValue(el, 'editable') === 'false' && getPermissionValue(el, 'readable') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <objectPermissions> - only if no access at all
getXMLTags(doc, 'objectPermissions').forEach(function(el) {
if (getPermissionValue(el, 'allowCreate') === 'false' &&
getPermissionValue(el, 'allowDelete') === 'false' &&
getPermissionValue(el, 'allowEdit') === 'false' &&
getPermissionValue(el, 'allowRead') === 'false' &&
getPermissionValue(el, 'modifyAllRecords') === 'false' &&
getPermissionValue(el, 'viewAllRecords') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <pageAccesses> - enabled=false.
getXMLTags(doc, 'pageAccesses').forEach(function(el) {
if (getPermissionValue(el, 'enabled') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <recordTypeVisibilities> - visible=false.
getXMLTags(doc, 'recordTypeVisibilities').forEach(function(el) {
if (getPermissionValue(el, 'visible') === 'false') {
el.parentNode.removeChild(el);
}
});
// Remove empty <tabSettings> - visibility=None.
getXMLTags(doc, 'tabSettings').forEach(function(el) {
if (getPermissionValue(el, 'visibility') === 'None') {
el.parentNode.removeChild(el);
}
});
// remove blank lines
return pd.xml(doc.toString());
/*
var stream = through();
stream.write(prefixText);
return stream;
*/
}
// Plugin level function(dealing with files)
function profileCleaner() {
var filesProcessed = 0;
// Creating a stream through which each file will pass
var stream = through.obj(function(file, enc, callback) {
filesProcessed += 1;
if (file.isNull()) {
// Do nothing if no contents
}
if (file.isBuffer()) {
file.contents = new Buffer(removeEmptyPermissions(file.contents));
}
if (file.isStream()) {
console.log('stream');
//file.contents = through().write(removeEmptyPermissions(file.contents));
}
this.push(file);
return callback();
}, function(callback) {
gutil.log(gutil.colors.cyan('cleanProfiles')+':', 'Processed',
gutil.colors.magenta(filesProcessed), 'files');
callback();
});
// returning the file stream
return stream;
};
// Exporting the plugin main function
module.exports = profileCleaner;
@boxfoot
Copy link
Author

boxfoot commented Dec 23, 2014

I pulled this out of a larger code base and didn't run to make sure it holds together so could be missing a stray dependency. Comment if you have any problems!

@nilvon9wo
Copy link

Cheers for sharing this.
I haven't worked with gulp much and that was many years ago.

I'd really appreciate if you could also include some information about environmental dependencies (e.g. what version of node and gulp we need) and how to execute this script from a command line, including how to specify where the salesforce source files live.

Also, please include whether your instructions are suitable for both ANT and SFDX users...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment