View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.security.setup;
35  
36  import static info.magnolia.jcr.nodebuilder.Ops.*;
37  
38  import info.magnolia.i18nsystem.setup.RemoveHardcodedI18nPropertiesFromDialogsTask;
39  import info.magnolia.i18nsystem.setup.RemoveHardcodedI18nPropertiesFromSubappsTask;
40  import info.magnolia.jcr.nodebuilder.task.ErrorHandling;
41  import info.magnolia.jcr.nodebuilder.task.NodeBuilderTask;
42  import info.magnolia.jcr.util.NodeTypes;
43  import info.magnolia.module.DefaultModuleVersionHandler;
44  import info.magnolia.module.InstallContext;
45  import info.magnolia.module.delta.ArrayDelegateTask;
46  import info.magnolia.module.delta.BootstrapSingleModuleResource;
47  import info.magnolia.module.delta.ChangeAllPropertiesWithCertainValueTask;
48  import info.magnolia.module.delta.ChangeNodeTypeTask;
49  import info.magnolia.module.delta.CheckAndModifyPartOfPropertyValueTask;
50  import info.magnolia.module.delta.CheckAndModifyPropertyValueTask;
51  import info.magnolia.module.delta.CreateNodeTask;
52  import info.magnolia.module.delta.DeltaBuilder;
53  import info.magnolia.module.delta.NewPropertyTask;
54  import info.magnolia.module.delta.NodeExistsDelegateTask;
55  import info.magnolia.module.delta.OrderNodeToFirstPositionTask;
56  import info.magnolia.module.delta.RemoveNodeTask;
57  import info.magnolia.module.delta.RemoveNodesTask;
58  import info.magnolia.module.delta.RemovePropertiesTask;
59  import info.magnolia.module.delta.RemovePropertyTask;
60  import info.magnolia.module.delta.RenameNodeTask;
61  import info.magnolia.module.delta.SetPropertyTask;
62  import info.magnolia.module.delta.Task;
63  import info.magnolia.repository.RepositoryConstants;
64  import info.magnolia.security.app.action.DeleteEmptyFolderActionDefinition;
65  import info.magnolia.security.app.container.GroupDropConstraint;
66  import info.magnolia.security.app.container.RoleDropConstraint;
67  import info.magnolia.security.app.dialog.field.ConditionalReadOnlyTextFieldDefinition;
68  import info.magnolia.security.app.dialog.field.SystemLanguagesFieldDefinition;
69  import info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition;
70  import info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition;
71  import info.magnolia.ui.admincentral.setup.ConvertAclToAppPermissionTask;
72  import info.magnolia.ui.contentapp.setup.DefaultActionToDelegateActionTask;
73  import info.magnolia.ui.contentapp.setup.for5_3.ContentAppMigrationTask;
74  import info.magnolia.ui.framework.action.ConfirmationActionDefinition;
75  import info.magnolia.ui.framework.action.DeleteActionDefinition;
76  import info.magnolia.ui.framework.action.DeleteConfirmationActionDefinition;
77  import info.magnolia.ui.framework.setup.AddIsPublishedRuleToAllDeactivateActionsTask;
78  import info.magnolia.ui.framework.setup.SetWritePermissionForActionsTask;
79  
80  import java.util.ArrayList;
81  import java.util.Arrays;
82  import java.util.HashMap;
83  import java.util.List;
84  
85  /**
86   * Version handler for Security app module.
87   */
88  public class SecurityModuleVersionHandler extends DefaultModuleVersionHandler {
89  
90      private static final String SECURITY_APP_DIALOGS = "/modules/security-app/dialogs";
91  
92      private final Task delegateActionForSecuritySubApps = new ArrayDelegateTask("Use delegate action for Security app", "Use delegate action as default action for Security app - double click on user/role will open edit dialog, double click on folder will expand it.",
93              new DefaultActionToDelegateActionTask("", "", "security", "users", new HashMap<String, String>() {{ put(NodeTypes.Folder.NAME, "expandNodeAction"); put(NodeTypes.User.NAME, "editUser"); }}),
94              new DefaultActionToDelegateActionTask("", "", "security", "groups", new HashMap<String, String>() {{ put(NodeTypes.Folder.NAME, "expandNodeAction"); put(NodeTypes.Group.NAME, "editGroup"); }}),
95              new DefaultActionToDelegateActionTask("", "", "security", "roles", new HashMap<String, String>() {{ put(NodeTypes.Folder.NAME, "expandNodeAction"); put(NodeTypes.Role.NAME, "editRole"); }}));
96  
97      public SecurityModuleVersionHandler() {
98  
99          register(DeltaBuilder.update("5.0", "")
100                 .addTask(new ConvertAclToAppPermissionTask("Convert permissions for 'Security' app", "Convert ACL permissions for old 'Security' menu to new 'security-app' permission",
101                         "/modules/adminInterface/config/menu/security", "/modules/security-app/apps/security", true)));
102 
103         register(DeltaBuilder.update("5.0.1", "")
104 
105                 .addTask(new NodeExistsDelegateTask("Change label of folder creation action to 'Add folder'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/addFolder",
106                         new CheckAndModifyPartOfPropertyValueTask("Change label of folder creation action to 'Add folder'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/addFolder", "label", "New folder", "Add folder")))
107 
108                 .addTask(new NodeExistsDelegateTask("Change label of user creation action to 'Add user'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/addUser",
109                         new CheckAndModifyPartOfPropertyValueTask("Change label of user creation action to 'Add user'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/addUser", "label", "New user", "Add user")))
110 
111                 .addTask(new NodeExistsDelegateTask("Change label of user creation action to 'Add group'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/addGroup",
112                         new CheckAndModifyPartOfPropertyValueTask("Change label of user creation action to 'Add group'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/addGroup", "label", "New group", "Add group")))
113 
114                 .addTask(new NodeExistsDelegateTask("Change label of role creation action to 'Add role'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/addRole",
115                         new CheckAndModifyPartOfPropertyValueTask("Change label of role creation action to 'Add role'", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/addRole", "label", "New role", "Add role")))
116 
117         );
118 
119         register(DeltaBuilder.update("5.1", "")
120                 .addTask(new BootstrapSingleModuleResource("Bootstrap Delete Items action in Security app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/users/actions/deleteItems"))
121                 .addTask(new BootstrapSingleModuleResource("Bootstrap new actionbar section in Security app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/users/actionbar/sections/multiple"))
122                 .addTask(new NodeExistsDelegateTask("Set ruleClass for deleteUser action to IsNotCurrentUserRule", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteUser/availability",
123                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteUser/availability", "ruleClass", "info.magnolia.security.app.action.availability.IsNotCurrentUserRule")))
124                 .addTask(new NodeExistsDelegateTask("Update class for deleteGroup action", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/deleteGroup",
125                         new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/deleteGroup", "class", "info.magnolia.security.app.action.DeleteGroupActionDefinition")))
126                 .addTask(new NodeExistsDelegateTask("Update class for deleteRole action", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/deleteRole",
127                         new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/deleteRole", "class", "info.magnolia.security.app.action.DeleteRoleActionDefinition")))
128                 .addTask(new RemovePropertyTask("Remove label from form field", "Remove label property from the static1 field of the ACL tab of the Role dialog", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/acls/fields/static1", "label"))
129                 .addTask(new RemovePropertyTask("Remove label from form field", "Remove label property from the static1 field of the ACL tab of the Role dialog", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/acls/fields/static2", "label"))
130                 // Remove hardcoded i18n properties, e.g. label, description, etc.
131                 .addTask(new RemoveHardcodedI18nPropertiesFromSubappsTask("security-app")));
132 
133         register(DeltaBuilder.update("5.1.1", "")
134                 .addTask(new BootstrapSingleModuleResource("Bootstrap SystemLanguages field type.", "", "config.modules.security-app.fieldTypes.xml", "/fieldTypes/systemLanguagesField"))
135                 .addTask(new NodeExistsDelegateTask("Update definition class for language field in user dialog.", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user/form/tabs/user/fields/language",
136                         new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user/form/tabs/user/fields/language", "class", SystemLanguagesFieldDefinition.class.getName())))
137                 .addTask(new NodeExistsDelegateTask("Remove now unnecessary options from language field in user dialog.", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user/form/tabs/user/fields/language/options",
138                         new RemoveNodeTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user/form/tabs/user/fields/language/options"))));
139 
140         register(DeltaBuilder.update("5.2", "")
141                 .addTask(new ArrayDelegateTask("Add folder support to groups sub app.", "",
142                         new BootstrapSingleModuleResource("Bootstrap add folder action in groups sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/addFolder"),
143                         new BootstrapSingleModuleResource("Bootstrap delete folder action in groups sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/deleteFolder"),
144                         new BootstrapSingleModuleResource("Bootstrap edit folder action in groups sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/editFolder"),
145                         new BootstrapSingleModuleResource("Bootstrap availability of add group action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/addGroup/availability/nodeTypes"),
146                         new NodeExistsDelegateTask("Remove constraint on add group action on nodes.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/addGroup/availability",
147                                 new RemovePropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/addGroup/availability", "nodes")),
148                         new BootstrapSingleModuleResource("Bootstrap availability for delete group action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/deleteGroup/availability"),
149                         new BootstrapSingleModuleResource("Bootstrap availability for edit group action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actions/editGroup/availability"),
150                         new NodeExistsDelegateTask("Set drop constraint for drag and drop support in groups sub app.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/workbench",
151                                 new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/workbench", "dropConstraintClass", GroupDropConstraint.class.getName())),
152                         new BootstrapSingleModuleResource("Bootstrap action bar section for folders in groups sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/groups/actionbar/sections/folder"),
153                         new NodeExistsDelegateTask("Configure add folder action in actionbar in groups sub app.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actionbar/sections/root/groups/addActions/items",
154                                 new CreateNodeTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actionbar/sections/root/groups/addActions/items", "addFolder", NodeTypes.ContentNode.NAME))
155                         ))
156                 .addTask(new ArrayDelegateTask("Add folder support to roles sub app.", "",
157                         new BootstrapSingleModuleResource("Bootstrap add folder action in roles sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/addFolder"),
158                         new BootstrapSingleModuleResource("Bootstrap delete folder action in roles sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/deleteFolder"),
159                         new BootstrapSingleModuleResource("Bootstrap edit folder action in roles sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/editFolder"),
160                         new BootstrapSingleModuleResource("Bootstrap availability of add role action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/addRole/availability/nodeTypes"),
161                         new NodeExistsDelegateTask("Remove constraint on add role action on nodes.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/addRole/availability",
162                                 new RemovePropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/addRole/availability", "nodes")),
163                         new BootstrapSingleModuleResource("Bootstrap availability for delete role action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/deleteRole/availability"),
164                         new BootstrapSingleModuleResource("Bootstrap availability for edit role action.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actions/editRole/availability"),
165                         new NodeExistsDelegateTask("Set drop constraint for drag and drop support in roles sub app.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/workbench",
166                                 new SetPropertyTask("", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/workbench", "dropConstraintClass", RoleDropConstraint.class.getName())),
167                         new BootstrapSingleModuleResource("Bootstrap action bar section for folders in roles sub app.", "", "config.modules.security-app.apps.security.xml", "/security/subApps/roles/actionbar/sections/folder"),
168                         new NodeExistsDelegateTask("Configure add folder action in actionbar in roles sub app.", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actionbar/sections/root/groups/addActions/items",
169                                 new CreateNodeTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actionbar/sections/root/groups/addActions/items", "addFolder", NodeTypes.ContentNode.NAME))
170                         ))
171                 .addTask(new RemovePropertyTask("Remove hardcoded field", "Remove hardcoded description of acl tab from role dialog: static1", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/acls/fields/static1", "value"))
172                 .addTask(new RemovePropertyTask("Remove hardcoded field", "Remove hardcoded description of acl tab from role dialog: static2", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/acls/fields/static2", "value"))
173                 .addTask(new NodeExistsDelegateTask("Disallow renaming the superuser role.", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/role/fields/jcrName",
174                         new ArrayDelegateTask("Configure role name field to be read only", "",
175                                 new SetPropertyTask("Change the field type", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/role/fields/jcrName", "class", ConditionalReadOnlyTextFieldDefinition.class.getName()),
176                                 new SetPropertyTask("Set the conditional value to superuser", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role/form/tabs/role/fields/jcrName", "conditionalValue", "superuser"))
177                         )));
178         register(DeltaBuilder.update("5.2.1", "")
179                 .addTask(new NewPropertyTask("Add user default action", "Adds edit user default action when a user is selected.", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actionbar", "defaultAction", "editUser"))
180                 .addTask(new NodeExistsDelegateTask("Add conditionalReadOnlyTextField field type", "Add conditionalReadOnlyTextField field type if it is not exist", RepositoryConstants.CONFIG, "/modules/security-app/fieldTypes/conditionalReadOnlyTextField", null,
181                         new BootstrapSingleModuleResource("Bootsrap conditionalReadOnlyTextField field type", "", "config.modules.security-app.fieldTypes.xml", "/fieldTypes/conditionalReadOnlyTextField")))
182         );
183 
184         register(DeltaBuilder.update("5.2.2", "")
185                 .addTask(new RemoveHardcodedI18nPropertiesFromDialogsTask("security-app"))
186                 .addTask(new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteUser/availability", "multiple", "true"))
187                 .addTask(new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteFolder/availability", "multiple", "true"))
188                 .addTask(new NodeExistsDelegateTask("Reconfigure deleteUser action", "Change class to info.magnolia.ui.framework.action.DeleteActionDefinition", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteUser",
189                         new CheckAndModifyPropertyValueTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actions/deleteUser", "class", "info.magnolia.ui.framework.action.DeleteItemActionDefinition", "info.magnolia.ui.framework.action.DeleteActionDefinition")))
190                 .addTask(new DeleteFolderActionReconfigurationTask("groups"))
191                 .addTask(new DeleteFolderActionReconfigurationTask("roles"))
192                 .addTask(new NodeExistsDelegateTask("Reconfigure deleteUser action", "/modules/security-app/apps/security/subApps/users/actions/deleteUser",
193                         new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/deleteUser", "class", "info.magnolia.ui.framework.action.DeleteItemActionDefinition", DeleteActionDefinition.class.getName())))
194                 .addTask(new NodeExistsDelegateTask("Reconfigure deleteFolder action of users subApp", "/modules/security-app/apps/security/subApps/users/actions/deleteFolder",
195                         new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/deleteFolder", "class", "info.magnolia.ui.framework.action.DeleteItemActionDefinition", DeleteActionDefinition.class.getName())))
196                 .addTask(new NodeExistsDelegateTask("Reconfigure deleteItems action of users subApp", "/modules/security-app/apps/security/subApps/users/actions/deleteItems",
197                         new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/deleteItems", "class", "info.magnolia.ui.framework.action.DeleteItemActionDefinition", DeleteActionDefinition.class.getName())))
198                 .addTask(new BootstrapSingleModuleResource("Add confirmDeleteUser action into users subApp", "", "config.modules.security-app.apps.security.xml", "/security/subApps/users/actions/confirmDeleteUser"))
199                 .addTask(new BootstrapSingleModuleResource("Add confirmDeleteFolder action into users subApp", "", "config.modules.security-app.apps.security.xml", "/security/subApps/users/actions/confirmDeleteFolder"))
200                 .addTask(new BootstrapSingleModuleResource("Add confirmDeleteItems action into users subApp", "", "config.modules.security-app.apps.security.xml", "/security/subApps/users/actions/confirmDeleteItems"))
201                 .addTask(new NodeExistsDelegateTask("Reconfigure actionbar of users subApp to use confirmDeleteUser action", "/modules/security-app/apps/security/subApps/users/actionbar/sections/user/groups/deleteActions/items/deleteUser",
202                         new RenameNodeTask("Reconfigure actionbar of users subApp to use confirmDeleteUser action", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actionbar/sections/user/groups/deleteActions/items", "deleteUser", "confirmDeleteUser", false)))
203                 .addTask(new NodeExistsDelegateTask("Reconfigure actionbar of users subApp to use confirmDeleteFolder action", "/modules/security-app/apps/security/subApps/users/actionbar/sections/folder/groups/addActions/items/deleteFolder",
204                         new RenameNodeTask("Reconfigure actionbar of users subApp to use confirmDeleteUser action", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actionbar/sections/folder/groups/addActions/items", "deleteFolder", "confirmDeleteFolder", false)))
205                 .addTask(new NodeExistsDelegateTask("Reconfigure actionbar of users subApp to use confirmDeleteItems action", "/modules/security-app/apps/security/subApps/users/actionbar/sections/multiple/groups/addActions/items/deleteItems",
206                         new RenameNodeTask("Reconfigure actionbar of users subApp to use confirmDeleteUser action", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/actionbar/sections/multiple/groups/addActions/items", "deleteItems", "confirmDeleteItems", false)))
207                 .addTask(new RemovePropertyTask("Remove implementation class property from delete folder action of roles sub-app", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actions/deleteFolder/", "implementationClass"))
208                 .addTask(new RemovePropertyTask("Remove implementation class property from delete folder action of groups sub-app", "", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actions/deleteFolder/", "implementationClass"))
209                 .addTask(new AddDuplicateAndMoveActionsToSecurityAppTask())
210         );
211 
212         register(DeltaBuilder.update("5.2.3", "")
213                 .addTask(new SetWritePermissionForActionsTask("/modules/security-app/apps/security/subApps/users/actions",
214                         new String[] { "editUser", "addUser", "deleteUser", "confirmDeleteUser", "addFolder", "deleteFolder", "confirmDeleteFolder", "editFolder", "deleteItems", "duplicateUser", "moveUser", "confirmDeleteItems" }))
215                 .addTask(new SetWritePermissionForActionsTask("/modules/security-app/apps/security/subApps/groups/actions",
216                         new String[] { "addGroup", "deleteGroup", "confirmDeleteGroup", "editGroup", "addFolder", "deleteFolder", "editFolder", "duplicateGroup", "moveGroup" }))
217                 .addTask(new SetWritePermissionForActionsTask("/modules/security-app/apps/security/subApps/roles/actions",
218                         new String[] { "deleteRole", "confirmDeleteRole", "editRole", "addRole", "addFolder", "deleteFolder", "editFolder", "duplicateRole", "moveRole" }))
219         );
220 
221         register(DeltaBuilder.update("5.2.4", "")
222                         .addTask(new NodeExistsDelegateTask("Reconfigure save action of user dialog", "/modules/security-app/dialogs/user/actions/commit",
223                                 new CheckAndModifyPropertyValueTask("/modules/security-app/dialogs/user/actions/commit", "class", "info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition", "info.magnolia.security.app.dialog.action.SaveUserDialogActionDefinition")))
224         );
225 
226         register(DeltaBuilder.update("5.3", "")
227                 .addTask(new ContentAppMigrationTask("/modules/security-app"))
228                 .addTask(new RemovePropertyTask("", "/modules/security-app/apps/security/subApps/roles/workbench/contentViews/tree", "implementationClass"))
229                 .addTask(new RemovePropertyTask("", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/tree", "implementationClass"))
230                 );
231 
232         register(DeltaBuilder.update("5.3.1", "")
233                 .addTask(new NewPropertyTask("Set security app role dialog to wide", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role","wide", true))
234                 .addTask(new SetWritePermissionForActionsTask("/modules/security-app/apps/security/subApps/users/actions", new String[] { "activate", "deactivate" }))
235         );
236 
237         register(DeltaBuilder.update("5.3.2", "")
238                 .addTask(new ArrayDelegateTask("Reconfigure delete folder actions",
239                         new NodeExistsDelegateTask("Reconfigure delete folder action in Groups", "/modules/security-app/apps/security/subApps/groups/actions/deleteFolder",
240                                 new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/groups/actions/deleteFolder", "class", "info.magnolia.security.app.action.DeleteEmptyFolderActionDefinition", "info.magnolia.security.app.action.DeleteFolderActionDefinition")),
241                         new NodeExistsDelegateTask("Reconfigure delete folder action in Roles", "/modules/security-app/apps/security/subApps/roles/actions/deleteFolder",
242                                 new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/roles/actions/deleteFolder", "class", "info.magnolia.security.app.action.DeleteEmptyFolderActionDefinition", "info.magnolia.security.app.action.DeleteFolderActionDefinition"))
243                         ))
244         );
245 
246         register(DeltaBuilder.update("5.3.4", "")
247                 .addTask(
248                         new NodeExistsDelegateTask("Reconfigure duplicate role action in Groups", "/modules/security-app/apps/security/subApps/roles/actions/duplicateRole",
249                                 new CheckAndModifyPropertyValueTask(
250                                         "/modules/security-app/apps/security/subApps/roles/actions/duplicateRole",
251                                         "class",
252                                         "info.magnolia.ui.framework.action.DuplicateNodeActionDefinition",
253                                         "info.magnolia.security.app.dialog.action.DuplicateRoleActionDefinition")
254                         ))
255                 .addTask(new AddListAndSearchViewTask("users"))
256                 .addTask(new AddListAndSearchViewTask("groups"))
257                 .addTask(new AddListAndSearchViewTask("roles"))
258         );
259         register(DeltaBuilder.update("5.3.6", "")
260                 .addTask(new AddIsPublishedRuleToAllDeactivateActionsTask("","/modules/security-app/apps/"))
261         );
262         register(DeltaBuilder.update("5.3.7", "")
263                 .addTask(
264                         new NodeExistsDelegateTask("Reconfigure duplicate user action in Users", "/modules/security-app/apps/security/subApps/users/actions/duplicateUser",
265                                 new CheckAndModifyPropertyValueTask(
266                                         "/modules/security-app/apps/security/subApps/users/actions/duplicateUser",
267                                         "class",
268                                         "info.magnolia.ui.framework.action.DuplicateNodeActionDefinition",
269                                         "info.magnolia.security.app.dialog.action.DuplicateUserActionDefinition")
270                         ))
271         );
272         register(DeltaBuilder.update("5.3.9", "")
273                 .addTask(
274                         new NodeExistsDelegateTask("Add validator for email field in user tab", "/modules/security-app/dialogs/user/form/tabs/user/fields/email/validators", null,
275                                 new BootstrapSingleModuleResource("", "", "config.modules.security-app.dialogs.user.xml", "/user/form/tabs/user/fields/email/validators"))
276                 )
277         );
278         register(DeltaBuilder.update("5.4.1", "")
279                 .addTask(new NodeExistsDelegateTask("Reconfigure actionbar of groups subApp to use deleteGroup action", "/modules/security-app/apps/security/subApps/groups/actionbar/sections/group/groups/deleteActions/items/confirmDeleteGroup",
280                         new RenameNodeTask("Reconfigure actionbar of groups subApp to use deleteGroup action", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actionbar/sections/group/groups/deleteActions/items", "confirmDeleteGroup", "deleteGroup", false)))
281                 .addTask(new NodeExistsDelegateTask("Reconfigure actionbar of roles subApp to use deleteRole action", "/modules/security-app/apps/security/subApps/roles/actionbar/sections/role/groups/deleteActions/items/confirmDeleteRole",
282                         new RenameNodeTask("Reconfigure actionbar of roles subApp to use deleteRole action", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actionbar/sections/role/groups/deleteActions/items", "confirmDeleteRole", "deleteRole", false)))
283                 .addTask(new ArrayDelegateTask("Reconfigure actionbar to use deleteFolder action",
284                         new NodeExistsDelegateTask("", "/modules/security-app/apps/security/subApps/groups/actionbar/sections/folder/groups/addActions/items/confirmDeleteFolder",
285                                 new RenameNodeTask("", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/groups/actionbar/sections/folder/groups/addActions/items", "confirmDeleteFolder", "deleteFolder", true)),
286                         new NodeExistsDelegateTask("", "/modules/security-app/apps/security/subApps/roles/actionbar/sections/folder/groups/addActions/items/confirmDeleteFolder",
287                                 new RenameNodeTask("", RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/roles/actionbar/sections/folder/groups/addActions/items", "confirmDeleteFolder", "deleteFolder", true))))
288                 .addTask(new ArrayDelegateTask("Remove unused cofirmDelete actions.",
289                         new NodeExistsDelegateTask("Remove confirmDeleteRole action.", "/modules/security-app/apps/security/subApps/roles/actions/confirmDeleteRole",
290                                 new RemoveNodeTask("Remove confirmDeleteRole action.", "/modules/security-app/apps/security/subApps/roles/actions/confirmDeleteRole")),
291                         new NodeExistsDelegateTask("Remove roles/confirmDeleteFolder action.", "/modules/security-app/apps/security/subApps/roles/actions/confirmDeleteFolder",
292                                 new RemoveNodeTask("Remove roles/confirmDeleteFolder action.", "/modules/security-app/apps/security/subApps/roles/actions/confirmDeleteFolder")),
293                         new NodeExistsDelegateTask("Remove confirmDeleteGroup action.", "/modules/security-app/apps/security/subApps/groups/actions/confirmDeleteGroup",
294                                 new RemoveNodeTask("Remove confirmDeleteGroup action.", "/modules/security-app/apps/security/subApps/groups/actions/confirmDeleteGroup")),
295                         new NodeExistsDelegateTask("Remove groups/confirmDeleteFolder action.", "/modules/security-app/apps/security/subApps/groups/actions/confirmDeleteFolder",
296                                 new RemoveNodeTask("Remove groups/confirmDeleteFolder action.", "/modules/security-app/apps/security/subApps/groups/actions/confirmDeleteFolder"))
297                         ))
298         );
299         register(DeltaBuilder.update("5.4.2", "")
300                 .addTask(new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/security-app/apps/security/subApps/users/workbench/contentViews/tree", "sortable", "true"))
301         );
302         register(DeltaBuilder.update("5.4.4", "")
303                 .addTask(new NodeExistsDelegateTask("Reconfigure factory class of System Languages field ", "/modules/security-app/fieldTypes/systemLanguagesField",
304                         new CheckAndModifyPropertyValueTask(
305                                 "/modules/security-app/fieldTypes/systemLanguagesField",
306                                 "factoryClass",
307                                 "info.magnolia.ui.form.field.factory.SelectFieldFactory",
308                                 "info.magnolia.security.app.dialog.field.SystemLanguagesFieldFactory")
309                 ))
310         );
311         register(DeltaBuilder.update("5.4.9", "")
312                 .addTask(delegateActionForSecuritySubApps)
313                 .addTask(new BootstrapSingleModuleResource("Install Security Tools", "", "config.modules.security-app.apps.security.xml", "/security/subApps/tools"))
314         );
315         register(DeltaBuilder.update("5.5", "")
316                 .addTask(new ChangeAllPropertiesWithCertainValueTask(RepositoryConstants.CONFIG, SECURITY_APP_DIALOGS, CancelDialogActionDefinition.class.getName(), info.magnolia.ui.dialog.action.CancelDialogActionDefinition.class.getName()))
317                 .addTask(new ChangeAllPropertiesWithCertainValueTask(RepositoryConstants.CONFIG, SECURITY_APP_DIALOGS, SaveDialogActionDefinition.class.getName(), info.magnolia.ui.dialog.action.SaveDialogActionDefinition.class.getName()))
318         );
319         register(DeltaBuilder.update("5.5.1", "")
320                 .addTask(new ArrayDelegateTask("Fix improper configuration in security app", "Remove obsolete configuration and extend only tree columns in list and search contentViews. Fix nodeType for securityApp list and search contentViews.",
321                         new RemoveNodesTask("Remove improper nodes", RepositoryConstants.CONFIG, Arrays.asList("/modules/security-app/apps/security/subApps/users/actions/addFolder/availability/availability", "/modules/security-app/apps/security/subApps/groups/actions/addFolder/availability/availability", "/modules/security-app/apps/security/subApps/roles/actions/addFolder/availability/availability"), false),
322                         new RemovePropertiesTask("Remove extends property", RepositoryConstants.CONFIG, Arrays.asList("/modules/security-app/apps/security/subApps/users/workbench/contentViews/list/extends", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/search/extends"), false),
323                         new NodeExistsDelegateTask("Fix nodeType and extend only tree columns", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/list",
324                                 new ArrayDelegateTask("",
325                                         new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/users/workbench/contentViews/list", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME),
326                                         new CreateNodeTask("", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/list", "columns", NodeTypes.ContentNode.NAME),
327                                         new NewPropertyTask("", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/list/columns", "extends", "../../tree/columns"))),
328                         new NodeExistsDelegateTask("Fix nodeType and extend only list columns", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/list",
329                                 new ArrayDelegateTask("",
330                                         new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/users/workbench/contentViews/search", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME),
331                                         new CreateNodeTask("", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/search", "columns", NodeTypes.ContentNode.NAME),
332                                         new NewPropertyTask("", "/modules/security-app/apps/security/subApps/users/workbench/contentViews/search/columns", "extends", "../../list/columns"))),
333                         new NodeExistsDelegateTask("Fix nodeType", "/modules/security-app/apps/security/subApps/roles/workbench/contentViews/list",
334                                 new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/roles/workbench/contentViews/list", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME)),
335                         new NodeExistsDelegateTask("Fix nodeType", "/modules/security-app/apps/security/subApps/roles/workbench/contentViews/search",
336                                 new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/roles/workbench/contentViews/search", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME)),
337                         new NodeExistsDelegateTask("Fix nodeType", "/modules/security-app/apps/security/subApps/groups/workbench/contentViews/list",
338                                 new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/groups/workbench/contentViews/list", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME)),
339                         new NodeExistsDelegateTask("Fix nodeType", "/modules/security-app/apps/security/subApps/groups/workbench/contentViews/search",
340                                 new ChangeNodeTypeTask("/modules/security-app/apps/security/subApps/groups/workbench/contentViews/search", RepositoryConstants.CONFIG, NodeTypes.ContentNode.NAME))))
341         );
342 
343         register(DeltaBuilder.update("5.5.4", "")
344                 .addTask(new ArrayDelegateTask("Use DeleteConfirmationAction instead of ConfirmationAction to warn about modified sub-nodes prior deletion.",
345                         new NodeExistsDelegateTask("", "/modules/security-app/apps/security/subApps/users/actions/confirmDeleteUser",
346                             new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/confirmDeleteUser", "class", ConfirmationActionDefinition.class.getName(), DeleteConfirmationActionDefinition.class.getName())),
347                         new NodeExistsDelegateTask("", "/modules/security-app/apps/security/subApps/users/actions/confirmDeleteFolder",
348                                 new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/confirmDeleteFolder", "class", ConfirmationActionDefinition.class.getName(), DeleteConfirmationActionDefinition.class.getName())),
349                         new NodeExistsDelegateTask("", "/modules/security-app/apps/security/subApps/users/actions/confirmDeleteItems",
350                                 new CheckAndModifyPropertyValueTask("/modules/security-app/apps/security/subApps/users/actions/confirmDeleteItems", "class", ConfirmationActionDefinition.class.getName(), DeleteConfirmationActionDefinition.class.getName()))
351 
352                 ))
353         );
354 
355         register(DeltaBuilder.update("5.7", "")
356                 .addTask(new NodeExistsDelegateTask("Set dynamic naming of user dialog in Security app", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user",
357                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/user", "dialogLabelItemProperty", "jcrName")))
358                 .addTask(new NodeExistsDelegateTask("Set dynamic naming of group dialog in Security app", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/group",
359                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/group", "dialogLabelItemProperty", "jcrName")))
360                 .addTask(new NodeExistsDelegateTask("Set dynamic naming of role dialog in Security app", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role",
361                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/security-app/dialogs/role", "dialogLabelItemProperty", "jcrName")))
362         );
363 
364     }
365 
366     @Override
367     protected List<Task> getExtraInstallTasks(InstallContext installContext) {
368         List<Task> tasks = new ArrayList<>();
369         Task orderNodeTo1stPosTask = new OrderNodeToFirstPositionTask("Security app ordering", "Moves the security app before the configuration app", RepositoryConstants.CONFIG, "modules/ui-admincentral/config/appLauncherLayout/groups/manage/apps/security");
370         NodeExistsDelegateTask delegateTask = new NodeExistsDelegateTask("Security app ordering delegate task", "Moves the security app before the configuration app if the node exists", RepositoryConstants.CONFIG, "/modules/ui-admincentral/config/appLauncherLayout/groups/manage/apps/security", orderNodeTo1stPosTask);
371         tasks.add(delegateTask);
372         return tasks;
373     }
374 
375     /**
376      * Task capable of fixing DeleteFolder settings of Security app sub-apps. Precisely it sets definition class to {@link DeleteEmptyFolderActionDefinition} and removes implementationClass property as unnecessary.
377      */
378     private static class DeleteFolderActionReconfigurationTask extends NodeExistsDelegateTask {
379 
380         private final static String actionPathTemplate = "/modules/security-app/apps/security/subApps/%s/actions/deleteFolder/";
381         public static final String taskTitleTemplate = "Reconfigure delete folder action of %s sub-app";
382 
383         public DeleteFolderActionReconfigurationTask(String subAppName) {
384             super(String.format(taskTitleTemplate, subAppName), String.format(actionPathTemplate, subAppName), new ArrayDelegateTask(
385                     "",
386                     new RemovePropertyTask("", "", RepositoryConstants.CONFIG, String.format(actionPathTemplate, subAppName), "implementationClass"),
387                     new SetPropertyTask(RepositoryConstants.CONFIG, String.format(actionPathTemplate, subAppName), "class", DeleteEmptyFolderActionDefinition.class.getName())
388                     ));
389         }
390     }
391 
392     /**
393      * Add a List and Search view to a Security subapp which has only a Tree view.
394      */
395     private static class AddListAndSearchViewTask extends NodeBuilderTask {
396 
397         private final static String workbenchPathTemplate = "/modules/security-app/apps/security/subApps/%s/workbench/";
398         private final static String taskTitleTemplate = "Add List and Search view to %s sub-app, in the Security app.";
399 
400         public AddListAndSearchViewTask(String subAppName) {
401             super(String.format(taskTitleTemplate, subAppName), "", ErrorHandling.logging, RepositoryConstants.CONFIG, String.format(workbenchPathTemplate, subAppName),
402                     getNode("contentViews").then(
403                             addNode("list", NodeTypes.Content.NAME).then(
404                                     addProperty("class", "info.magnolia.ui.workbench.list.ListPresenterDefinition"),
405                                     addProperty("extends", "../tree")),
406                             addNode("search", NodeTypes.Content.NAME).then(
407                                     addProperty("class", "info.magnolia.ui.workbench.search.SearchPresenterDefinition"),
408                                     addProperty("extends", "../list"))
409                             ));
410         }
411     }
412 
413 }