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.pages.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.AbstractCondition;
46  import info.magnolia.module.delta.ArrayDelegateTask;
47  import info.magnolia.module.delta.BootstrapConditionally;
48  import info.magnolia.module.delta.BootstrapSingleModuleResource;
49  import info.magnolia.module.delta.CheckAndModifyPartOfPropertyValueTask;
50  import info.magnolia.module.delta.CheckAndModifyPropertyValueTask;
51  import info.magnolia.module.delta.Condition;
52  import info.magnolia.module.delta.DeltaBuilder;
53  import info.magnolia.module.delta.HasPropertyDelegateTask;
54  import info.magnolia.module.delta.IsModuleInstalledOrRegistered;
55  import info.magnolia.module.delta.NewPropertyTask;
56  import info.magnolia.module.delta.NodeExistsDelegateTask;
57  import info.magnolia.module.delta.OrderNodeAfterTask;
58  import info.magnolia.module.delta.OrderNodeToFirstPositionTask;
59  import info.magnolia.module.delta.PartialBootstrapTask;
60  import info.magnolia.module.delta.RemoveNodeTask;
61  import info.magnolia.module.delta.RemovePropertiesTask;
62  import info.magnolia.module.delta.RemovePropertyTask;
63  import info.magnolia.module.delta.RenameNodeTask;
64  import info.magnolia.module.delta.RenameNodesTask;
65  import info.magnolia.module.delta.SetPropertyTask;
66  import info.magnolia.module.delta.Task;
67  import info.magnolia.module.delta.ValueOfPropertyDelegateTask;
68  import info.magnolia.module.delta.WarnTask;
69  import info.magnolia.pages.app.PagesContentApp;
70  import info.magnolia.pages.app.action.CreatePageAction;
71  import info.magnolia.pages.app.action.OpenCreatePageDialogActionDefinition;
72  import info.magnolia.pages.app.action.PreviewPreviousVersionActionDefinition;
73  import info.magnolia.pages.app.action.RestorePreviousVersionActionDefinition;
74  import info.magnolia.pages.app.editor.PagesEditorSubAppDescriptor;
75  import info.magnolia.pages.app.editor.PagesJcrContentConnector;
76  import info.magnolia.pages.app.editor.availability.IsDuplicatableRule;
77  import info.magnolia.pages.app.editor.extension.definition.ExtensionDefinition;
78  import info.magnolia.repository.RepositoryConstants;
79  import info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition;
80  import info.magnolia.ui.admincentral.setup.ConvertAclToAppPermissionTask;
81  import info.magnolia.ui.contentapp.ConfiguredContentAppDescriptor;
82  import info.magnolia.ui.contentapp.ContentApp;
83  import info.magnolia.ui.contentapp.availability.IsNotVersionedDetailLocationRule;
84  import info.magnolia.ui.contentapp.browser.action.ShowVersionsActionDefinition;
85  import info.magnolia.ui.contentapp.contenttypes.ConfiguredContentTypeAppDescriptor;
86  import info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor;
87  import info.magnolia.ui.contentapp.setup.for5_3.ContentAppMigrationTask;
88  import info.magnolia.ui.framework.action.ConfirmationActionDefinition;
89  import info.magnolia.ui.framework.action.DeleteConfirmationActionDefinition;
90  import info.magnolia.ui.framework.action.ExportActionDefinition;
91  import info.magnolia.ui.framework.action.OpenCreateDialogActionDefinition;
92  import info.magnolia.ui.framework.action.OpenExportDialogActionDefinition;
93  import info.magnolia.ui.framework.setup.AddIsPublishedRuleToAllDeactivateActionsTask;
94  import info.magnolia.ui.framework.setup.SetWritePermissionForActionsTask;
95  
96  import java.util.ArrayList;
97  import java.util.Arrays;
98  import java.util.List;
99  
100 
101 /**
102  * Version handler for the pages app module.
103  */
104 public class PagesModuleVersionHandler extends DefaultModuleVersionHandler {
105 
106     public static final String PAGES_APP_ACTIONS = "/modules/pages/apps/pages/subApps/browser/actions/";
107     String contentConnectorPath = "/modules/pages/apps/pages/subApps/detail/contentConnector";
108 
109     public PagesModuleVersionHandler() {
110         super();
111 
112         register(DeltaBuilder.update("5.0", "Configuration update for Magnolia 5.0")
113                 .addTask(new IsModuleInstalledOrRegistered("", "", "adminInterface",
114                         new BootstrapConditionally("Bootstrap activation commands", "Bootstraps the default activation and deletion commands which no longer reside under adminInterface.", "config.modules.pages.commands.xml")))
115                 .addTask(new ConvertAclToAppPermissionTask("Convert permissions for Pages app", "Convert ACL permissions for old 'Website' menu to new 'pages-app' permission", "/modules/adminInterface/config/menu/website", "/modules/pages/apps/pages", true)));
116 
117         register(DeltaBuilder.update("5.0.1", "")
118                 .addTask(new NodeExistsDelegateTask("Remove dialog links Node", "Remove dialog definition in pages/dialogs/links", RepositoryConstants.CONFIG, "/modules/pages/dialogs/link",
119                         new RemoveNodeTask("Remove dialog links Node", "Remove dialog definition in pages/dialogs/links", RepositoryConstants.CONFIG, "/modules/pages/dialogs/link")))
120                 .addTask(new NodeExistsDelegateTask("Add title to CreatePage dialog", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/createPage/form",
121                         new NewPropertyTask("Add title to CreatePage dialog", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/createPage/form", "label", "pages.dialog.add_page"))));
122 
123         register(DeltaBuilder.update("5.0.2", "")
124                 // new action for confirmation
125                 .addTask(new PartialBootstrapTask("Add new confirmation action definition", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/confirmDeletion"))
126 
127                 .addTask(new NodeExistsDelegateTask("Remove action availability from delete action", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete/availability",
128                         new RemoveNodeTask("", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete/availability")))
129                 .addTask(new HasPropertyDelegateTask("Remove label for delete action", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "label",
130                         new RemovePropertyTask("", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "label")))
131                 .addTask(new HasPropertyDelegateTask("Remove icon for delete action", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "icon",
132                         new RemovePropertyTask("", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "icon")))
133 
134                 // update actionbar for confirmation
135                 .addTask(new NodeExistsDelegateTask("Update actionbar configuration", "Rename action mapping to new confirmation action", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actionbar",
136                         new RenameNodesTask("Rename action bar items", "Rename delete to confirmDeletion", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actionbar", "delete", "confirmDeletion", NodeTypes.ContentNode.NAME))));
137 
138         register(DeltaBuilder.update("5.1", "")
139                 .addTask(new NodeExistsDelegateTask("", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "confirmDeletion",
140                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "confirmDeletion/availability", "multiple", true)))
141 
142                 // add show versions action
143                 // if module diff is installed, this task will create a second node showVersions
144                 // we'll handle the renaming of the correct node in module diff
145                 .addTask(new NodeBuilderTask("Create showVersions action", "", ErrorHandling.logging, RepositoryConstants.CONFIG, PAGES_APP_ACTIONS,
146                         addNode("showVersions", NodeTypes.ContentNode.NAME).then(
147                                 addProperty("class", ShowVersionsActionDefinition.class.getName()),
148                                 addProperty("icon", "icon-show-versions"),
149                                 addNode("availability", NodeTypes.ContentNode.NAME).then(
150                                         addProperty("ruleClass", "info.magnolia.ui.api.availability.HasVersionsRule")
151                                 )
152                         )
153                 ))
154                 // bootstrap versionActions to action bar if it doesn't exists already
155                 .addTask(new NodeExistsDelegateTask("Bootstrap actionbar section group for versionActions", "", RepositoryConstants.CONFIG, "/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions", null,
156                         new PartialBootstrapTask("", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions")
157                 ))
158 
159                 // Remove hardcoded i18n properties, e.g. label, description, etc.
160                 .addTask(new RemoveHardcodedI18nPropertiesFromSubappsTask("pages"))
161 
162                 // cleanup pages commands
163                 .addTask(new NodeExistsDelegateTask("remove the activate command chain from pages app", "", RepositoryConstants.CONFIG, "/modules/pages/commands/website/activate",
164                         new RemoveNodeTask("", "", RepositoryConstants.CONFIG, "/modules/pages/commands/website/activate")))
165                 .addTask(new NodeExistsDelegateTask("remove the deactivate command chain from pages app", "", RepositoryConstants.CONFIG, "/modules/pages/commands/website/deactivate",
166                         new RemoveNodeTask("", "", RepositoryConstants.CONFIG, "/modules/pages/commands/website/deactivate")))
167 
168                 .addTask(new PartialBootstrapTask("Bootstrap new activate commands to website catalog.", "", "/mgnl-bootstrap/pages/config.modules.pages.commands.xml", "/commands/website/activate"))
169                 .addTask(new PartialBootstrapTask("Bootstrap new deactivate commands to website catalog.", "", "/mgnl-bootstrap/pages/config.modules.pages.commands.xml", "/commands/website/deactivate"))
170 
171                 // Add availability rules to detail view actions
172                 .addTask(new NodeBuilderTask("Add availability rule to edit action", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/edit",
173                         addNode("availability", NodeTypes.ContentNode.NAME).then(
174                                 addProperty("ruleClass", IsNotVersionedDetailLocationRule.class.getName())
175                         )
176                 ))
177                 .addTask(new NodeBuilderTask("Add availability rule to activate action", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/activate",
178                         addNode("availability", NodeTypes.ContentNode.NAME).then(
179                                 addProperty("ruleClass", IsNotVersionedDetailLocationRule.class.getName())
180                         )
181                 ))
182                 .addTask(new NodeBuilderTask("Add availability rule to deactivate action", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/deactivate",
183                         addNode("availability", NodeTypes.ContentNode.NAME).then(
184                                 addProperty("ruleClass", IsNotVersionedDetailLocationRule.class.getName())
185                         )
186                 ))
187 
188                 .addTask(new PartialBootstrapTask("Bootstrap move action in Pages app", "",
189                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/move"))
190                 .addTask(new PartialBootstrapTask("Bootstrap move action to Pages app actionbar", "Adds action move to folder/editingActions section in actionbar.",
191                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actionbar/sections/pageActions/groups/editingActions/items/move")));
192 
193         register(DeltaBuilder.update("5.1.1", "")
194                 .addTask(new NodeExistsDelegateTask("Add root availability to import", "Add root availability to import action in Pages app", RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "import/availability",
195                         new NewPropertyTask("Add root availability to import", "Add root availability to import action in Pages app", RepositoryConstants.CONFIG,
196                                 PAGES_APP_ACTIONS + "import/availability", "root", true))));
197 
198         register(DeltaBuilder.update("5.2.2", "")
199                 .addTask(new RemoveHardcodedI18nPropertiesFromDialogsTask("pages"))
200                 .addTask(new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/pages/apps/pages", "class", ConfiguredContentAppDescriptor.class.getName()))
201                 .addTask(new SetPropertyTask(RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "import/availability", "root", "true"))
202                 .addTask(new PartialBootstrapTask("Bootstrap restore version action", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "pages/subApps/browser/actions/restoreVersion"))
203                 .addTask(new NodeExistsDelegateTask("Bootstrap restore version action to actionbar", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions/items",
204                         new ArrayDelegateTask("",
205                                 new PartialBootstrapTask("", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions/items/restoreVersion"),
206                                 new NodeExistsDelegateTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions/items/showVersions",
207                                         new OrderNodeAfterTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actionbar/sections/pageActions/groups/versionActions/items/restoreVersion", "showVersions"))))));
208 
209         register(DeltaBuilder.update("5.2.3", "")
210                 .addTask(new SetWritePermissionForActionsTask(PAGES_APP_ACTIONS,
211                         "add", "confirmDeletion", "edit", "editPageName", "editTemplate", "restorePreviousVersion", "import", "move", "restoreVersion"))
212                 .addTask(new SetWritePermissionForActionsTask("/modules/pages/apps/pages/subApps/detail/actions", "edit")));
213 
214         register(DeltaBuilder.update("5.2.5", "")
215                 .addTask(new IsModuleInstalledOrRegistered("Configure recursive activation and deletion as asynchronous", "scheduler", new ArrayDelegateTask("",
216                         new NodeExistsDelegateTask("Configure recursive activation as asynchronous", PAGES_APP_ACTIONS + "activateRecursive",
217                                 new SetPropertyTask(RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "activateRecursive", "asynchronous", "true")),
218                         new NodeExistsDelegateTask("Configure deletion as asynchronous", PAGES_APP_ACTIONS + "delete",
219                                 new SetPropertyTask(RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "asynchronous", "true"))
220                 ))));
221 
222         register(DeltaBuilder.update("5.3", "")
223                 .addTask(new ArrayDelegateTask("Make dialogs light", "Turns edit page and edit template dialogs into light dialogs.",
224                         new NodeExistsDelegateTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/editPage",
225                                 new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/editPage", "modalityLevel", "light")),
226                         new NodeExistsDelegateTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/createPage",
227                                 new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/createPage", "modalityLevel", "strong")),
228                         new NodeExistsDelegateTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/editTemplate",
229                                 new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/dialogs/editTemplate", "modalityLevel", "light"))))
230                 .addTask(new ContentAppMigrationTask("/modules/pages", RestorePreviousVersionActionDefinition.class, PreviewPreviousVersionActionDefinition.class)));
231 
232         register(DeltaBuilder.update("5.3.1", "")
233                 .addTask(new SetWritePermissionForActionsTask(PAGES_APP_ACTIONS, "activate", "activateRecursive", "deactivate", "activateDeletion")));
234 
235         register(DeltaBuilder.update("5.3.3", "")
236                 .addTask(new UpdatePageEditorActionAvailability()));
237 
238         register(DeltaBuilder.update("5.3.4", "")
239                 .addTask(new NodeExistsDelegateTask("Make action available on multiple nodes", "Makes restorePreviousVersion action available on multiple nodes.",
240                         RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/restorePreviousVersion/availability",
241                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/restorePreviousVersion/availability", "multiple", true)))
242                 .addTask(new NodeExistsDelegateTask("Configure restorePreviousVersion", "Makes restorePreviousVersion action act only on mgnl:page node type.",
243                         RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/restorePreviousVersion",
244                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/restorePreviousVersion", "parentNodeTypeOnly", true)))
245 
246                 .addTask(new NodeExistsDelegateTask("Bootstrap actionbar availability.", "/modules/pages/apps/pages/subApps/detail/actionbar/sections",
247                         new ArrayDelegateTask("Bootstrap actionbar availability for pageActions and pagePreviewActions.",
248                                 new PartialBootstrapTask("Bootstrap pagePreviewActions actionbar section availability rule.",
249                                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml",
250                                         "/pages/subApps/detail/actionbar/sections/pagePreviewActions/availability/rules/isPageElement"),
251                                 new PartialBootstrapTask("Bootstrap pagePreviewActions actionbar section availability rule.",
252                                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml",
253                                         "/pages/subApps/detail/actionbar/sections/pagePreviewActions/availability/rules/isNotDeleted"),
254                                 new PartialBootstrapTask("Bootstrap pageActions actionbar section availability rule.",
255                                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml",
256                                         "/pages/subApps/detail/actionbar/sections/pageActions/availability/rules/isPageElement"),
257                                 new PartialBootstrapTask("Bootstrap pageActions actionbar section availability rule.",
258                                         "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml",
259                                         "/pages/subApps/detail/actionbar/sections/pageActions/availability/rules/isNotDeleted"))))
260         );
261 
262         register(DeltaBuilder.update("5.3.6", "")
263                 .addTask(new AddIsPublishedRuleToAllDeactivateActionsTask("", "/modules/pages/apps/"))
264                 .addTask(new ArrayDelegateTask("Bootstrap IsPublishableRule",
265                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/activate/availability/rules/IsPublishableRule"),
266                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/activateRecursive/availability/rules/IsPublishableRule"))));
267         register(DeltaBuilder.update("5.3.8", "")
268                 .addTask(new NodeExistsDelegateTask("Bootstrap newComponent dialog", "newComponent dialog is no longer hard-coded within CreateComponentAction, bootstrap it if it doesn't exist already.",
269                         RepositoryConstants.CONFIG, "/modules/pages/dialogs/newComponent",
270                         null, new BootstrapSingleModuleResource("", "", "dialogs/config.modules.pages.dialogs.newComponent.xml")))
271         );
272         register(DeltaBuilder.update("5.3.9", "")
273                 .addTask(new NodeExistsDelegateTask("Configure multiple", "Allow select multiple items for activateDeletion action.",
274                         RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/activateDeletion/availability",
275                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/activateDeletion/availability", "multiple", "true"))
276                 )
277         );
278         register(DeltaBuilder.update("5.4", "")
279                 .addTask(new NodeExistsDelegateTask("Bootstrap page editor extensions.", "/modules/pages/apps/pages/subApps/detail", new ArrayDelegateTask("",
280                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages/subApps/detail", "class", DetailSubAppDescriptor.class.getName(), PagesEditorSubAppDescriptor.class.getName()),
281                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages", "appClass", ContentApp.class.getName(), PagesContentApp.class.getName()),
282                         new PartialBootstrapTask("Bootstrap pageBar extensions", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/pageBar"),
283                         new PartialBootstrapTask("Bootstrap statusBar extensions", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/statusBar"))))
284                 .addTask(new NodeExistsDelegateTask("Add IsPageEditableRule to apps/pages/subApps/detail/actions/editProperties", "/modules/pages/apps/pages/subApps/detail/actions/editProperties",
285                         new ArrayDelegateTask("", "",
286                                 new NodeExistsDelegateTask("", "/modules/pages/apps/pages/subApps/detail/actions/editProperties/availability", null,
287                                         new NodeBuilderTask("", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/editProperties",
288                                                 addNode("availability", NodeTypes.ContentNode.NAME))),
289                                 new NodeExistsDelegateTask("", "/modules/pages/apps/pages/subApps/detail/actions/editProperties/availability/rules", null,
290                                         new NodeBuilderTask("", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/editProperties/availability",
291                                                 addNode("rules", NodeTypes.ContentNode.NAME))),
292                                 new NodeExistsDelegateTask("", "/modules/pages/apps/pages/subApps/detail/actions/editProperties/availability/rules/isPageEditable", null,
293                                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/editProperties/availability/rules/isPageEditable")))))
294         );
295         register(DeltaBuilder.update("5.4.1", "")
296                 .addTask(new NodeExistsDelegateTask("Configure multiple", "Allow select multiple items for activateDeletion action.",
297                         RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/activateDeletion/availability",
298                         new NewPropertyTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/actions/activateDeletion/availability", "multiple", "true")))
299                 .addTask(new RemovePropertiesTask("Remove obsolete or superfluous access roles", RepositoryConstants.CONFIG, Arrays.asList(
300                         PAGES_APP_ACTIONS + "activate/availability/access/roles/demo-publisher",
301                         PAGES_APP_ACTIONS + "activate/availability/access/roles/superuser",
302                         PAGES_APP_ACTIONS + "deactivate/availability/access/roles/demo-publisher",
303                         PAGES_APP_ACTIONS + "deactivate/availability/access/roles/superuser",
304                         PAGES_APP_ACTIONS + "activateRecursive/availability/access/roles/demo-publisher",
305                         PAGES_APP_ACTIONS + "activateRecursive/availability/access/roles/superuser",
306                         PAGES_APP_ACTIONS + "activateDeletion/availability/access/roles/demo-publisher",
307                         PAGES_APP_ACTIONS + "activateDeletion/availability/access/roles/superuser"), false))
308         );
309         register(DeltaBuilder.update("5.4.4", "")
310                 .addTask(new PartialBootstrapTask("Configure duplicate component action", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/duplicateComponent"))
311                 .addTask(new PartialBootstrapTask("Add duplicate component action to action bar", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/duplicateComponent"))
312                 .addTask(new OrderNodeAfterTask("Move duplicateComponent action after editComponent", "/modules/pages/apps/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/duplicateComponent", "editComponent"))
313         );
314         register(DeltaBuilder.update("5.4.5", "")
315                 .addTask(new NodeExistsDelegateTask("Add IsDuplicatableRule to duplicateComponent action.", "/modules/pages/apps/pages/subApps/detail/actions/duplicateComponent",
316                         new ArrayDelegateTask("", "",
317                                 new NodeExistsDelegateTask("", "/modules/pages/apps/pages/subApps/detail/actions/duplicateComponent",
318                                         new NodeBuilderTask("", "", ErrorHandling.logging, RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/detail/actions/duplicateComponent",
319                                                 getOrAddNode("availability", NodeTypes.ContentNode.NAME)
320                                                         .then(getOrAddNode("rules", NodeTypes.ContentNode.NAME)
321                                                                 .then(getOrAddNode("IsDuplicatableRule", NodeTypes.ContentNode.NAME)
322                                                                         .then(addProperty("implementationClass", IsDuplicatableRule.class.getName())))))))))
323                 .addTask(new NodeExistsDelegateTask("Allow to choose position of new component", "/modules/pages/dialogs/newComponent/form/tabs/components/fields",
324                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/dialogs/config.modules.pages.dialogs.newComponent.xml", "newComponent/form/tabs/components/fields/mgnl-position"))
325                 )
326         );
327         register(DeltaBuilder.update("5.4.6", "")
328                 .addTask(new ArrayDelegateTask("Configure add page action to open edit page dialog after page creation",
329                         new NodeExistsDelegateTask("", "/modules/pages/dialogs/createPage/actions/commit",
330                                 new CheckAndModifyPropertyValueTask("/modules/pages/dialogs/createPage/actions/commit", "class", SaveDialogActionDefinition.class.getName(), CreatePageAction.Definition.class.getName()),
331                                 new PartialBootstrapTask("", "/mgnl-bootstrap/pages/dialogs/config.modules.pages.dialogs.createPage.xml", "createPage/actions/commit")
332                         ),
333                         new PartialBootstrapTask("", "", "/mgnl-bootstrap/pages/dialogs/config.modules.pages.dialogs.createPage.xml", "createPage/form/tabs/tabPage/fields"),
334                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages/subApps/browser/actions/add", "class", OpenCreateDialogActionDefinition.class.getName(), OpenCreatePageDialogActionDefinition.class.getName())
335                 )));
336         register(DeltaBuilder.update("5.4.8", "")
337                 .addTask(new HasPropertyDelegateTask("Remove untitled property from contentViews", "/modules/pages/apps/pages/subApps/browser/workbench/contentViews", "untitled",
338                         new RemovePropertyTask("", "/modules/pages/apps/pages/subApps/browser/workbench/contentViews", "untitled")))
339                 .addTask(new NodeExistsDelegateTask("", "/modules/pages/apps/pages/subApps/detail/pageBar/extensions",
340                         new ArrayDelegateTask("Configure nativePagePreviewLink extension and order at the first position",
341                                 new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "pages/subApps/detail/pageBar/extensions/nativePagePreviewLink"),
342                                 new OrderNodeToFirstPositionTask("", "modules/pages/apps/pages/subApps/detail/pageBar/extensions/nativePagePreviewLink"),
343                                 new ValueOfPropertyDelegateTask("", "/modules/pages/apps/pages/subApps/detail/pageBar/extensions/languageSelector", "class", ExtensionDefinition.class.getName(), false,
344                                         new RemovePropertyTask("", "/modules/pages/apps/pages/subApps/detail/pageBar/extensions/languageSelector", "class")))))
345         );
346         register(DeltaBuilder.update("5.5", "")
347                 .addTask(new NodeExistsDelegateTask("", contentConnectorPath,
348                         new HasPropertyDelegateTask("Install pages detail content connector.", "contentConnectorPath", "implementationClass",
349                                 new ArrayDelegateTask("Overriding existing, custom content connector",
350                                         new WarnTask("", "You have a custom content connector installed in the pages detail sub-app. You will have to adapt it to extend the new one."),
351                                         new SetPropertyTask(RepositoryConstants.CONFIG, contentConnectorPath, "implementationClass", PagesJcrContentConnector.class.getName())),
352                                 new NewPropertyTask("", contentConnectorPath, "implementationClass", PagesJcrContentConnector.class.getName()))))
353                 .addTask(new ArrayDelegateTask("Add copy and paste functionality into the pages editor.", "Add ability to copy and paste the components in pages editor.",
354                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/copyComponent"),
355                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/copyComponents"),
356                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/pasteComponents"),
357                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/copyComponent"),
358                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/pasteComponents"),
359                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/areaActions/groups/editingActions/items/copyComponents"),
360                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/areaActions/groups/editingActions/items/pasteComponents"),
361                         new OrderNodeAfterTask("", "/modules/pages/apps/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/pasteComponents", "copyComponent"),
362                         new OrderNodeAfterTask("", "/modules/pages/apps/pages/subApps/detail/actionbar/sections/areaActions/groups/editingActions/items/pasteComponents", "copyComponents")))
363                 .addTask(new ArrayDelegateTask("Add copy and paste functionality into the pages browser.", "Add ability to copy and paste pages in the pages browser.",
364                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/copy"),
365                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/paste"),
366                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actionbar/sections/pageActions/groups/editingActions/items/copy"),
367                         new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actionbar/sections/pageActions/groups/editingActions/items/paste"),
368                         new OrderNodeAfterTask("", "/modules/pages/apps/pages/subApps/browser/actionbar/sections/pageActions/groups/editingActions/items/paste", "copy")))
369         );
370         register(DeltaBuilder.update("5.5.1", "")
371                 .addTask(new NodeExistsDelegateTask("", "/modules/pages/dialogs/newComponent/form/tabs/components/fields/position",
372                         new RenameNodeTask("", RepositoryConstants.CONFIG, "/modules/pages/dialogs/newComponent/form/tabs/components/fields", "position", "mgnl-position", true)))
373                 .addTask(new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/statusBar/extensions/frameResolution"))
374         );
375 
376         register(DeltaBuilder.update("5.5.2", "")
377                 .addTask(new NodeExistsDelegateTask("Display mapping conflicts in pages app", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/workbench/contentViews/list/columns/page",
378                         new ArrayDelegateTask("Display mapping conflicts in pages app",
379                                 new SetPropertyTask("", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/workbench/contentViews/list/columns/page", "reportVirtualURIConflicts", true),
380                                 new CheckAndModifyPartOfPropertyValueTask("", "", RepositoryConstants.CONFIG, "/modules/pages/apps/pages/subApps/browser/workbench/contentViews/list/columns/page", "class", "info.magnolia.ui.workbench.column.definition.PropertyColumnDefinition",
381                                         "info.magnolia.pages.app.column.PageNameColumnFormatter$Definition"))))
382         );
383 
384         register(DeltaBuilder.update("5.5.3", "")
385                 .addTask(new NodeExistsDelegateTask("Add change component template action if not already present", "/modules/pages/apps/pages/subApps/detail/actions/changeComponentTemplate", null,
386                         new ArrayDelegateTask("",
387                                 new PartialBootstrapTask("", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actions/changeComponentTemplate"),
388                                 new PartialBootstrapTask("", "", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/changeComponentTemplate"),
389                                 new OrderNodeAfterTask("", "/modules/pages/apps/pages/subApps/detail/actionbar/sections/componentActions/groups/editingActions/items/changeComponentTemplate", "duplicateComponent"))))
390         );
391         register(DeltaBuilder.update("5.5.4", "")
392                 .addTask(new NodeExistsDelegateTask("Use DeleteConfirmationAction instead of ConfirmationAction to warn about modified sub-nodes prior deletion.", "/modules/pages/apps/pages/subApps/browser/actions/confirmDeletion",
393                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages/subApps/browser/actions/confirmDeletion", "class", ConfirmationActionDefinition.class.getName(), DeleteConfirmationActionDefinition.class.getName())))
394                 .addTask(new NodeExistsDelegateTask("Use JCR export dialog for export action.", "/modules/pages/apps/pages/subApps/browser/actions/export",
395                         new ValueOfPropertyDelegateTask("Use JCR export dialog for export action.", "/modules/pages/apps/pages/subApps/browser/actions/export", "class", ExportActionDefinition.class.getName(), false,
396                                 new PartialBootstrapTask("", "/mgnl-bootstrap/pages/config.modules.pages.apps.pages.xml", "/pages/subApps/browser/actions/export"))))
397         );
398         register(DeltaBuilder.update("5.5.5", "")
399                 .addTask(new NodeExistsDelegateTask("Set class property of export action to " + OpenExportDialogActionDefinition.class.getName(), "/modules/pages/apps/pages/subApps/browser/actions/export",
400                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages/subApps/browser/actions/export", "class", OpenCreateDialogActionDefinition.class.getName(), OpenExportDialogActionDefinition.class.getName())))
401         );
402 
403         register((DeltaBuilder.update("5.5.6", ""))
404                 .addTask(new BootstrapSingleModuleResource("", "Disable copy action on deleted item.", "config.modules.pages.apps.pages.xml", "pages/subApps/browser/actions/copy/availability/rules")));
405 
406         register((DeltaBuilder.update("5.6.2", ""))
407                 .addTask(new ArrayDelegateTask("Override extend of '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields'",
408                         new NodeExistsDelegateTask("Bootstrap '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName' if node doesn't exist", "/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName", null,
409                                 new ArrayDelegateTask("Bootstrap '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName' and order it as first",
410                                         new BootstrapSingleModuleResource("Bootstrap '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName'", "Bootstrap '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName'", "dialogs/config.modules.pages.dialogs.createPage.xml", "createPage/form/tabs/tabPage/fields/jcrName"),
411                                         new OrderNodeToFirstPositionTask("Order '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName' as first", "modules/pages/dialogs/createPage/form/tabs/tabPage/fields/jcrName"))),
412                         new HasPropertyDelegateTask("Remove '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/title'", "/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/title", "extends", new RemoveNodeTask("Remove '/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/title'", "/modules/pages/dialogs/createPage/form/tabs/tabPage/fields/title")),
413                         new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/pages/dialogs/createPage/form/tabs/tabPage/fields", "extends", "override")
414                 )));
415 
416         register((DeltaBuilder.update("6.1", ""))
417                 .addTask(new ArrayDelegateTask("Change app definition to support Content Type",
418                         new CheckAndModifyPropertyValueTask("/modules/pages/apps/pages", "class", ConfiguredContentAppDescriptor.class.getName(), ConfiguredContentTypeAppDescriptor.class.getName()),
419                         new SetPropertyTask(RepositoryConstants.CONFIG, "/modules/pages/apps/pages", "contentType", "page")
420                 )));
421     }
422 
423     @Override
424     protected List<Task> getExtraInstallTasks(InstallContext installContext) {
425         List<Task> tasks = new ArrayList<>();
426         tasks.addAll(super.getExtraInstallTasks(installContext));
427         tasks.add(new IsModuleInstalledOrRegistered("Configure recursive activation and deletion as asynchronous", "scheduler", new ArrayDelegateTask("",
428                 new NodeExistsDelegateTask("Configure recursive activation as asynchronous", PAGES_APP_ACTIONS + "activateRecursive",
429                         new SetPropertyTask(RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "activateRecursive", "asynchronous", "true")),
430                 new NodeExistsDelegateTask("Configure deletion as asynchronous", PAGES_APP_ACTIONS + "delete",
431                         new SetPropertyTask(RepositoryConstants.CONFIG, PAGES_APP_ACTIONS + "delete", "asynchronous", "true"))
432         )));
433         return tasks;
434     }
435 
436     @Override
437     protected List<Condition> getInstallConditions() {
438         List<Condition> conditions = new ArrayList<>();
439         conditions.add(new PublishingOrActivationInstalledCondition());
440         return conditions;
441     }
442 
443     private class PublishingOrActivationInstalledCondition extends AbstractCondition {
444 
445         public PublishingOrActivationInstalledCondition() {
446             super("Publishing or Activation module is installed condition.", "Pages module requires Publishing(recommended) or Activation module installed.");
447         }
448 
449         @Override
450         public boolean check(InstallContext installContext) {
451             return installContext.isModuleRegistered("publishing-core") || installContext.isModuleRegistered("activation");
452         }
453     }
454 }