Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion component/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-component-api</artifactId>
<name>Meeds:: PLF:: Social API</name>
Expand Down
2 changes: 1 addition & 1 deletion component/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<groupId>io.meeds.social</groupId>
<artifactId>social-component-common</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion component/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-component-core</artifactId>
<name>Meeds:: PLF:: Social Core Component</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@

import java.util.List;

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

import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;

import io.meeds.social.category.model.CategoryObject;
import io.meeds.social.category.plugin.CategoryPlugin;

@Component
Expand All @@ -35,6 +41,9 @@
@Autowired
private SpaceService spaceService;

@Autowired
private IdentityManager identityManager;

@Override
public String getType() {
return OBJECT_TYPE;
Expand All @@ -55,4 +64,63 @@
return spaceService.getSpaceCategoryIds();
}

/**
* Normalizes the identifier carried by the incoming {@link CategoryObject} to
* the canonical space technical id ({@link Space#getSpaceId()}) before the
* link is stored, read back or broadcast. Category links are stored generically
* on {@code (type, id)}, but the space UI/REST relies on the denormalized
* {@code space.getCategoryIds()} that is only kept in sync by
* {@code CategoryLinkModifiedListener}, whose SPACE branch resolves the space
* through {@code spaceService.getSpaceById(object.getId())} and therefore
* requires the technical id. Callers (e.g. the MCP tooling) may pass the space
* identity id or its pretty name instead; normalizing here makes the write, the
* read-back and the denormalization listener all agree whichever id form was
* supplied.
*
* @param categoryObject The incoming {@link CategoryObject} whose id may be a
* space technical id, a social {@link Identity} id or a pretty name
* @return A {@link CategoryObject} carrying the canonical space technical id,
* or the object unchanged when the id cannot be resolved to a space
**/
@Override
public CategoryObject getObject(CategoryObject categoryObject) {
Space space = resolveSpace(categoryObject.getId());
if (space == null) {
return categoryObject;
}
return new CategoryObject(categoryObject.getType(),
String.valueOf(space.getSpaceId()),
categoryObject.getParentId(),
categoryObject.getSpaceId());
}

/**
* Resolves a {@link Space} from any of the id forms a space can be referenced
* by across the platform: a space technical id, a social {@link Identity} id
* (mapped to its space through the space identity provider's remote id, i.e.
* the space pretty name) or a pretty name. This mirrors the space resolution
* idiom used by {@code SpacePermanentLinkPlugin#getDirectAccessUrl}.
*
* @param id A space technical id, social {@link Identity} id or pretty name
* @return The resolved {@link Space}, or {@code null} when none matches
**/
private Space resolveSpace(String id) {
if (StringUtils.isBlank(id)) {
return null;
}
if (StringUtils.isNumeric(id)) {
Space space = spaceService.getSpaceById(id);
if (space != null) {
return space;
}
// Fall back to a social Identity id pointing at the space
Identity identity = identityManager.getIdentity(id);

Check warning on line 117 in component/core/src/main/java/io/meeds/social/space/plugin/SpaceCategoryPlugin.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this call to a deprecated method, it has been marked for removal.

See more on https://sonarcloud.io/project/issues?id=io.meeds.social&issues=AZ980ise_8yZka3MBxDw&open=AZ980ise_8yZka3MBxDw&pullRequest=5895
if (identity != null && SpaceIdentityProvider.NAME.equals(identity.getProviderId())) {
return spaceService.getSpaceByPrettyName(identity.getRemoteId());
}
return null;
}
return spaceService.getSpaceByPrettyName(id);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.Collections;
import java.util.Locale;

import org.apache.commons.collections4.CollectionUtils;
import org.junit.Test;

import org.exoplatform.commons.ObjectAlreadyExistsException;
Expand Down Expand Up @@ -129,4 +130,30 @@ public void testUnLink() {
assertFalse(categoryLinkService.isLinked(rootCategory.getId(), object));
}

@Test
@SneakyThrows
public void testLinkBySpaceIdentityIdDenormalizesCategoryIds() {
Space space = new Space();
space.setRegistration(Space.OPEN);
space.setVisibility(Space.PUBLIC);
space = spaceService.createSpace(space, ROOT_USER);

Category rootCategory = categoryService.getRootCategory(getAdminGroupIdentityId());

// Link the space using its social Identity id (how spaces are referenced
// across the platform) instead of its technical id, as the MCP tooling does
String spaceIdentityId = identityManager.getOrCreateSpaceIdentity(space.getPrettyName()).getId();
CategoryObject object = new CategoryObject(SpaceCategoryPlugin.OBJECT_TYPE, spaceIdentityId, space.getSpaceId());
categoryLinkService.link(rootCategory.getId(), object, ROOT_USER);

// The link is stored/read-back under the normalized technical id
assertTrue(categoryLinkService.isLinked(rootCategory.getId(), object));

// And the denormalization listener kept space.categoryIds in sync
restartTransaction();
Space updatedSpace = spaceService.getSpaceById(space.getId());
assertTrue(CollectionUtils.isNotEmpty(updatedSpace.getCategoryIds())
&& updatedSpace.getCategoryIds().contains(rootCategory.getId()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2025 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.social.space.plugin;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;

import io.meeds.social.category.model.CategoryObject;

@SpringBootTest(classes = {
SpaceCategoryPlugin.class,
})
@RunWith(SpringRunner.class)
public class SpaceCategoryPluginUnitTest {

private static final long SPACE_TECHNICAL_ID = 42l;

private static final long SPACE_IDENTITY_ID = 74456l;

private static final String SPACE_PRETTY_NAME = "prettyName";

@MockBean

Check warning on line 53 in component/core/src/test/java/io/meeds/social/space/plugin/SpaceCategoryPluginUnitTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this call to a deprecated class, it has been marked for removal.

See more on https://sonarcloud.io/project/issues?id=io.meeds.social&issues=AZ980ixM_8yZka3MBxDx&open=AZ980ixM_8yZka3MBxDx&pullRequest=5895
private SpaceService spaceService;

@MockBean

Check warning on line 56 in component/core/src/test/java/io/meeds/social/space/plugin/SpaceCategoryPluginUnitTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this call to a deprecated class, it has been marked for removal.

See more on https://sonarcloud.io/project/issues?id=io.meeds.social&issues=AZ980ixM_8yZka3MBxDy&open=AZ980ixM_8yZka3MBxDy&pullRequest=5895
private IdentityManager identityManager;

@Autowired
private SpaceCategoryPlugin spaceCategoryPlugin;

@Test
public void testGetObjectNormalizesTechnicalId() {
Space space = newSpace();
when(spaceService.getSpaceById(String.valueOf(SPACE_TECHNICAL_ID))).thenReturn(space);

CategoryObject object = new CategoryObject(SpaceCategoryPlugin.OBJECT_TYPE, String.valueOf(SPACE_TECHNICAL_ID), 0l);
CategoryObject normalized = spaceCategoryPlugin.getObject(object);

assertEquals(String.valueOf(SPACE_TECHNICAL_ID), normalized.getId());
assertEquals(SpaceCategoryPlugin.OBJECT_TYPE, normalized.getType());
}

@Test
public void testGetObjectNormalizesIdentityIdToTechnicalId() {
Space space = newSpace();
// The identity id is not a space technical id
when(spaceService.getSpaceById(String.valueOf(SPACE_IDENTITY_ID))).thenReturn(null);
Identity identity = mock(Identity.class);
when(identity.getProviderId()).thenReturn(SpaceIdentityProvider.NAME);
when(identity.getRemoteId()).thenReturn(SPACE_PRETTY_NAME);
when(identityManager.getIdentity(String.valueOf(SPACE_IDENTITY_ID))).thenReturn(identity);

Check warning on line 82 in component/core/src/test/java/io/meeds/social/space/plugin/SpaceCategoryPluginUnitTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this call to a deprecated method, it has been marked for removal.

See more on https://sonarcloud.io/project/issues?id=io.meeds.social&issues=AZ980ixM_8yZka3MBxDz&open=AZ980ixM_8yZka3MBxDz&pullRequest=5895
when(spaceService.getSpaceByPrettyName(SPACE_PRETTY_NAME)).thenReturn(space);

CategoryObject object = new CategoryObject(SpaceCategoryPlugin.OBJECT_TYPE, String.valueOf(SPACE_IDENTITY_ID), 0l);
CategoryObject normalized = spaceCategoryPlugin.getObject(object);

assertEquals(String.valueOf(SPACE_TECHNICAL_ID), normalized.getId());
}

@Test
public void testGetObjectNormalizesPrettyNameToTechnicalId() {
Space space = newSpace();
when(spaceService.getSpaceByPrettyName(SPACE_PRETTY_NAME)).thenReturn(space);

CategoryObject object = new CategoryObject(SpaceCategoryPlugin.OBJECT_TYPE, SPACE_PRETTY_NAME, 0l);
CategoryObject normalized = spaceCategoryPlugin.getObject(object);

assertEquals(String.valueOf(SPACE_TECHNICAL_ID), normalized.getId());
}

@Test
public void testGetObjectReturnsSameObjectWhenUnresolvable() {
when(spaceService.getSpaceById("unknown")).thenReturn(null);
when(spaceService.getSpaceByPrettyName("unknown")).thenReturn(null);

CategoryObject object = new CategoryObject(SpaceCategoryPlugin.OBJECT_TYPE, "unknown", 0l);
CategoryObject normalized = spaceCategoryPlugin.getObject(object);

assertSame(object, normalized);
}

private Space newSpace() {
Space space = new Space();
space.setId(String.valueOf(SPACE_TECHNICAL_ID));
space.setPrettyName(SPACE_PRETTY_NAME);
return space;
}

}
2 changes: 1 addition & 1 deletion component/notification/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-component-notification</artifactId>
<name>Meeds:: PLF:: Social Notification Component</name>
Expand Down
2 changes: 1 addition & 1 deletion component/oauth-auth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion component/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-component</artifactId>
<packaging>pom</packaging>
Expand Down
2 changes: 1 addition & 1 deletion component/service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-component-service</artifactId>
<name>Meeds:: PLF:: Social Service Component</name>
Expand Down
2 changes: 1 addition & 1 deletion component/web/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<artifactId>social-component</artifactId>
<groupId>io.meeds.social</groupId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<groupId>io.meeds.social</groupId>
<artifactId>social-component-web</artifactId>
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</parent>
<groupId>io.meeds.social</groupId>
<artifactId>social</artifactId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Meeds:: PLF:: Social</name>
<description>Meeds Social - Enterprise Social Networking</description>
Expand All @@ -45,8 +45,8 @@
<!-- **************************************** -->
<!-- Project Dependencies -->
<!-- **************************************** -->
<io.meeds.commons.version>7.3.x-SNAPSHOT</io.meeds.commons.version>
<io.meeds.platform-ui.version>7.3.x-SNAPSHOT</io.meeds.platform-ui.version>
<io.meeds.commons.version>7.3.x-ai-contribution-SNAPSHOT</io.meeds.commons.version>
<io.meeds.platform-ui.version>7.3.x-ai-contribution-SNAPSHOT</io.meeds.platform-ui.version>

<!-- Sonar properties -->
<sonar.organization>meeds-io</sonar.organization>
Expand Down
2 changes: 1 addition & 1 deletion webapp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>io.meeds.social</groupId>
<artifactId>social</artifactId>
<version>7.3.x-SNAPSHOT</version>
<version>7.3.x-ai-contribution-SNAPSHOT</version>
</parent>
<artifactId>social-webapp</artifactId>
<packaging>war</packaging>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default {
drawer: false,
backgroundProperties: null,
defaultCustomPageWidth: '1320',
defaultPageBackground: '#F0F0F0',
defaultPageBackground: '#F0F0F0FF',
pageWidth: null,
borderRadius: null,
defaultPageStylingProperties: null,
Expand Down Expand Up @@ -164,7 +164,7 @@ export default {
methods: {
init() {
this.backgroundProperties = {
backgroundColor: this.pageStylingProperties?.pageBackgroundColor || this.defaultPageBackground,
backgroundColor: this.normalizeBackgroundColor(this.pageStylingProperties?.pageBackgroundColor) || this.defaultPageBackground,
backgroundPosition: this.pageStylingProperties?.pageBackgroundPosition || null,
background: this.pageStylingProperties?.pageBackground || null,
backgroundRepeat: this.pageStylingProperties?.pageBackgroundRepeat || null,
Expand Down Expand Up @@ -205,6 +205,12 @@ export default {
this.reset();
this.$refs.drawer.close();
},
normalizeBackgroundColor(color) {
if (!color) {
return color;
}
return color.length === 7 ? `${color}FF` : color;
},
getPageBackgroundEffect() {
const effect = this.pageStylingProperties?.pageBackgroundEffect;
if (!effect || effect === 'none') {
Expand Down
Loading
Loading