Skip to content

Commit

Permalink
feat: Allow to Configure Spaces List in Left Menu - MEED-7799 - Meeds…
Browse files Browse the repository at this point in the history
…-io/MIPs#159 (#4197)

This change will allow to add Spaces in the Left Menu per Space
Template.
  • Loading branch information
boubaker authored Nov 22, 2024
1 parent 3f512bf commit 751f1e7
Show file tree
Hide file tree
Showing 18 changed files with 510 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
package io.meeds.social.navigation.constant;

public enum SidebarItemType {
PAGE, SITE, SEPARATOR, SPACES, SPACE_TEMPLATE;
PAGE, SITE, SEPARATOR, SPACES, SPACE_TEMPLATE, SPACE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,40 @@
*/
package io.meeds.social.navigation.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class NavigationConfiguration implements Cloneable {

private TopbarConfiguration topbar;

private SidebarConfiguration sidebar;

private final long lastModified;

public NavigationConfiguration() {
this.lastModified = System.currentTimeMillis();
}

public NavigationConfiguration(TopbarConfiguration topbar, SidebarConfiguration sidebar) {
this.topbar = topbar;
this.sidebar = sidebar;
this.lastModified = System.currentTimeMillis();
}

public NavigationConfiguration(TopbarConfiguration topbar,
SidebarConfiguration sidebar,
long lastModified) {
this.topbar = topbar;
this.sidebar = sidebar;
this.lastModified = lastModified;
}

@Override
public NavigationConfiguration clone() { // NOSONAR
return new NavigationConfiguration(topbar == null ? null : topbar.clone(),
sidebar == null ? null : sidebar.clone());
sidebar == null ? null : sidebar.clone(),
lastModified);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,30 @@
*/
public interface SidebarPlugin {

/**
* @return {@link SidebarItemType} managed by the implementing plugin
*/
SidebarItemType getType();

/**
* Resolves Item Name and Icon when storage is maintained
*
* @param item
* @param username
* @param locale
*/
SidebarItem resolveProperties(SidebarItem item, Locale locale);
SidebarItem resolveProperties(SidebarItem item, String username, Locale locale);

/**
* @return {@link List} of {@link SidebarItem} to inject on startup
*/
List<SidebarItem> getDefaultItems();

boolean itemExists(SidebarItem item);
/**
* @param item {@link SidebarItem}
* @param username User name
* @return true if the item exists and the user has access to it, else false
*/
boolean itemExists(SidebarItem item, String username);

}
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,15 @@ default ListAccess<Space> getLastAccessedSpace(String remoteId) {
throw new UnsupportedOperationException();
}

/**
* @param username
* @param spaceFilter
* @return
*/
default ListAccess<Space> getLastAccessedSpaceByFilter(String username, SpaceFilter spaceFilter) {
throw new UnsupportedOperationException();
}

/**
* Registers a space lifecycle listener.
*
Expand Down
2 changes: 1 addition & 1 deletion component/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<name>Meeds:: PLF:: Social Core Component</name>
<description>Meeds Social Core Component: People and Space</description>
<properties>
<exo.test.coverage.ratio>0.70</exo.test.coverage.ratio>
<exo.test.coverage.ratio>0.69</exo.test.coverage.ratio>
</properties>
<dependencies>
<!-- These dependency is required to compile but reported as useless by mvn dependency:analyze -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2024 Meeds Association [email protected]
*
* 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.social.navigation.plugin;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.exoplatform.social.core.search.Sorting;
import org.exoplatform.social.core.search.Sorting.OrderBy;
import org.exoplatform.social.core.search.Sorting.SortBy;
import org.exoplatform.social.core.space.SpaceFilter;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;

import io.meeds.social.navigation.constant.SidebarItemType;
import io.meeds.social.navigation.model.SidebarItem;

import lombok.SneakyThrows;

public abstract class AbstractSpaceSidebarPlugin implements SidebarPlugin {

public static final int SPACES_LIMIT_DEFAULT = 4;

public static final String SPACES_LIMIT = "limit";

public static final String SPACES_SORT_BY = "sortBy";

@Autowired
private SpaceService spaceService;

protected abstract void buildSpaceFilter(SidebarItem item, SpaceFilter spaceFilter);

protected List<SidebarItem> getSpaces(SidebarItem item, String username) {
SpaceFilter spaceFilter = new SpaceFilter();
SidebarSpaceSortBy sortBy = getSortBy(item);
spaceFilter.setSorting(getSorting(item, sortBy));
spaceFilter.setRemoteId(username);
buildSpaceFilter(item, spaceFilter);
int limit = getLimit(item);
Space[] spaces = getSpaces(item, spaceFilter, username, sortBy, limit);
return Arrays.stream(spaces).map(this::toSidebarItem).toList();
}

protected SidebarItem toSidebarItem(Space space) {
return new SidebarItem(space.getDisplayName(),
"/portal/s/" + space.getId(),
null,
space.getAvatarUrl(),
null,
SidebarItemType.SPACE,
null,
Collections.singletonMap("id", space.getId()));
}

private SortBy getSortField(SidebarItem item, SidebarSpaceSortBy sortBy) { // NOSONAR
return Sorting.SortBy.TITLE;
}

private OrderBy getSortDirection(SidebarItem item, SidebarSpaceSortBy sortBy) { // NOSONAR
return sortBy == SidebarSpaceSortBy.LAST_ACCESS ? OrderBy.DESC : OrderBy.ASC;
}

private SidebarSpaceSortBy getSortByField(String sortByProperty) {
return StringUtils.isBlank(sortByProperty) ? SidebarSpaceSortBy.TITLE :
SidebarSpaceSortBy.valueOf(sortByProperty);
}

private Sorting getSorting(SidebarItem item, SidebarSpaceSortBy sortBy) {
return new Sorting(getSortField(item, sortBy), getSortDirection(item, sortBy));
}

@SneakyThrows
private Space[] getSpaces(SidebarItem item, SpaceFilter spaceFilter, String username, SidebarSpaceSortBy sortBy, int limit) {
if (limit <= 0) {
return new Space[0];
}
return switch (sortBy) {
case TITLE: {
yield spaceService.getMemberSpacesByFilter(username, spaceFilter).load(0, limit);
}
case FAVORITE: {
yield spaceService.getFavoriteSpacesByFilter(username, spaceFilter).load(0, limit);
}
case LAST_ACCESS: {
yield spaceService.getLastAccessedSpaceByFilter(username, spaceFilter).load(0, limit);
}
default:
yield new Space[0];
};
}

private SidebarSpaceSortBy getSortBy(SidebarItem item) {
String sortByProperty = item.getProperties().get(SPACES_SORT_BY);
return getSortByField(sortByProperty);
}

private int getLimit(SidebarItem item) {
String limitProperty = item.getProperties().get(SPACES_LIMIT);
return StringUtils.isBlank(limitProperty) ? SPACES_LIMIT_DEFAULT : Integer.parseInt(limitProperty);
}

protected enum SidebarSpaceSortBy {
TITLE, FAVORITE, LAST_ACCESS;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@ public List<SidebarItem> getDefaultItems() {
}

@Override
public SidebarItem resolveProperties(SidebarItem item, Locale locale) {
public SidebarItem resolveProperties(SidebarItem item, String username, Locale locale) {
return item;
}

@Override
public boolean itemExists(SidebarItem item) {
public boolean itemExists(SidebarItem item, String username) {
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@
import java.util.ResourceBundle;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import org.exoplatform.commons.utils.ExpressionUtil;
import org.exoplatform.portal.config.UserACL;
import org.exoplatform.portal.config.model.Page;
import org.exoplatform.portal.config.model.PortalConfig;
import org.exoplatform.portal.mop.SiteKey;
import org.exoplatform.portal.mop.State;
Expand Down Expand Up @@ -82,6 +83,9 @@ public class PageSidebarPlugin implements SidebarPlugin {
@Autowired
private ResourceBundleManager resourceBundleManager;

@Autowired
private UserACL userAcl;

public static SidebarItem resolveProperties(NavigationService navigationService, // NOSONAR
LayoutService layoutService,
TranslationService translationService,
Expand Down Expand Up @@ -159,7 +163,7 @@ public SidebarItemType getType() {
}

@Override
public SidebarItem resolveProperties(SidebarItem item, Locale locale) {
public SidebarItem resolveProperties(SidebarItem item, String username, Locale locale) {
return resolveProperties(navigationService,
layoutService,
translationService,
Expand All @@ -176,9 +180,29 @@ public List<SidebarItem> getDefaultItems() {
}

@Override
public boolean itemExists(SidebarItem item) {
String nodeId = item.getProperties().get(NODE_ID_PROP_NAME);
return StringUtils.isNoneBlank(nodeId) && navigationService.getNodeById(Long.parseLong(nodeId)) != null;
public boolean itemExists(SidebarItem item, String username) {
String nodeIdProperty = item.getProperties().get(NODE_ID_PROP_NAME);
long nodeId = Long.parseLong(nodeIdProperty);
NodeData node = navigationService.getNodeById(nodeId);
if (node == null) {
return false;
} else {
PortalConfig site = layoutService.getPortalConfig(node.getSiteKey());
if (!userAcl.hasAccessPermission(site, userAcl.getUserIdentity(username))) {
return false;
} else if (node.getState() == null
|| node.getState().getPageRef() == null
|| !SiteSidebarPlugin.isVisibilityEligible(node.getState())) {
return false;
} else {
Page page = layoutService.getPage(node.getState().getPageRef());
if (page == null) {
return false;
} else {
return userAcl.hasAccessPermission(page, userAcl.getUserIdentity(username));
}
}
}
}

private static String getLocaleName(Locale locale) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
package io.meeds.social.navigation.plugin;

import static io.meeds.social.navigation.plugin.PageSidebarPlugin.*;
import static io.meeds.social.navigation.plugin.PageSidebarPlugin.NODE_ID_PROP_NAME;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -38,6 +38,7 @@

import org.exoplatform.commons.utils.ExpressionUtil;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.portal.config.UserACL;
import org.exoplatform.portal.config.UserPortalConfigService;
import org.exoplatform.portal.config.model.PortalConfig;
import org.exoplatform.portal.mop.SiteFilter;
Expand Down Expand Up @@ -100,13 +101,16 @@ public class SiteSidebarPlugin implements SidebarPlugin {
@Autowired
private LocaleConfigService localeConfigService;

@Autowired
private UserACL userAcl;

@Override
public SidebarItemType getType() {
return SidebarItemType.SITE;
}

@Override
public SidebarItem resolveProperties(SidebarItem item, Locale locale) {
public SidebarItem resolveProperties(SidebarItem item, String username, Locale locale) {
String siteId = item.getProperties().get(SITE_ID_PROP_NAME);
String label = translationService.getTranslationLabelOrDefault(SITE_OBJECT_TYPE,
Long.parseLong(siteId),
Expand Down Expand Up @@ -173,10 +177,11 @@ public List<SidebarItem> getDefaultItems() {
}

@Override
public boolean itemExists(SidebarItem item) {
public boolean itemExists(SidebarItem item, String username) {
String siteType = item.getProperties().get(SITE_TYPE_PROP_NAME);
String siteName = item.getProperties().get(SITE_NAME_PROP_NAME);
return layoutService.getPortalConfig(siteType, siteName) != null;
PortalConfig site = layoutService.getPortalConfig(siteType, siteName);
return site != null && userAcl.hasAccessPermission(site, userAcl.getUserIdentity(username));
}

protected SidebarItem toSidebarItem(SiteKey siteKey) {
Expand Down Expand Up @@ -266,7 +271,7 @@ private ResourceBundle getBundle(String siteType, String siteName, Locale locale
siteName);
}

private static boolean isVisibilityEligible(NodeState state) {
public static boolean isVisibilityEligible(NodeState state) {
if (state.getVisibility() == Visibility.DISPLAYED) {
return true;
} else if (state.getVisibility() == Visibility.TEMPORAL) {
Expand Down
Loading

0 comments on commit 751f1e7

Please sign in to comment.