Forked from mraandrews/addRemoveFilesAndFolderPermissionsForRole.groovy
Created
June 27, 2025 20:07
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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