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