Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save fabian-bouche-liferay/d45a98d53663e7420ad8e7356986b65a to your computer and use it in GitHub Desktop.

Select an option

Save fabian-bouche-liferay/d45a98d53663e7420ad8e7356986b65a to your computer and use it in GitHub Desktop.
Liferay script for Bulk Adding/Removing DLFolder and DLFileEntry Permission Actions for Roles
/**
* Author: mraandrews@gmail.com
* Name: addRemoveFilesAndFolderPermissionsForRole.groovy
*
* Prerequisits: Runs in the Liferay Admin Gui script console
Run with HTML output selected
*
* Description: This script will add and remove the permissions for folders and files in Liferay's DAM (Documents and Media Feature). You can add a folder ID of the folder
* you'd like to start with, and it will recurse the folders and files, changing their permissions. You need ot target the site you want to do this in, and provide
* the roles and permissions for the files and folders.
*
* The script has a DRY_RUN (DRY_RUN) option to run and not make any changes to the permissions, this will provide output of all the files that 'would' be affected
* if DRY_RUN was set to false.
* I have also included a limit (updateOnly) so that you can test on a small number of records, this requires the variable (IS_LIMITED) to be set to true
*
* The script will also provide a summary of the number of folders and files that were processed.
*
* Controlling Configuration:
* DRY_RUN: boolean to determine if the script should actually perform the chagnes to the permissions.
* GLOBAL_SITE_GROUP_ID: long for the Site that the script will target.
* ADD_PERMISSIONS_FOR_ROLE: Map object that contains a structure to determine which roles are targetted, and which permission actions should be
* added for FOLDERs and FILEs.
* REMOVE_PERMISSIONS_FOR_ROLE: Map object that contains a structure to determine which roles are targetted, and which permission actions should be
* removed for FOLDERs and FILEs.
* STARTING_FOLDER: The starting folder if you do not want work on only a subset.
* IMPLEMENT_REMOVE_PERMISSIONS: boolean to determine if the removal of permissions will be run.
* IMPLEMENT_ADD_PERMISSIONS: boolean to determine if the addmin of permissions will be run.
*
* Additonal Configuration:
* tmpDirectory: The temp directory to store the audit file named in [customLogFileName].
* sysSeparator: The path separator for the OS.
* customLogFileName: The name for the custom log file used for audit.
* scriptName: The name of this script.
* tabAmountPx: The HTML styling value for the indent for the console
* updateOnly: int to restrict the number of files updated (used for testing)
*
* NOTE:
* - If the files/folders do not have the permission being removed, the script will not error, it will just continue processing
* - when the script adds permissions, it will overwrite all existing permissions too!
*
* See Also: ResourceConstants - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/model/ResourceConstants.html
* DLFileEntryLocalServiceUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/document/library/kernel/service/DLFileEntryLocalServiceUtil.html
* DLFolderLocalServiceUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/document/library/kernel/service/DLFolderLocalServiceUtil.html
* RoleLocalServiceUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/service/RoleLocalServiceUtil.html
* ResourceActionLocalServiceUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/service/ResourceActionLocalServiceUtil.html#%3Cinit%3E()
* ResourceAction - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/model/ResourceAction.html
* DLFolder - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/document/library/kernel/model/DLFolder.html
* DLFileEntry - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/document/library/kernel/model/DLFileEntry.html
* DLFolderConstants - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/document/library/kernel/model/DLFolderConstants.html
* PortalUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/util/PortalUtil.html
* ResourcePermissionLocalServiceUtil - https://resources.learn.liferay.com/reference/latest/en/dxp/javadocs/portal-kernel/com/liferay/portal/kernel/service/ResourcePermissionLocalServiceUtil.html
*
**/
import com.liferay.portal.kernel.model.ResourceConstants;
import com.liferay.document.library.kernel.service.DLFileEntryLocalServiceUtil;
import com.liferay.document.library.kernel.service.DLFolderLocalServiceUtil;
import com.liferay.portal.kernel.service.RoleLocalServiceUtil;
import com.liferay.portal.kernel.service.ResourceActionLocalServiceUtil;
import com.liferay.portal.kernel.model.ResourceAction;
import com.liferay.document.library.kernel.model.DLFolder;
import com.liferay.document.library.kernel.model.DLFolderConstants;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.service.ResourcePermissionLocalServiceUtil;
import com.liferay.portal.kernel.model.ResourcePermission;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
// **************** Start:Variables ***********************************
// config for allowing the actual changes
DRY_RUN = true;
long GLOBAL_SITE_GROUP_ID = 0; // [Add Site/Group ID]
STARTING_FOLDER = 0 // [Add starting folder ID]
IMPLEMENT_REMOVE_PERMISSIONS = false;
IMPLEMENT_ADD_PERMISSIONS = false;
// for creating a temporary file
String tmpDirectory = "/tmp";
String sysSeparator = System.getProperty("file.separator");
String customLogFileName = "FilesAndFoldersPermissionScriptOutput.txt";
logFileNameAndPath = tmpDirectory+sysSeparator +customLogFileName;
// used for custom logfile output stream
customOutputStream = null;
// Script Name
scriptName = "addRemoveFilesAndFolderPermissionsForRole.groovy";
//
_log = null;
// Print to Console
PRT_CONSOLE = 1;
// Print to Liferay Log
PRT_LOG = 2;
// print to file
PRT_FILE = 4;
DLFOLDER_CLASS_NAME = "com.liferay.document.library.kernel.model.DLFolder";
DLFILEENTRY_CLASS_NAME = "com.liferay.document.library.kernel.model.DLFileEntry";
// Map for Roles; Folder and File; and Permissions actions to REMOVE
REMOVE_PERMISSIONS_FOR_ROLE = [
10117:[ // Liferay Default User Role
"FOLDER":["VIEW", "ADD_DOCUMENT", "ADD_SHORTCUT", "ADD_SUBFOLDER", "SUBSCRIBE"],
"FILE":["VIEW", "DOWNLOAD", "ADD_DISCUSSION"]
],
10114:[ // Liferay Default Guest Role
"FOLDER":["VIEW"],
"FILE":["VIEW"]
]
];
// Map for Roles; Folder and File; and Permissions actions to ADD
ADD_PERMISSIONS_FOR_ROLE = [
10117:[ // Liferay Default User Role
"FOLDER":["VIEW", "ADD_DOCUMENT"],
"FILE":["VIEW"]
]
];
// used for indenting results, when displaying HTML
tabAmountPx = 20;
// for limiting the amount of records (for testing)
IS_LIMITED = false;
updateOnly = 10;
filesUpdated = 0;
filesUpdatedAdd = 0;
foldersUpdated = 0;
foldersUpdatedAdd = 0;
// **************** End:Variables ***********************************
/** **************** Start: Main script flow ************************
*
*
**/
print("Started Script ${scriptName} @ ${new Date().toString()}",PRT_LOG);
print("Started Script ${scriptName} @ ${new Date().toString()}",PRT_FILE);
infoHeader("Permission Changes");
iterateFolderStructure(STARTING_FOLDER, GLOBAL_SITE_GROUP_ID, 0);
print("<br><br>",PRT_CONSOLE);
infoHeader("Change Summary");
fileAddStr = (filesUpdatedAdd>1||filesUpdatedAdd==0) ? "files" : "file";
folderAddStr = (foldersUpdatedAdd>1||foldersUpdatedAdd==0) ? "folders" : "folder";
fileRmvStr = (filesUpdated>1||filesUpdated==0) ? "files" : "file";
folderRmvStr = (foldersUpdated>1||foldersUpdated==0) ? "folders" : "folder";
print("Added permissions for ${filesUpdatedAdd} ${fileAddStr} and ${foldersUpdatedAdd} ${folderAddStr} folders<br>",PRT_CONSOLE);
print("Added permissions for ${filesUpdatedAdd} ${fileAddStr} and ${foldersUpdatedAdd} ${folderAddStr} folders",PRT_LOG);
print("Removed permissions for ${filesUpdated} ${fileRmvStr} and ${foldersUpdated} ${folderAddStr} folders<br>",PRT_CONSOLE);
print("Removed permissions for ${filesUpdated} ${fileRmvStr} and ${foldersUpdated} ${folderRmvStr} folders",PRT_LOG);
print("Script ${scriptName} Complete @ ${new Date().toString()}",PRT_LOG);
print("Script ${scriptName} Complete @ ${new Date().toString()}",PRT_FILE);
infoFooter();
infoFooter();
tidyUp();
// **************** End: Main script flow *************************
def iterateFolderStructure(folderId, groupId, indent) {
indent++;
folders = DLFolderLocalServiceUtil.getFolders(groupId, folderId);
for(currentFolder in folders) {
if(currentFolder.isHidden()==false) {
lftP = indent*tabAmountPx;
fileCount = DLFileEntryLocalServiceUtil.getFileEntriesCount(groupId,currentFolder.getFolderId());
print("<div style='padding-left:${lftP}px'> ${currentFolder.getName()} (Count of files: ${fileCount})</div>",PRT_CONSOLE);
print("${currentFolder.getName()} (Count of files: ${fileCount})",PRT_FILE);
// remove permissions for Role/Folder
if(IMPLEMENT_REMOVE_PERMISSIONS) {
removeFolderPermissions(currentFolder,REMOVE_PERMISSIONS_FOR_ROLE, DLFOLDER_CLASS_NAME,indent);
}
if(IMPLEMENT_ADD_PERMISSIONS) {
addFolderPermissions(currentFolder,ADD_PERMISSIONS_FOR_ROLE, DLFOLDER_CLASS_NAME,indent);
}
if(fileCount>0) {
files = DLFileEntryLocalServiceUtil.getFileEntries(groupId,currentFolder.getFolderId());
if(IMPLEMENT_REMOVE_PERMISSIONS) {
removePermissions(files , REMOVE_PERMISSIONS_FOR_ROLE, DLFILEENTRY_CLASS_NAME, indent);
}
if(IMPLEMENT_ADD_PERMISSIONS) {
addPermissions(files , ADD_PERMISSIONS_FOR_ROLE , DLFILEENTRY_CLASS_NAME, indent);
}
}
//find child folders
if(DLFolderLocalServiceUtil.getFoldersCount(groupId, currentFolder.getFolderId())>0) {
iterateFolderStructure(currentFolder.getFolderId(), groupId,indent);
}
}
// Implements file update limiting for testing
if(IS_LIMITED&&(filesUpdated>=updateOnly||filesUpdatedAdd>=updateOnly)) {
return
}
}
indent--
}
/**
* Function: removeFolderPermissions()
* Description: Removes the permissions for the folder
* Parameters: folder - The Liferay model DLFolder Object instance to remove the permissions on.
* rolesAndPermissions - A Map of the role, and permission actions to remove
* className - The class name of the object we're removing the permissions from (Can't rely on the [instance].class.getName()
* method for this, as it returns the impl, not the interface)
* indent - This is an index to show how far down the tree we've gone, but I don't like including this in this method, I will remove it
* eventually.
**/
def removeFolderPermissions(DLFolder folder, rolesAndPermissions, className, indent) {
lftP = indent*tabAmountPx;
rolesAndPermissions.each { roleId, typ->
if(!DRY_RUN) {
print("<div style='padding-left:${lftP}px'> removing permissions on folder: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}Removing permissions on folder: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
typ.FOLDER.each { ptr ->
ResourcePermissionLocalServiceUtil.removeResourcePermission(PortalUtil.getDefaultCompanyId(), className, ResourceConstants.SCOPE_INDIVIDUAL, ""+folder.getFolderId(), roleId, ptr);
}
} else {
print("<div style='padding-left:${lftP}px'> [DRY RUN: folder permissions will not be removed]: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}[DRY RUN: folder permissions will not be removed]: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
}
}
foldersUpdated++;
}
/**
* Function: removePermissions()
* Description: Iterates over a list of files and removes the permissions for them based on the parameters provided
* Parameters: listOfFiles - A list of Liferay model DLFileEntry Object instances to remove the permissions on.
* rolesAndPermissions - A Map of the role, and permission actions to remove
* className - The class name of the object we're removing the permissions from (Can't rely on the [instance].class.getName()
* method for this, as it returns the impl, not the interface)
* indent - This is an index to show how far down the tree we've gone, but I don't like including this in this method, I will remove it
* eventually.
**/
def removePermissions(listOfFiles, rolesAndPermissions , className, indent) {
indent++
listOfFiles.each { file ->
lftP = indent*tabAmountPx;
rolesAndPermissions.each { roleId, typ->
if(IS_LIMITED&&filesUpdated>=updateOnly) {
return
}
if(!DRY_RUN) {
print("<div style='padding-left:${lftP}px'> removing permissions on file: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}Removing permissions on file: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
typ.FILE.each { ptr ->
ResourcePermissionLocalServiceUtil.removeResourcePermission(PortalUtil.getDefaultCompanyId(), className, ResourceConstants.SCOPE_INDIVIDUAL, ""+file.getFileEntryId(), roleId, ptr);
}
} else {
print("<div style='padding-left:${lftP}px'> [DRY RUN: file permissions will not be removed] file name: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}[DRY RUN: file permissions will not be removed] file name: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
}
filesUpdated++;
}
}
indent--;
}
/**
* Function: addFolderPermissions()
* Description: Adds the permissions for the folder
* Parameters: folder - Liferays DLFolder Object instance
* rolesAndPermissions - A Map of the role, and permission actions to add
* className - The class name of the object we're adding the permissions from (Can't rely on the [instance].class.getName()
* method for this, as it returns the impl, not the interface)
* indent - This is an index to show how far down the tree we've gone, but I don't like including this in this method; I will remove it
* eventually.
**/
def addFolderPermissions(DLFolder folder, rolesAndPermissions, className, indent) {
lftP = indent*tabAmountPx;
rolesAndPermissions.each { roleId, typ->
if(!DRY_RUN) {
print("<div style='padding-left:${lftP}px'> adding permissions on folder: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}Adding permissions on folder: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
ResourcePermissionLocalServiceUtil.setResourcePermissions(PortalUtil.getDefaultCompanyId(), className, ResourceConstants.SCOPE_INDIVIDUAL, ""+folder.getFolderId(), (Long)roleId, typ.FOLDER as String[]);
} else {
print("<div style='padding-left:${lftP}px'> [DRY RUN: folder permissions will not be added]: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}[DRY RUN: folder permissions will not be added]: ${folder.getName()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
}
}
foldersUpdatedAdd++;
}
/**
* Function: addPermissions()
* Description: Iterates over a list of files and adds the permissions for them based on the parameters provided
* Parameters: listOfFiles - A list of Liferay model DLFileEntry Object instances to add the permissions on.
* rolesAndPermissions - A Map of the role, and permission actions to add
* className - The class name of the object we're removing the permissions from (Can't rely on the [instance].class.getName()
* method for this, as it returns the impl, not the interface)
* indent - This is an index to show how far down the tree we've gone, but I don't like including this in this method; I will remove it
* eventually.
**/
def addPermissions(listOfFiles, rolesAndPermissions , className, indent) {
indent++
listOfFiles.each { file ->
lftP = indent*tabAmountPx;
rolesAndPermissions.each { roleId, typ->
if(IS_LIMITED && filesUpdatedAdd>=updateOnly) {
return;
}
if(!DRY_RUN) {
print("<div style='padding-left:${lftP}px'> Adding permissions on file: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}Adding permissions on file: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
ResourcePermissionLocalServiceUtil.setResourcePermissions(PortalUtil.getDefaultCompanyId(), className, ResourceConstants.SCOPE_INDIVIDUAL, ""+file.getFileEntryId(), (Long)roleId, typ.FILE as String[]);
} else {
print("<div style='padding-left:${lftP}px'> [DRY RUN: file permissions will not be added] file name: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]</div>",PRT_CONSOLE);
print("${tab(indent)}[DRY RUN: file permissions will not be added] file name: ${file.getTitle()}, [ROLE: ${RoleLocalServiceUtil.getRole(roleId).getName()}, Permission Actions: ${typ.FILE}]",PRT_FILE);
}
filesUpdatedAdd++;
}
}
indent--;
}
// Used for decoding the actionId's in bitwise notation. Not used for the implementation, but was for the testing.
def separateBinaryNumbers(int actionIds) {
actionIdStr = Integer.toBinaryString(actionIds)
responseActionsList = []
for(i=actionIdStr.length()-1;i>-1;i--) {
if(actionIdStr[i]>0) {
responseActionsList.add(allObjectAccessPermissions[i].getActionId() )
}
}
return responseActionsList
}
// Prints output to the appropriate place
def print(String data, toWhere) {
if (toWhere==PRT_CONSOLE) {
out.println(data)
} else if (toWhere==PRT_LOG){
if(_log==null) {
_log = LogFactoryUtil.getLog(scriptName);
}
_log.info(data);
} else if (toWhere==PRT_FILE){
if(customOutputStream==null) {
customOutputStream = new FileWriter(logFileNameAndPath);
customOutputStream.write("Output File Created: "+new Date().toString()+"\n");
}
customOutputStream.write(data+"\n");
}
}
// header for making results pretty, works in conjunction with infoFooter
def infoHeader(title) {
print("""
<div class="portlet-msg-info"><h1>$title</h1>
""")
}
// footer for making results pretty, works in conjunction with infoHeader
def infoFooter() {
print("""
</div>
""")
}
def tidyUp() {
customOutputStream.close();
}
def tab(int num) {
tabs = "";
for(i=0;i<=num;i++) {
tabs+="\t";
}
return tabs;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment