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