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