diff --git a/layout-service/src/main/java/io/meeds/layout/listener/SiteCreatedFromTemplateListener.java b/layout-service/src/main/java/io/meeds/layout/listener/SiteCreatedFromTemplateListener.java new file mode 100644 index 000000000..34005e133 --- /dev/null +++ b/layout-service/src/main/java/io/meeds/layout/listener/SiteCreatedFromTemplateListener.java @@ -0,0 +1,53 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.layout.listener; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import org.exoplatform.portal.config.UserPortalConfigService; +import org.exoplatform.portal.mop.SiteKey; +import org.exoplatform.services.listener.Event; +import org.exoplatform.services.listener.ListenerBase; +import org.exoplatform.services.listener.ListenerService; + +import io.meeds.layout.service.PageLayoutService; + +import jakarta.annotation.PostConstruct; + +@Component +public class SiteCreatedFromTemplateListener implements ListenerBase { + + @Autowired + private ListenerService listenerService; + + @Autowired + private PageLayoutService pageLayoutService; + + @PostConstruct + public void init() { + listenerService.addListener(UserPortalConfigService.SITE_TEMPLATE_INSTANTIATED, this); + } + + @Override + public void onEvent(Event event) throws Exception { + pageLayoutService.impersonateSite(event.getData()); + } + +} diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/PortletInstancePreferencePlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/PortletInstancePreferencePlugin.java index 293a737b9..33474a004 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/PortletInstancePreferencePlugin.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/PortletInstancePreferencePlugin.java @@ -46,6 +46,6 @@ public interface PortletInstancePreferencePlugin { * @param preferences current {@link Portlet} preferences * @return */ - List generatePreferences(Application application, Portlet preferences); + List generatePreferences(Application application, Portlet preferences); } diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/attachment/LayoutBackgroundAttachmentPlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/attachment/LayoutBackgroundAttachmentPlugin.java index 8fedca301..c90e0e04c 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/attachment/LayoutBackgroundAttachmentPlugin.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/attachment/LayoutBackgroundAttachmentPlugin.java @@ -26,6 +26,7 @@ import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.portal.config.model.Page; +import org.exoplatform.portal.mop.SiteType; import org.exoplatform.portal.mop.page.PageKey; import org.exoplatform.portal.mop.service.LayoutService; import org.exoplatform.services.security.Identity; @@ -63,14 +64,14 @@ public String getObjectType() { @Override public boolean hasEditPermission(Identity userIdentity, String entityId) throws ObjectNotFoundException { - return layoutAclService.canEditPage(getPageKey(entityId.split("_")[0]), - userIdentity == null ? null : userIdentity.getUserId()); + return layoutAclService.canEditPage(getPageKey(entityId), getUsername(userIdentity)); } @Override public boolean hasAccessPermission(Identity userIdentity, String entityId) throws ObjectNotFoundException { - return layoutAclService.canViewPage(getPageKey(entityId.split("_")[0]), - userIdentity == null ? null : userIdentity.getUserId()); + PageKey pageKey = getPageKey(entityId); + return pageKey.getSite().getType() == SiteType.GROUP_TEMPLATE + || layoutAclService.canViewPage(pageKey, getUsername(userIdentity)); } @Override @@ -84,10 +85,14 @@ public long getSpaceId(String objectId) throws ObjectNotFoundException { } private PageKey getPageKey(String entityId) { - String pageUuid = entityId.replace("page_", ""); + String pageUuid = entityId.split("_")[0].replace("page_", ""); long pageId = StringUtils.isNumeric(pageUuid) ? Long.parseLong(pageUuid) : 0; Page page = layoutService.getPage(pageId); return page.getPageKey(); } + private String getUsername(Identity userIdentity) { + return userIdentity == null ? null : userIdentity.getUserId(); + } + } diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceAddOnPlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceAddOnPlugin.java index 8d9f11a18..4b209d49d 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceAddOnPlugin.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceAddOnPlugin.java @@ -57,7 +57,7 @@ public String getContainerName() { } @Override - public List> getApplications() { + public List getApplications() { return Collections.singletonList(portletInstanceApplicationAdapter); } diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapter.java b/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapter.java index 2b6d9a589..8c619ba41 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapter.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapter.java @@ -26,59 +26,53 @@ import org.exoplatform.portal.application.PortalRequestContext; import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.config.model.ApplicationState; -import org.exoplatform.portal.config.model.ApplicationType; import org.exoplatform.portal.config.model.ModelStyle; import org.exoplatform.portal.config.model.Properties; import org.exoplatform.portal.config.model.TransientApplicationState; import org.exoplatform.portal.config.serialize.PortletApplication; import org.exoplatform.portal.pom.data.ApplicationData; -import org.exoplatform.portal.pom.spi.portlet.Portlet; import io.meeds.layout.service.PortletInstanceService; +import lombok.EqualsAndHashCode; import lombok.SneakyThrows; @Component +@EqualsAndHashCode(callSuper = true) public class PortletInstanceApplicationAdapter extends PortletApplication { - private static final String PLACEHOLDER_ID = "PortletInstanceApplicationAdapter"; + private static final String PLACEHOLDER_ID = "PortletInstanceApplicationAdapter"; - private static final TransientApplicationState PLACEHOLDER_STATE = - new TransientApplicationState<>("layout/PortletEditor"); + private static final TransientApplicationState PLACEHOLDER_STATE = new TransientApplicationState("layout/PortletEditor"); @Autowired - private PortletInstanceService portletInstanceService; + private PortletInstanceService portletInstanceService; - private ThreadLocal> application = new ThreadLocal<>(); + private ThreadLocal application = new ThreadLocal<>(); @Override public ModelStyle getCssStyle() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getCssStyle(); } @Override public void setCssStyle(ModelStyle cssStyle) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setCssStyle(cssStyle); } } - @Override - public ApplicationType getType() { - return ApplicationType.PORTLET; - } - @Override public String getWidth() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getWidth(); } @Override public void setWidth(String s) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setWidth(s); } @@ -86,13 +80,13 @@ public void setWidth(String s) { @Override public String getHeight() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getHeight(); } @Override public void setHeight(String s) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setHeight(s); } @@ -100,13 +94,13 @@ public void setHeight(String s) { @Override public String getId() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? PLACEHOLDER_ID : portletApplication.getId(); } @Override public void setId(String value) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setId(value); } @@ -114,41 +108,27 @@ public void setId(String value) { @Override public String[] getAccessPermissions() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getAccessPermissions(); } @Override public void setAccessPermissions(String[] accessPermissions) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setAccessPermissions(accessPermissions); } } @Override - public boolean isModifiable() { - Application portletApplication = getApplication(); - return portletApplication != null && portletApplication.isModifiable(); - } - - @Override - public void setModifiable(boolean modifiable) { - Application portletApplication = getApplication(); - if (portletApplication != null) { - portletApplication.setModifiable(modifiable); - } - } - - @Override - public ApplicationState getState() { - Application portletApplication = getApplication(); + public ApplicationState getState() { + Application portletApplication = getApplication(); return portletApplication == null ? PLACEHOLDER_STATE : portletApplication.getState(); } @Override - public void setState(ApplicationState value) { - Application portletApplication = getApplication(); + public void setState(ApplicationState value) { + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setState(value); } @@ -156,13 +136,13 @@ public void setState(ApplicationState value) { @Override public boolean getShowInfoBar() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication != null && portletApplication.getShowInfoBar(); } @Override public void setShowInfoBar(boolean b) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setShowInfoBar(b); } @@ -170,13 +150,13 @@ public void setShowInfoBar(boolean b) { @Override public boolean getShowApplicationState() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication != null && portletApplication.getShowApplicationState(); } @Override public void setShowApplicationState(boolean b) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setShowApplicationState(b); } @@ -184,13 +164,13 @@ public void setShowApplicationState(boolean b) { @Override public boolean getShowApplicationMode() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication != null && portletApplication.getShowApplicationMode(); } @Override public void setShowApplicationMode(boolean b) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setShowApplicationMode(b); } @@ -198,13 +178,13 @@ public void setShowApplicationMode(boolean b) { @Override public String getIcon() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getIcon(); } @Override public void setIcon(String value) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setIcon(value); } @@ -212,13 +192,13 @@ public void setIcon(String value) { @Override public String getDescription() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getDescription(); } @Override public void setDescription(String des) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setDescription(des); } @@ -226,13 +206,13 @@ public void setDescription(String des) { @Override public String getTitle() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getTitle(); } @Override public void setTitle(String value) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setTitle(value); } @@ -240,13 +220,13 @@ public void setTitle(String value) { @Override public Properties getProperties() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getProperties(); } @Override public void setProperties(Properties properties) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setProperties(properties); } @@ -254,13 +234,13 @@ public void setProperties(Properties properties) { @Override public String getTheme() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getTheme(); } @Override public void setTheme(String theme) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setTheme(theme); } @@ -268,20 +248,19 @@ public void setTheme(String theme) { @Override public String getCssClass() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getCssClass(); } @Override - @SuppressWarnings("unchecked") - public ApplicationData build() { - Application portletApplication = getApplication(); + public ApplicationData build() { + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.build(); } @Override public void checkStorage() throws ObjectNotFoundException { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.checkStorage(); } @@ -289,7 +268,7 @@ public void checkStorage() throws ObjectNotFoundException { @Override public void resetStorage() throws ObjectNotFoundException { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.resetStorage(); } @@ -297,7 +276,7 @@ public void resetStorage() throws ObjectNotFoundException { @Override public void setCssClass(String cssClass) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setCssClass(cssClass); } @@ -305,27 +284,27 @@ public void setCssClass(String cssClass) { @Override public String getStorageId() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getStorageId(); } @Override public String getStorageName() { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); return portletApplication == null ? null : portletApplication.getStorageName(); } @Override public void setStorageName(String storageName) { - Application portletApplication = getApplication(); + Application portletApplication = getApplication(); if (portletApplication != null) { portletApplication.setStorageName(storageName); } } @SneakyThrows - public Application getApplication() { // NOSONAR - Application portletApplication = application.get(); + public Application getApplication() { // NOSONAR + Application portletApplication = application.get(); if (portletApplication == null) { portletApplication = portletInstanceService.getPortletInstanceApplication(getPortletInstanceId(), getApplicationStorageId(), @@ -339,7 +318,7 @@ public void cleanApplication() { application.remove(); } - private void manageRequestCache(Application portletApplication) { + private void manageRequestCache(Application portletApplication) { PortalRequestContext requestContext = PortalRequestContext.getCurrentInstance(); if (requestContext != null) { application.set(portletApplication); diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/ImagePortletInstancePreferencePlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/ImagePortletInstancePreferencePlugin.java index 5d78ad644..7d0d99cd0 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/ImagePortletInstancePreferencePlugin.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/ImagePortletInstancePreferencePlugin.java @@ -66,11 +66,16 @@ public String getPortletName() { @Override @SneakyThrows - public List generatePreferences(Application application, - Portlet preferences) { + public List generatePreferences(Application application, Portlet preferences) { String settingName = getCmsSettingName(preferences); if (StringUtils.isBlank(settingName)) { - return Collections.emptyList(); + if (preferences != null && preferences.getPreference(DATA_INIT_PREFERENCE_NAME) != null) { + return Collections.singletonList(new PortletInstancePreference(DATA_INIT_PREFERENCE_NAME, + preferences.getPreference(DATA_INIT_PREFERENCE_NAME) + .getValue())); + } else { + return Collections.emptyList(); + } } Long fileId = getImageFileId(settingName); if (fileId == null) { diff --git a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/LinkPortletInstancePreferencePlugin.java b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/LinkPortletInstancePreferencePlugin.java index a7f0b9c8e..8fac4a7a5 100644 --- a/layout-service/src/main/java/io/meeds/layout/plugin/renderer/LinkPortletInstancePreferencePlugin.java +++ b/layout-service/src/main/java/io/meeds/layout/plugin/renderer/LinkPortletInstancePreferencePlugin.java @@ -54,11 +54,16 @@ public String getPortletName() { @Override @SneakyThrows - public List generatePreferences(Application application, - Portlet preferences) { + public List generatePreferences(Application application, Portlet preferences) { String settingName = getCmsSettingName(preferences); if (StringUtils.isBlank(settingName)) { - return Collections.emptyList(); + if (preferences != null && preferences.getPreference(DATA_INIT_PREFERENCE_NAME) != null) { + return Collections.singletonList(new PortletInstancePreference(DATA_INIT_PREFERENCE_NAME, + preferences.getPreference(DATA_INIT_PREFERENCE_NAME) + .getValue())); + } else { + return Collections.emptyList(); + } } LinkData linkData = linkService.getLinkData(settingName); return Collections.singletonList(new PortletInstancePreference(DATA_INIT_PREFERENCE_NAME, JsonUtils.toJsonString(linkData))); diff --git a/layout-service/src/main/java/io/meeds/layout/rest/model/LayoutModel.java b/layout-service/src/main/java/io/meeds/layout/rest/model/LayoutModel.java index 4d28257a2..417274c6d 100644 --- a/layout-service/src/main/java/io/meeds/layout/rest/model/LayoutModel.java +++ b/layout-service/src/main/java/io/meeds/layout/rest/model/LayoutModel.java @@ -35,7 +35,6 @@ import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.config.model.ApplicationBackgroundStyle; import org.exoplatform.portal.config.model.ApplicationState; -import org.exoplatform.portal.config.model.ApplicationType; import org.exoplatform.portal.config.model.CloneApplicationState; import org.exoplatform.portal.config.model.Container; import org.exoplatform.portal.config.model.ModelObject; @@ -292,12 +291,11 @@ private void init(ModelObject model) { // NOSONAR this.showApplicationMode = application.getShowApplicationMode(); this.accessPermissions = application.getAccessPermissions(); - @SuppressWarnings("unchecked") - ApplicationState state = application.getState(); + ApplicationState state = application.getState(); switch (state) { - case PersistentApplicationState persistentState -> this.storageId = persistentState.getStorageId(); - case CloneApplicationState persistentState -> this.storageId = persistentState.getStorageId(); - case TransientApplicationState transientState -> { + case PersistentApplicationState persistentState -> this.storageId = persistentState.getStorageId(); + case CloneApplicationState persistentState -> this.storageId = persistentState.getStorageId(); + case TransientApplicationState transientState -> { this.contentId = transientState.getContentId(); Portlet portlet = transientState.getContentState(); this.preferences = portlet == null ? Collections.emptyList() : @@ -348,8 +346,7 @@ public static ModelObject toModelObject(LayoutModel layoutModel) { // NOSONAR } return container; } else { // NOSONAR - Application application = new Application<>(ApplicationType.PORTLET, - layoutModel.getStorageId()); + Application application = new Application(layoutModel.getStorageId()); application.setId(layoutModel.getId()); application.setStorageName(layoutModel.getStorageName()); application.setIcon(layoutModel.getIcon()); @@ -364,11 +361,11 @@ public static ModelObject toModelObject(LayoutModel layoutModel) { // NOSONAR application.setAccessPermissions(layoutModel.getAccessPermissions()); application.setCssStyle(cssStyle); - ApplicationState state; + ApplicationState state; if (StringUtils.isNotBlank(layoutModel.getStorageId())) { - state = new PersistentApplicationState<>(layoutModel.getStorageId()); + state = new PersistentApplicationState(layoutModel.getStorageId()); } else if (StringUtils.isNotBlank(layoutModel.getContentId())) { - TransientApplicationState transientState = new TransientApplicationState<>(layoutModel.getContentId()); + TransientApplicationState transientState = new TransientApplicationState(layoutModel.getContentId()); transientState.setOwnerId(layoutModel.getOwnerId()); transientState.setOwnerType(layoutModel.getOwnerType()); if (CollectionUtils.isNotEmpty(layoutModel.getPreferences())) { diff --git a/layout-service/src/main/java/io/meeds/layout/rest/util/RestEntityBuilder.java b/layout-service/src/main/java/io/meeds/layout/rest/util/RestEntityBuilder.java index 9c15d7549..35cca75b8 100644 --- a/layout-service/src/main/java/io/meeds/layout/rest/util/RestEntityBuilder.java +++ b/layout-service/src/main/java/io/meeds/layout/rest/util/RestEntityBuilder.java @@ -72,7 +72,6 @@ public static LayoutModel toLayoutModel(ModelObject modelObject, return layoutModel; } - @SuppressWarnings("unchecked") private static void computeApplicationContentId(LayoutService layoutService, ArrayList children, Map contentIds) { diff --git a/layout-service/src/main/java/io/meeds/layout/service/NavigationLayoutService.java b/layout-service/src/main/java/io/meeds/layout/service/NavigationLayoutService.java index 58f1180db..8023b8fe0 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/NavigationLayoutService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/NavigationLayoutService.java @@ -37,7 +37,9 @@ import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.commons.utils.ExpressionUtil; import org.exoplatform.portal.application.PortalRequestHandler; +import org.exoplatform.portal.config.model.PortalConfig; import org.exoplatform.portal.mop.SiteKey; +import org.exoplatform.portal.mop.SiteType; import org.exoplatform.portal.mop.State; import org.exoplatform.portal.mop.Visibility; import org.exoplatform.portal.mop.navigation.NodeContext; @@ -59,6 +61,7 @@ import io.meeds.layout.model.NavigationCreateModel; import io.meeds.layout.model.NavigationUpdateModel; import io.meeds.layout.model.NodeLabel; +import io.meeds.portal.web.handler.PortalTemplateRequestHandler; @Service public class NavigationLayoutService { @@ -297,11 +300,19 @@ public String getNodeUri(NodeData node) { Router router = webController.getRouter(); Map params = new HashMap<>(); - params.put(WebAppController.HANDLER_PARAM, "portal"); // PortalRequestHandler.NAME - params.put(PortalRequestHandler.REQUEST_SITE_NAME, siteKey.getName()); - params.put(PortalRequestHandler.REQUEST_SITE_TYPE, siteKey.getTypeName()); - params.put(PortalRequestHandler.REQUEST_PATH, uriBuilder.toString().replaceFirst("/", "")); - params.put(PortalRequestHandler.LANG, Locale.ENGLISH.toLanguageTag()); + if (siteKey.getType() == SiteType.GROUP_TEMPLATE) { + PortalConfig portalConfig = layoutService.getPortalConfig(siteKey); + params.put(WebAppController.HANDLER_PARAM, PortalTemplateRequestHandler.HANDLER_NAME); + params.put(PortalTemplateRequestHandler.REQUEST_SITE_ID, (portalConfig.getStorageId().split("_"))[1]); + params.put(PortalTemplateRequestHandler.REQUEST_PATH, uriBuilder.toString().replaceFirst("/", "")); + params.put(PortalTemplateRequestHandler.LANG, Locale.ENGLISH.toLanguageTag()); + } else { + params.put(WebAppController.HANDLER_PARAM, PortalRequestHandler.HANDLER_NAME); + params.put(PortalRequestHandler.REQUEST_SITE_NAME, siteKey.getName()); + params.put(PortalRequestHandler.REQUEST_SITE_TYPE, siteKey.getTypeName()); + params.put(PortalRequestHandler.REQUEST_PATH, uriBuilder.toString().replaceFirst("/", "")); + params.put(PortalRequestHandler.LANG, Locale.ENGLISH.toLanguageTag()); + } return router.render(params).replace("/en", "").replace("?lang=en", "").replace("&lang=en", ""); } diff --git a/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java b/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java index ab2dcc754..9b3427226 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/PageLayoutService.java @@ -36,7 +36,6 @@ import org.exoplatform.commons.addons.AddOnService; import org.exoplatform.commons.exception.ObjectNotFoundException; -import org.exoplatform.portal.config.UserPortalConfigService; import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.config.model.Container; import org.exoplatform.portal.config.model.ModelObject; @@ -94,9 +93,6 @@ public class PageLayoutService { @Autowired private PortletInstanceService portletInstanceService; - @Autowired - private UserPortalConfigService userPortalConfigService; - @Autowired private AddOnService addOnService; @@ -128,12 +124,12 @@ public PageContext getPage(PageKey pageKey, String username) throws ObjectNotFou return page; } - public Application getPageApplicationLayout(PageKey pageKey, - long applicationId, - String username) throws ObjectNotFoundException, - IllegalAccessException { + public Application getPageApplicationLayout(PageKey pageKey, + long applicationId, + String username) throws ObjectNotFoundException, + IllegalAccessException { Page page = getPageLayout(pageKey, username); - Application application = findApplication(page, applicationId); + Application application = findApplication(page, applicationId); if (application == null) { throw new ObjectNotFoundException(String.format("Application with id %s wasn't found in page %s", applicationId, @@ -143,6 +139,20 @@ public Application getPageApplicationLayout(PageKey pageKey, return application; } + public void impersonateSite(SiteKey siteKey) { + PortalConfig portalConfig = layoutService.getPortalConfig(siteKey); + impersonateModel(portalConfig.getPortalLayout()); + List pages = layoutService.findPages(siteKey); + if (CollectionUtils.isNotEmpty(pages)) { + pages.forEach(page -> impersonatePage(page.getKey())); + } + } + + public void impersonatePage(PageKey pageKey) { + Page page = getPageLayout(pageKey); + impersonateModel(page); + } + public Page getPageLayout(PageKey pageKey, String username) throws ObjectNotFoundException, IllegalAccessException { Page page = getPageLayout(pageKey); if (page == null) { @@ -231,7 +241,7 @@ public void updatePageApplicationPreferences(PageKey pageKey, } else if (!aclService.canEditPage(pageKey, username)) { throw new IllegalAccessException(String.format(PAGE_NOT_EDITABLE_MESSAGE, pageKey.format(), username)); } - Application application = findApplication(page, applicationId); + Application application = findApplication(page, applicationId); if (application == null) { throw new ObjectNotFoundException(String.format("Application with id %s wasn't found in page %s", applicationId, @@ -345,14 +355,11 @@ private Page createPageInstance(String siteType, if (pageTemplate.isDisabled()) { throw new IllegalArgumentException("pageTemplate with designated Id is disabled"); } - Page page = userPortalConfigService.createPageTemplate(EMPTY_PAGE_TEMPLATE, - siteType, - siteName); + Page page = new Page(siteType, siteName, pageName); Page pageLayout = JsonUtils.fromJsonString(pageTemplate.getContent(), LayoutModel.class) .toPage(); page.setChildren(pageLayout.getChildren()); page.resetStorage(); - page.setName(pageName); page.setType(pageType.name()); yield page; } @@ -374,7 +381,7 @@ private PageType getPageType(String pageType) { private void expandAddonContainerChildren(Container container) { if (StringUtils.equals(container.getFactoryId(), "addonContainer")) { - List> applications = addOnService.getApplications(container.getName()); + List applications = addOnService.getApplications(container.getName()); if (CollectionUtils.isNotEmpty(applications)) { container.setChildren(new ArrayList<>(applications)); } @@ -393,12 +400,12 @@ private void replaceAddonContainerChildren(Container container) { if (subContainers == null) { return; } - LinkedHashMap>> addonContainerChildren = new LinkedHashMap<>(); + LinkedHashMap> addonContainerChildren = new LinkedHashMap<>(); for (int i = subContainers.size() - 1; i >= 0; i--) { ModelObject modelObject = subContainers.get(i); if (modelObject instanceof Container subContainer) { if (StringUtils.equals(subContainer.getFactoryId(), "addonContainer")) { - List> applications = addOnService.getApplications(subContainer.getName()); + List applications = addOnService.getApplications(subContainer.getName()); if (CollectionUtils.isNotEmpty(applications)) { addonContainerChildren.put(i, applications); } @@ -461,14 +468,29 @@ private void validateCSSStyleValue(String value) { } } - private void computeApplicationPreferences(Application application, String username) throws IllegalAccessException, - ObjectNotFoundException { + private void computeApplicationPreferences(Application application, String username) throws IllegalAccessException, + ObjectNotFoundException { String portletContentId = layoutService.getId(application.getState()); Portlet portletPreferences = getApplicationPreferences(Long.parseLong(application.getStorageId()), username); - TransientApplicationState applicationState = new TransientApplicationState<>(portletContentId, portletPreferences); + TransientApplicationState applicationState = new TransientApplicationState(portletContentId, portletPreferences); application.setState(applicationState); } + @SneakyThrows + private void impersonateModel(ModelObject object) { + if (object instanceof Container container) { + ArrayList children = container.getChildren(); + if (CollectionUtils.isNotEmpty(children)) { + children.forEach(this::impersonateModel); + } + } else if (object instanceof Application application) { + Portlet preferences = portletInstanceService.exportApplicationPreferences(application); + if (preferences != null) { + layoutService.save(application.getState(), preferences); + } + } + } + private Portlet getApplicationPreferences(long applicationId, String username) throws IllegalAccessException, ObjectNotFoundException { List preferences = portletInstanceService.getApplicationPreferences(applicationId, username); @@ -480,8 +502,7 @@ private Portlet getApplicationPreferences(long applicationId, String username) t return new Portlet(preferencesMap); } - @SuppressWarnings({ "unchecked", "rawtypes" }) - private Application findApplication(ModelObject modelObject, long applicationId) { + private Application findApplication(ModelObject modelObject, long applicationId) { return switch (modelObject) { case Container container -> { if (!CollectionUtils.isEmpty(container.getChildren())) { diff --git a/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java index 35dc25791..40dde921b 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/PortletInstanceService.java @@ -25,6 +25,7 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; @@ -36,6 +37,7 @@ import org.exoplatform.portal.config.UserACL; import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.pom.spi.portlet.Portlet; +import org.exoplatform.portal.pom.spi.portlet.Preference; import org.exoplatform.services.listener.ListenerService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; @@ -301,7 +303,7 @@ public PortletInstanceCategory updatePortletInstanceCategory(PortletInstanceCate return updatedPortletInstanceCategory; } - public Application getPortletInstanceApplication(long portletInstanceId, + public Application getPortletInstanceApplication(long portletInstanceId, long applicationStorageId, String username) throws IllegalAccessException, ObjectNotFoundException { @@ -323,7 +325,7 @@ public List getPortletInstancePreferences(long portle public List getApplicationPreferences(long applicationId, String username) throws IllegalAccessException, ObjectNotFoundException { - Application application = portletInstanceLayoutStorage.getApplication(applicationId); + Application application = portletInstanceLayoutStorage.getApplication(applicationId); if (application == null) { throw new ObjectNotFoundException(String.format("Application with id %s wasn't found", applicationId)); } @@ -347,6 +349,23 @@ public List getPortletInstances() { return portletInstanceStorage.getPortletInstances(); } + public Portlet exportApplicationPreferences(Application application) { + String portletName = portletInstanceLayoutStorage.getApplicationPortletName(application); + if (preferencePlugins.containsKey(portletName)) { + PortletInstancePreferencePlugin plugin = preferencePlugins.get(portletName); + Portlet preferences = portletInstanceLayoutStorage.getApplicationPreferences(Long.parseLong(application.getStorageId())); + List exportedPreferences = plugin.generatePreferences(application, preferences); + Map preferencesMap = exportedPreferences.stream() + .collect(Collectors.toMap(PortletInstancePreference::getName, + p -> new Preference(p.getName(), + p.getValue(), + false))); + return new Portlet(preferencesMap); + } else { + return null; + } + } + private void deletePortletInstanceFromStore(long id) throws ObjectNotFoundException { try { attachmentService.deleteAttachments(PortletInstanceAttachmentPlugin.OBJECT_TYPE, String.valueOf(id)); @@ -399,14 +418,14 @@ private void computePortletInstanceCategoryAttributes(Locale locale, PortletInst } private List getPortletInstancePreferences(PortletInstance portletInstance) throws ObjectNotFoundException { - Application application = portletInstanceLayoutStorage.getOrCreatePortletInstanceApplication(portletInstance); + Application application = portletInstanceLayoutStorage.getOrCreatePortletInstanceApplication(portletInstance); if (application == null) { throw new ObjectNotFoundException(String.format("Portlet Instance with id %s wasn't found", portletInstance.getId())); } return getApplicationPreferences(application); } - private List getApplicationPreferences(Application application) { + private List getApplicationPreferences(Application application) { String portletName = portletInstanceLayoutStorage.getApplicationPortletName(application); Portlet preferences = portletInstanceLayoutStorage.getApplicationPreferences(Long.parseLong(application.getStorageId())); PortletInstancePreferencePlugin plugin = preferencePlugins.get(portletName); diff --git a/layout-service/src/main/java/io/meeds/layout/service/SiteLayoutService.java b/layout-service/src/main/java/io/meeds/layout/service/SiteLayoutService.java index 6f2f3c62d..920b56910 100644 --- a/layout-service/src/main/java/io/meeds/layout/service/SiteLayoutService.java +++ b/layout-service/src/main/java/io/meeds/layout/service/SiteLayoutService.java @@ -37,6 +37,7 @@ import org.exoplatform.portal.mop.SiteKey; import org.exoplatform.portal.mop.SiteType; import org.exoplatform.portal.mop.service.LayoutService; +import org.exoplatform.portal.mop.service.NavigationService; import org.exoplatform.portal.mop.user.UserPortal; import org.exoplatform.services.resources.LocaleConfig; import org.exoplatform.services.resources.LocaleConfigService; @@ -55,6 +56,9 @@ public class SiteLayoutService { @Autowired private LayoutService layoutService; + @Autowired + private NavigationService navigationService; + @Autowired private LocaleConfigService localeConfigService; @@ -151,6 +155,8 @@ public void deleteSite(SiteKey siteKey, String username) throws IllegalAccessExc } else if (!aclService.canEditSite(siteKey, username)) { throw new IllegalAccessException(String.format("Site with key %s can't be deleted by user %s", siteKey, username)); } + navigationService.destroyNavigation(siteKey); + layoutService.removePages(siteKey); layoutService.remove(portalConfig); } diff --git a/layout-service/src/main/java/io/meeds/layout/storage/PortletInstanceLayoutStorage.java b/layout-service/src/main/java/io/meeds/layout/storage/PortletInstanceLayoutStorage.java index c11bd6001..6f3495748 100644 --- a/layout-service/src/main/java/io/meeds/layout/storage/PortletInstanceLayoutStorage.java +++ b/layout-service/src/main/java/io/meeds/layout/storage/PortletInstanceLayoutStorage.java @@ -79,7 +79,7 @@ public class PortletInstanceLayoutStorage { @Autowired private LayoutService layoutService; - public Application getPortletInstanceApplication(PortletInstance portletInstance, long applicationStorageId) { + public Application getPortletInstanceApplication(PortletInstance portletInstance, long applicationStorageId) { if (portletInstance != null) { // Display the portlet instance by id return getOrCreatePortletInstanceApplication(portletInstance); @@ -91,7 +91,7 @@ public Application getPortletInstanceApplication(PortletInstance portle } } - public Application getOrCreatePortletInstanceApplication(PortletInstance portletInstance) { // NOSONAR + public Application getOrCreatePortletInstanceApplication(PortletInstance portletInstance) { // NOSONAR long applicationId = getPortletInstanceApplicationId(portletInstance.getId()); if (applicationId == 0) { return createPortletInstanceApplication(portletInstance); @@ -104,16 +104,16 @@ public Application getOrCreatePortletInstanceApplication(PortletInstanc } } - public Application getApplication(long applicationId) { + public Application getApplication(long applicationId) { return layoutService.getApplicationModel(String.valueOf(applicationId)); } public Portlet getApplicationPreferences(long applicationId) { - Application application = getApplication(applicationId); - return layoutService.load(application.getState(), application.getType()); + Application application = getApplication(applicationId); + return layoutService.load(application.getState()); } - public String getApplicationPortletName(Application application) { + public String getApplicationPortletName(Application application) { String contentId = layoutService.getId(application.getState()); return StringUtils.isBlank(contentId) ? null : contentId.split("/")[1]; } @@ -126,9 +126,8 @@ public long getPortletInstanceApplicationId(long portletInstanceId) { return getSettingValue(PORTLET_INSTANCE_SCOPE, portletInstanceId); } - @SuppressWarnings("unchecked") - private synchronized Application createPortletInstanceApplication(PortletInstance portletInstance) { - TransientApplicationState state = new TransientApplicationState<>(portletInstance.getContentId()); + private synchronized Application createPortletInstanceApplication(PortletInstance portletInstance) { + TransientApplicationState state = new TransientApplicationState(portletInstance.getContentId()); List permissions = portletInstance.getPermissions(); List preferences = portletInstance.getPreferences(); @@ -160,7 +159,7 @@ private synchronized Application createPortletInstanceApplication(Portl layoutService.save(page); container = getPortletInstanceSystemContainer(); - Application application = (Application) container.getChildren().get(index); + Application application = (Application) container.getChildren().get(index); savePortletInstanceApplicationId(Long.parseLong(application.getStorageId()), portletInstance.getId()); return application; diff --git a/layout-service/src/test/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapterTest.java b/layout-service/src/test/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapterTest.java index 27e2e39bc..73e21889d 100644 --- a/layout-service/src/test/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapterTest.java +++ b/layout-service/src/test/java/io/meeds/layout/plugin/container/PortletInstanceApplicationAdapterTest.java @@ -18,12 +18,15 @@ */ package io.meeds.layout.plugin.container; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.*; - -import org.exoplatform.portal.config.model.Properties; +import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -38,9 +41,8 @@ import org.exoplatform.portal.application.PortalRequestContext; import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.config.model.ApplicationState; -import org.exoplatform.portal.config.model.ApplicationType; import org.exoplatform.portal.config.model.ModelStyle; -import org.exoplatform.portal.pom.spi.portlet.Portlet; +import org.exoplatform.portal.config.model.Properties; import io.meeds.layout.service.PortletInstanceService; @@ -58,20 +60,18 @@ public class PortletInstanceApplicationAdapterTest { private PortletInstanceService portletInstanceService; @Mock - private Application application; + private Application application; @Autowired private PortletInstanceApplicationAdapter portletInstanceApplicationAdapter; @Test public void testNullApplication() { - assertEquals(ApplicationType.PORTLET, portletInstanceApplicationAdapter.getType()); assertNull(portletInstanceApplicationAdapter.getCssStyle()); assertNull(portletInstanceApplicationAdapter.getWidth()); assertNull(portletInstanceApplicationAdapter.getHeight()); assertNotNull(portletInstanceApplicationAdapter.getId()); assertNotNull(portletInstanceApplicationAdapter.getState()); - assertFalse(portletInstanceApplicationAdapter.isModifiable()); assertFalse(portletInstanceApplicationAdapter.getShowInfoBar()); assertFalse(portletInstanceApplicationAdapter.getShowApplicationState()); assertFalse(portletInstanceApplicationAdapter.getShowApplicationMode()); @@ -92,7 +92,6 @@ public void testNoThrowWhenNoApplication() { assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setWidth(null)); assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setHeight(null)); assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setId(null)); - assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setModifiable(false)); assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setState(null)); assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setShowInfoBar(false)); assertDoesNotThrow(() -> portletInstanceApplicationAdapter.setShowApplicationState(false)); @@ -119,20 +118,18 @@ public void testApplicationDelegation() throws IllegalAccessException, ObjectNot when(request.getParameter("portletInstanceId")).thenReturn(String.valueOf(portletInstanceId)); when(request.getRemoteUser()).thenReturn(USERNAME); - Application portletApplication = portletInstanceApplicationAdapter.getApplication(); + Application portletApplication = portletInstanceApplicationAdapter.getApplication(); assertNotNull(portletApplication); int i = 0; ModelStyle cssStyle = mock(ModelStyle.class); - @SuppressWarnings("unchecked") - ApplicationState state = mock(ApplicationState.class); + ApplicationState state = mock(ApplicationState.class); Properties properties = mock(Properties.class); when(portletApplication.getCssStyle()).thenReturn(cssStyle); when(portletApplication.getWidth()).thenReturn(String.valueOf(++i)); when(portletApplication.getHeight()).thenReturn(String.valueOf(++i)); when(portletApplication.getId()).thenReturn(String.valueOf(++i)); when(portletApplication.getState()).thenReturn(state); - when(portletApplication.isModifiable()).thenReturn(true); when(portletApplication.getShowInfoBar()).thenReturn(true); when(portletApplication.getShowApplicationState()).thenReturn(true); when(portletApplication.getShowApplicationMode()).thenReturn(true); @@ -150,7 +147,6 @@ public void testApplicationDelegation() throws IllegalAccessException, ObjectNot assertEquals(String.valueOf(++i), portletInstanceApplicationAdapter.getHeight()); assertEquals(String.valueOf(++i), portletInstanceApplicationAdapter.getId()); assertEquals(state, portletInstanceApplicationAdapter.getState()); - assertTrue(portletInstanceApplicationAdapter.isModifiable()); assertTrue(portletInstanceApplicationAdapter.getShowInfoBar()); assertTrue(portletInstanceApplicationAdapter.getShowApplicationState()); assertTrue(portletInstanceApplicationAdapter.getShowApplicationMode()); diff --git a/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java index 9cf73adb1..bd46ce36d 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/PageLayoutServiceTest.java @@ -59,7 +59,6 @@ import org.exoplatform.portal.mop.page.PageKey; import org.exoplatform.portal.mop.page.PageState; import org.exoplatform.portal.mop.service.LayoutService; -import org.exoplatform.portal.pom.spi.portlet.Portlet; import io.meeds.layout.model.PageCreateModel; import io.meeds.layout.model.PageTemplate; @@ -166,7 +165,6 @@ public void getPageLayout() throws IllegalAccessException, ObjectNotFoundExcepti assertEquals(page, pageLayoutService.getPageLayout(PAGE_KEY, TEST_USER)); } - @SuppressWarnings("unchecked") @Test public void getPageApplicationLayout() throws IllegalAccessException, ObjectNotFoundException { assertThrows(ObjectNotFoundException.class, () -> pageLayoutService.getPageApplicationLayout(PAGE_KEY, 2l, TEST_USER)); @@ -177,13 +175,12 @@ public void getPageApplicationLayout() throws IllegalAccessException, ObjectNotF Container container = mock(Container.class); when(page.getChildren()).thenReturn(new ArrayList<>(Collections.singleton(container))); - Application application = mock(Application.class); + Application application = mock(Application.class); when(application.getStorageId()).thenReturn("2"); when(container.getChildren()).thenReturn(new ArrayList<>(Collections.singleton(application))); assertNotNull(pageLayoutService.getPageApplicationLayout(PAGE_KEY, 2l, TEST_USER)); } - @SuppressWarnings("unchecked") @Test public void getPageLayoutWithDynamicContainer() { when(layoutService.getPage(PAGE_KEY)).thenReturn(page); @@ -191,7 +188,7 @@ public void getPageLayoutWithDynamicContainer() { when(dynamicContainer.getFactoryId()).thenReturn(ADDON_CONTAINER); when(dynamicContainer.getName()).thenReturn(TEST_ADDON_CONTAINER); when(page.getChildren()).thenReturn(new ArrayList<>(Collections.singleton(dynamicContainer))); - Application application = mock(Application.class); + Application application = mock(Application.class); when(addOnService.getApplications(TEST_ADDON_CONTAINER)).thenReturn(Collections.singletonList(application)); pageLayoutService.getPageLayout(PAGE_KEY); verify(dynamicContainer).setChildren(argThat(children -> children != null && children.size() == 1 @@ -219,9 +216,6 @@ public void createPage() { when(portalConfig.getAccessPermissions()).thenReturn(new String[] { sitePermission }); String siteEditPermission = "site edit permission"; when(portalConfig.getEditPermission()).thenReturn(siteEditPermission); - when(userPortalConfigService.createPageTemplate(PageLayoutService.EMPTY_PAGE_TEMPLATE, - SITE_KEY.getTypeName(), - SITE_KEY.getName())).thenReturn(page); assertThrows(ObjectNotFoundException.class, () -> pageLayoutService.createPage(pageModel, TEST_USER)); PageTemplate pageTemplate = mock(PageTemplate.class); @@ -229,18 +223,19 @@ public void createPage() { when(pageTemplateService.getPageTemplate(2l)).thenReturn(pageTemplate); pageLayoutService.createPage(pageModel, TEST_USER); - verify(layoutService).save(any(PageContext.class), eq(page)); - verify(page).setAccessPermissions(argThat(permissions -> permissions[0].equals(sitePermission))); - verify(page).setEditPermission(argThat(permission -> permission.equals(siteEditPermission))); - verify(page).setTitle(pageTitle); + verify(layoutService).save(any(PageContext.class), + argThat(p -> p.getAccessPermissions()[0].equals(sitePermission) + && p.getEditPermission().equals(siteEditPermission) + && p.getTitle().equals(pageTitle))); String pagePermission = "page permission"; when(pageModel.getAccessPermissions()).thenReturn(new String[] { pagePermission }); String pageEditPermission = "page edit permission"; when(pageModel.getEditPermission()).thenReturn(pageEditPermission); pageLayoutService.createPage(pageModel, TEST_USER); - verify(page).setAccessPermissions(argThat(permissions -> permissions[0].equals(pagePermission))); - verify(page).setEditPermission(argThat(permission -> permission.equals(pageEditPermission))); + verify(layoutService).save(any(PageContext.class), + argThat(p -> p.getAccessPermissions()[0].equals(pagePermission) + && p.getEditPermission().equals(pageEditPermission))); } @Test @@ -285,7 +280,6 @@ public void clonePage() throws IllegalAccessException, ObjectNotFoundException { verify(layoutService).save(any(PageContext.class), eq(page)); } - @SuppressWarnings("unchecked") @Test public void clonePageWithDynamicContainer() throws IllegalAccessException, ObjectNotFoundException { when(layoutService.getPage(PAGE_KEY)).thenReturn(page); @@ -293,7 +287,7 @@ public void clonePageWithDynamicContainer() throws IllegalAccessException, Objec when(dynamicContainer.getFactoryId()).thenReturn(ADDON_CONTAINER); when(dynamicContainer.getName()).thenReturn(TEST_ADDON_CONTAINER); when(page.getChildren()).thenReturn(new ArrayList<>(Collections.singleton(dynamicContainer))); - Application application = mock(Application.class); + Application application = mock(Application.class); when(addOnService.getApplications(TEST_ADDON_CONTAINER)).thenReturn(Collections.singletonList(application)); when(aclService.canEditPage(PAGE_KEY, TEST_USER)).thenReturn(true); when(page.getName()).thenReturn(PAGE_KEY.getName()); @@ -302,7 +296,6 @@ public void clonePageWithDynamicContainer() throws IllegalAccessException, Objec verify(page).setChildren(argThat(children -> children != null && children.size() == 1 && children.get(0) == application)); } - @SuppressWarnings("unchecked") @Test public void updatePageLayout() throws IllegalAccessException, ObjectNotFoundException { assertThrows(ObjectNotFoundException.class, @@ -349,7 +342,7 @@ public void updatePageLayout() throws IllegalAccessException, ObjectNotFoundExce assertDoesNotThrow(() -> pageLayoutService.updatePageLayout(PAGE_KEY.format(), page, true, TEST_USER)); - Application application = mock(Application.class); + Application application = mock(Application.class); when(page.getChildren()).thenReturn(new ArrayList<>(Collections.singletonList(application))); when(application.getWidth()).thenReturn("eval('alert(`XSS in application width CSS style`)')"); diff --git a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceRenderServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceRenderServiceTest.java index d683c8073..6b8d4bdfc 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceRenderServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceRenderServiceTest.java @@ -98,7 +98,7 @@ public void getPortletInstanceApplicationByInstanceId() { when(layoutService.getApplicationModel("3")).thenReturn(application); when(portletInstance.getId()).thenReturn(2l); - Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0); + Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0); assertEquals(application, portletInstanceApplication); } @@ -113,7 +113,7 @@ public void getPortletInstanceApplicationPlaceholder() { public void getPortletInstancePreferencesWhenNoPlugin() { when(layoutService.getApplicationModel("3")).thenReturn(application); Portlet portlet = new Portlet(); - when(layoutService.load(any(), any())).thenReturn(portlet); + when(layoutService.load(any())).thenReturn(portlet); portlet.setValue("test", "testValue"); Portlet portletInstancePreferences = portletInstanceLayoutStorage.getApplicationPreferences(3); @@ -151,7 +151,7 @@ public void getPortletInstanceApplicationByInstanceIdAndCreateApplication() { return null; }).when(container).setChildren(any()); - Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0); + Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0); assertEquals(application, portletInstanceApplication); } @@ -161,7 +161,7 @@ public void getPortletInstanceApplicationByApplicationId() { when(settingService.get(any(), any(), eq("2"))).thenReturn(new SettingValue("3")); when(layoutService.getApplicationModel("3")).thenReturn(application); - Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(null, 3); + Application portletInstanceApplication = portletInstanceLayoutStorage.getPortletInstanceApplication(null, 3); assertEquals(application, portletInstanceApplication); } diff --git a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java index f3053e3e1..a32719af7 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/PortletInstanceServiceTest.java @@ -114,7 +114,7 @@ public class PortletInstanceServiceTest { private PortletInstance portletInstance; @Mock - private Application application; + private Application application; @Mock private LocaleConfig defaultLocaleConfig; @@ -550,7 +550,7 @@ public void getPortletInstanceApplication() { () -> portletInstanceService.getPortletInstanceApplication(2, 0, USERNAME)); when(portletInstanceStorage.getPortletInstance(2)).thenReturn(portletInstance); when(portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0)).thenReturn(application); - Application portletInstanceApplication = portletInstanceService.getPortletInstanceApplication(2, 0, USERNAME); + Application portletInstanceApplication = portletInstanceService.getPortletInstanceApplication(2, 0, USERNAME); assertEquals(application, portletInstanceApplication); } @@ -618,24 +618,12 @@ public void getPortletInstancePreferencesWhenNoPluginNoPreferences() { assertEquals(0, portletInstanceService.getPortletInstancePreferences(2, USERNAME).size()); } - @Test - @SneakyThrows - public void getPortletInstanceApplicationByInstanceIdAndCreateApplication() { - assertThrows(ObjectNotFoundException.class, - () -> portletInstanceService.getPortletInstanceApplication(2, 0, USERNAME)); - when(portletInstanceStorage.getPortletInstance(2)).thenReturn(portletInstance); - when(portletInstanceLayoutStorage.getPortletInstanceApplication(portletInstance, 0)).thenReturn(application); - - Application portletInstanceApplication = portletInstanceService.getPortletInstanceApplication(2, 0, USERNAME); - assertEquals(application, portletInstanceApplication); - } - @Test @SneakyThrows public void getPortletInstanceApplicationByApplicationId() { when(portletInstanceLayoutStorage.getPortletInstanceApplication(null, 3)).thenReturn(application); - Application portletInstanceApplication = portletInstanceService.getPortletInstanceApplication(0, 3, USERNAME); + Application portletInstanceApplication = portletInstanceService.getPortletInstanceApplication(0, 3, USERNAME); assertEquals(application, portletInstanceApplication); } diff --git a/layout-service/src/test/java/io/meeds/layout/service/SiteLayoutServiceTest.java b/layout-service/src/test/java/io/meeds/layout/service/SiteLayoutServiceTest.java index 4ac06435a..db83ac105 100644 --- a/layout-service/src/test/java/io/meeds/layout/service/SiteLayoutServiceTest.java +++ b/layout-service/src/test/java/io/meeds/layout/service/SiteLayoutServiceTest.java @@ -50,6 +50,7 @@ import org.exoplatform.portal.config.model.PortalConfig; import org.exoplatform.portal.mop.SiteKey; import org.exoplatform.portal.mop.service.LayoutService; +import org.exoplatform.portal.mop.service.NavigationService; import org.exoplatform.portal.mop.user.UserPortal; import org.exoplatform.services.resources.LocaleConfig; import org.exoplatform.services.resources.LocaleConfigService; @@ -75,6 +76,9 @@ public class SiteLayoutServiceTest { @MockBean private LayoutService layoutService; + @MockBean + private NavigationService navigationService; + @MockBean private UserPortalConfigService portalConfigService; diff --git a/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties b/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties index 0db947226..c06871be6 100644 --- a/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties +++ b/layout-webapp/src/main/resources/locale/portlet/LayoutEditor_en.properties @@ -350,3 +350,6 @@ layout.globalPageBackground=Page Background layout.newPortletChoice=New Portlet layout.existingPortletChoice=Existing Portlet +layout.previewAsASpace=View as a space +layout.searchForASpace=Search for a space +layout.noSpaceFound=No matching space found diff --git a/layout-webapp/src/main/resources/locale/portlet/SiteManagement_en.properties b/layout-webapp/src/main/resources/locale/portlet/SiteManagement_en.properties index 0e5f57389..8311e7252 100644 --- a/layout-webapp/src/main/resources/locale/portlet/SiteManagement_en.properties +++ b/layout-webapp/src/main/resources/locale/portlet/SiteManagement_en.properties @@ -1,5 +1,6 @@ siteManagement.label.portal=Site siteManagement.label.group=Site of group +siteManagement.label.group_template=Group Template siteManagement.label.navigation=Navigation siteManagement.label.delete=Delete siteManagement.label.cancel=Cancel diff --git a/layout-webapp/src/main/resources/locale/portlet/SiteNavigation_en.properties b/layout-webapp/src/main/resources/locale/portlet/SiteNavigation_en.properties index 8c2a5a1ba..922457ea9 100644 --- a/layout-webapp/src/main/resources/locale/portlet/SiteNavigation_en.properties +++ b/layout-webapp/src/main/resources/locale/portlet/SiteNavigation_en.properties @@ -19,6 +19,7 @@ siteNavigation.label.groupSuggester.noData=No data siteNavigation.label.view.everyone=Everyone siteNavigation.label.view.designedGroup=Group members siteNavigation.label.btn.save=Save +siteNavigation.label.btn.close=Close siteNavigation.label.btn.next=Next siteNavigation.label.btn.cancel=Cancel siteNavigation.label.moveUp=Move up diff --git a/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml b/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml index ac52ca89f..edc6f8280 100644 --- a/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml +++ b/layout-webapp/src/main/webapp/WEB-INF/gatein-resources.xml @@ -43,6 +43,13 @@ /skin/css/editor.css + + social + SpaceTemplateManagement + Enterprise + /skin/css/siteNavigation.css + + commonLayoutComponents + + extensionRegistry + + + eXoVueI18n + + + vue + + + vuetify + + + commonVueComponents + + + commonLayoutComponents + + + translationField + + + fontIcons + + + SiteNavigation diff --git a/layout-webapp/src/main/webapp/WEB-INF/jsp/siteManagement.jsp b/layout-webapp/src/main/webapp/WEB-INF/jsp/siteManagement.jsp index 1b76f32ca..e945ebcaf 100644 --- a/layout-webapp/src/main/webapp/WEB-INF/jsp/siteManagement.jsp +++ b/layout-webapp/src/main/webapp/WEB-INF/jsp/siteManagement.jsp @@ -4,7 +4,7 @@ <% PortalContainer portalContainer = PortalContainer.getCurrentInstance(session.getServletContext()); UserPortalConfigService userPortalConfigService = portalContainer.getComponentInstanceOfType(UserPortalConfigService.class); - String defaultPortalName = userPortalConfigService.getDefaultPortal(); + String defaultPortalName = userPortalConfigService.getMetaPortal(); String globalPortalName = userPortalConfigService.getGlobalPortal(); %>
diff --git a/layout-webapp/src/main/webapp/vue-app/common-layout-components/components/site-navigation/SiteNavigationDrawer.vue b/layout-webapp/src/main/webapp/vue-app/common-layout-components/components/site-navigation/SiteNavigationDrawer.vue index f57a4eb8c..70f150fc0 100644 --- a/layout-webapp/src/main/webapp/vue-app/common-layout-components/components/site-navigation/SiteNavigationDrawer.vue +++ b/layout-webapp/src/main/webapp/vue-app/common-layout-components/components/site-navigation/SiteNavigationDrawer.vue @@ -19,7 +19,8 @@ + \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/layout-editor/initComponents.js b/layout-webapp/src/main/webapp/vue-app/layout-editor/initComponents.js index 93bdd8639..3a82436b3 100644 --- a/layout-webapp/src/main/webapp/vue-app/layout-editor/initComponents.js +++ b/layout-webapp/src/main/webapp/vue-app/layout-editor/initComponents.js @@ -27,6 +27,7 @@ import SaveTemplateButton from './components/toolbar/actions/SaveTemplateButton. import HistoryButtons from './components/toolbar/actions/HistoryButtons.vue'; import MobilePreviewButton from './components/toolbar/actions/MobilePreviewButton.vue'; import PagePreviewButton from './components/toolbar/actions/PagePreviewButton.vue'; +import PageSpacePreviewButton from './components/toolbar/actions/PageSpacePreviewButton.vue'; import PagePropertiesButton from './components/toolbar/actions/PagePropertiesButton.vue'; import BorderRadiusSelector from './components/form/BorderRadiusSelector.vue'; @@ -81,6 +82,7 @@ const components = { 'layout-editor-toolbar-save-template-button': SaveTemplateButton, 'layout-editor-toolbar-history-buttons': HistoryButtons, 'layout-editor-toolbar-page-preview-button': PagePreviewButton, + 'layout-editor-toolbar-page-space-preview-button': PageSpacePreviewButton, 'layout-editor-toolbar-page-properties-button': PagePropertiesButton, 'layout-editor-toolbar-mobile-preview-button': MobilePreviewButton, 'layout-editor-content': Content, diff --git a/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js b/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js index dedb554f9..c48ec5941 100644 --- a/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js +++ b/layout-webapp/src/main/webapp/vue-app/layout-editor/main.js @@ -94,6 +94,8 @@ export function init() { diffScrollY: 0, gap: 20, nodeUri: null, + originalUri: `/portal/${window.location.href.split('/portal/')[1]}`, + originalHref: window.location.href, }), computed: { parentAppX() { @@ -129,6 +131,9 @@ export function init() { pageId() { return this.$root.page?.state?.storageId?.replace?.('page_', ''); }, + isSpaceSiteTemplate() { + return this.pageRef?.toLowerCase?.()?.indexOf('group_template::') === 0; + }, }, watch: { movingParentId() { @@ -154,6 +159,9 @@ export function init() { }, }, created() { + // Some applications will change the window location state when displayed + // This will ensure to preserve the original Page location URI + new MutationObserver(this.setOriginalUri).observe(document, { subtree: true, childList: true }); document.addEventListener('extension-layout-editor-container-updated', this.refreshContainerTypes); this.$on('layout-editor-portlet-instances-refresh', this.refreshPortletInstances); document.addEventListener('drawerOpened', this.setDrawerOpened); @@ -166,6 +174,11 @@ export function init() { this.$el?.closest?.('.PORTLET-FRAGMENT')?.classList?.remove?.('PORTLET-FRAGMENT'); }, methods: { + setOriginalUri() { + if (window.location.href !== this.originalHref) { + window.history.replaceState('', window.document.title, this.originalUri); + } + }, setDrawerOpened() { this.drawerOpened++; }, diff --git a/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteCard.vue b/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteCard.vue index e8904581a..9cf14eac4 100644 --- a/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteCard.vue +++ b/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteCard.vue @@ -54,7 +54,6 @@ - \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteManagement.vue b/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteManagement.vue index 1b7eb2cd1..52780feaf 100644 --- a/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteManagement.vue +++ b/layout-webapp/src/main/webapp/vue-app/site-management/components/SiteManagement.vue @@ -44,6 +44,7 @@ export default { data() { return { sites: [], + loading: 0, siteToDelete: null, deleteConfirmMessage: '', }; @@ -55,12 +56,10 @@ export default { }, methods: { getSites() { - this.loading = true; - return this.$siteService.getSites(null, 'USER', null, true, true, false, false, false, null, true) - .then(sites => { - this.sites = sites || []; - }) - .finally(() => this.loading = false); + this.loading++; + return this.$siteService.getSites('PORTAL', null, 'public', true, true, false, false, false, null, true) + .then(sites => this.sites = sites?.filter(s => !s?.properties?.IS_SPACE_PUBLIC_SITE) || []) + .finally(() => this.loading--); }, confirmDelete(siteToDelete) { this.siteToDelete = siteToDelete; @@ -68,10 +67,11 @@ export default { this.$refs.deleteSiteConfirmDialog.open(); }, deleteSite() { + this.loading++; return this.$siteLayoutService.deleteSite(this.siteToDelete.siteType, this.siteToDelete.name) - .then(() => { - this.$root.$emit('refresh-sites'); - });} + .then(() => this.$root.$emit('refresh-sites')) + .finally(() => this.loading--); + }, } }; diff --git a/layout-webapp/src/main/webapp/vue-app/site-management/components/SitesList.vue b/layout-webapp/src/main/webapp/vue-app/site-management/components/SitesList.vue index f3415190c..7f9fbf1eb 100644 --- a/layout-webapp/src/main/webapp/vue-app/site-management/components/SitesList.vue +++ b/layout-webapp/src/main/webapp/vue-app/site-management/components/SitesList.vue @@ -33,7 +33,6 @@ - \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/site-navigation/components/SpaceTemplateEditLayoutSpaceMenuItem.vue b/layout-webapp/src/main/webapp/vue-app/site-navigation/components/SpaceTemplateEditLayoutSpaceMenuItem.vue new file mode 100644 index 000000000..c3bf95248 --- /dev/null +++ b/layout-webapp/src/main/webapp/vue-app/site-navigation/components/SpaceTemplateEditLayoutSpaceMenuItem.vue @@ -0,0 +1,84 @@ + + + \ No newline at end of file diff --git a/layout-webapp/src/main/webapp/vue-app/site-navigation/initComponents.js b/layout-webapp/src/main/webapp/vue-app/site-navigation/initComponents.js index c4ebd603e..56426cb22 100644 --- a/layout-webapp/src/main/webapp/vue-app/site-navigation/initComponents.js +++ b/layout-webapp/src/main/webapp/vue-app/site-navigation/initComponents.js @@ -20,11 +20,15 @@ import SiteNavigation from './components/SiteNavigation.vue'; import SiteNavigationButton from './components/SiteNavigationButton.vue'; import SiteNavigationDrawersActions from './components/SiteNavigationDrawersActions.vue'; +import SpaceTemplateEditLayoutSpaceMenuItem from './components/SpaceTemplateEditLayoutSpaceMenuItem.vue'; +import SpaceTemplateCreateListener from './components/SpaceTemplateCreateListener.vue'; const components = { 'site-navigation': SiteNavigation, 'site-navigation-button': SiteNavigationButton, - 'site-navigation-drawers-actions': SiteNavigationDrawersActions + 'site-navigation-drawers-actions': SiteNavigationDrawersActions, + 'site-navigation-space-template-manage-layout': SpaceTemplateEditLayoutSpaceMenuItem, + 'site-navigation-space-template-create-listener': SpaceTemplateCreateListener, }; for (const key in components) { diff --git a/layout-webapp/src/main/webapp/vue-app/site-navigation/main.js b/layout-webapp/src/main/webapp/vue-app/site-navigation/main.js index 2e5340051..afd91ab3d 100644 --- a/layout-webapp/src/main/webapp/vue-app/site-navigation/main.js +++ b/layout-webapp/src/main/webapp/vue-app/site-navigation/main.js @@ -43,6 +43,24 @@ extensionRegistry.registerComponent('manageSpaceDrawers', 'manage-space-drawers' rank: 20, }); +extensionRegistry.registerComponent('space-templates', 'space-templates-drawers', { + id: 'manage-space-drawers', + vueComponent: Vue.options.components['site-navigation-drawers-actions'], + rank: 10, +}); + +extensionRegistry.registerExtension('space-templates', 'space-templates-item-action', { + rank: 25, + name: 'manage-layout', + componentName: 'site-navigation-space-template-manage-layout', +}); + +extensionRegistry.registerExtension('space-templates', 'space-templates-main', { + rank: 10, + name: 'manage-layout', + componentName: 'site-navigation-space-template-create-listener', +}); + const appId = 'siteNavigation'; //getting language of the PLF