Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow to retrieve I18N keys for Sites Name and Description in UI - MEED-3342 - Meeds-io/meeds#1629 #219

Merged
merged 1 commit into from
Sep 16, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.exoplatform.portal.mop.SiteKey;
import org.exoplatform.social.rest.entity.SiteEntity;

import io.meeds.layout.model.NodeLabel;
import io.meeds.layout.model.PermissionUpdateModel;
import io.meeds.layout.model.SiteCreateModel;
import io.meeds.layout.model.SiteUpdateModel;
Expand Down Expand Up @@ -237,4 +238,46 @@ public ResponseEntity<SiteEntity> createSite(
}
}

@GetMapping("{siteId}/labels")
@Operation(summary = "Retrieve site I18N labels", method = "GET", description = "This retrieves site labels")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Request fulfilled"),
@ApiResponse(responseCode = "403", description = "Forbidden"),
@ApiResponse(responseCode = "404", description = "Not found"),
})
public NodeLabel getSiteLabels(
HttpServletRequest request,
@Parameter(description = "Site id", required = true)
@PathVariable("siteId")
Long siteId) {
try {
return siteLayoutService.getSiteLabels(siteId, request.getRemoteUser());
} catch (ObjectNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
} catch (IllegalAccessException e) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, e.getMessage());
}
}

@GetMapping("{siteId}/descriptions")
@Operation(summary = "Retrieve site I18N descriptions", method = "GET", description = "This retrieves site descriptions")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Request fulfilled"),
@ApiResponse(responseCode = "403", description = "Forbidden"),
@ApiResponse(responseCode = "404", description = "Not found"),
})
public NodeLabel getSiteDescriptions(
HttpServletRequest request,
@Parameter(description = "Site id", required = true)
@PathVariable("siteId")
Long siteId) {
try {
return siteLayoutService.getSiteDescriptions(siteId, request.getRemoteUser());
} catch (ObjectNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
} catch (IllegalAccessException e) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,31 @@
*/
package io.meeds.layout.service;

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.exoplatform.commons.ObjectAlreadyExistsException;
import org.exoplatform.commons.exception.ObjectNotFoundException;
import org.exoplatform.portal.config.UserPortalConfig;
import org.exoplatform.portal.config.UserPortalConfigService;
import org.exoplatform.portal.config.model.PortalConfig;
import org.exoplatform.portal.mop.SiteKey;
import org.exoplatform.portal.mop.SiteType;
import org.exoplatform.portal.mop.service.LayoutService;
import org.exoplatform.portal.mop.user.UserPortal;
import org.exoplatform.services.resources.LocaleConfig;
import org.exoplatform.services.resources.LocaleConfigService;
import org.exoplatform.services.resources.LocaleContextInfo;

import io.meeds.layout.model.NodeLabel;
import io.meeds.layout.model.PermissionUpdateModel;
import io.meeds.layout.model.SiteCreateModel;
import io.meeds.layout.model.SiteUpdateModel;
Expand All @@ -41,12 +55,19 @@ public class SiteLayoutService {
@Autowired
private LayoutService layoutService;

@Autowired
private LocaleConfigService localeConfigService;

@Autowired
private UserPortalConfigService portalConfigService;

@Autowired
private LayoutAclService aclService;

private Map<String, String> supportedLanguages;

private Locale defaultConfiguredLocale;

public PortalConfig getSite(long siteId, String username) throws ObjectNotFoundException, IllegalAccessException {
PortalConfig portalConfig = layoutService.getPortalConfig(siteId);
if (portalConfig == null) {
Expand Down Expand Up @@ -153,6 +174,76 @@ public void updateSitePermissions(PermissionUpdateModel permissionUpdateModel,
layoutService.save(portalConfig);
}

public NodeLabel getSiteLabels(Long siteId, String username) throws ObjectNotFoundException, IllegalAccessException {
return getSiteLabel(siteId, username, true);
}

public NodeLabel getSiteDescriptions(Long siteId, String username) throws ObjectNotFoundException, IllegalAccessException {
return getSiteLabel(siteId, username, false);
}

private NodeLabel getSiteLabel(long siteId, String username, boolean isLabel) throws ObjectNotFoundException,
IllegalAccessException {
PortalConfig portalConfig = layoutService.getPortalConfig(siteId);
if (portalConfig == null) {
throw new ObjectNotFoundException(String.format("Site with id %s doesn't exists", siteId));
} else if (!aclService.canViewSite(new SiteKey(portalConfig.getType(), portalConfig.getName()), username)) {
throw new IllegalAccessException();
}
Locale defaultLocale = getDefaultLocale();

NodeLabel nodeLabel = new NodeLabel();
nodeLabel.setDefaultLanguage(defaultLocale.getLanguage());
nodeLabel.setSupportedLanguages(getSupportedLanguages(defaultLocale));
Map<String, String> labels = getLabels(portalConfig, defaultLocale, username, isLabel);
nodeLabel.setLabels(labels);
return nodeLabel;
}

private Map<String, String> getLabels(PortalConfig portalConfig, Locale defaultLocale, String username, boolean isLabel) {
SiteKey siteKey = new SiteKey(SiteType.valueOf(portalConfig.getType().toUpperCase()), portalConfig.getName());
UserPortalConfig userPortalConfig = portalConfigService.getUserPortalConfig(siteKey.getName(), username);
UserPortal userPortal = userPortalConfig.getUserPortal();

Map<String, String> labels = new HashMap<>();
localeConfigService.getLocalConfigs()
.stream()
.map(LocaleConfig::getLocale)
.forEach(locale -> {
String translatedLabel = isLabel ? userPortal.getPortalLabel(siteKey, locale) :
userPortal.getPortalDescription(siteKey, locale);
labels.put(LocaleContextInfo.getLocaleAsString(locale), translatedLabel);
});
if (!labels.containsKey(defaultLocale.getLanguage()) && !labels.isEmpty()) {
labels.put(defaultLocale.getLanguage(), labels.values().iterator().next());
}
return labels;
}

private Map<String, String> getSupportedLanguages(Locale defaultLocale) {
if (supportedLanguages == null || !defaultConfiguredLocale.equals(defaultLocale)) {
supportedLanguages = CollectionUtils.isEmpty(localeConfigService.getLocalConfigs()) ?
Collections.singletonMap(defaultLocale.toLanguageTag(),
defaultLocale.getDisplayName()) :
localeConfigService.getLocalConfigs()
.stream()
.filter(localeConfig -> !StringUtils.equals(localeConfig.getLocale()
.toLanguageTag(),
"ma"))
.map(LocaleConfig::getLocale)
.collect(Collectors.toMap(Locale::toLanguageTag,
Locale::getDisplayName));
defaultConfiguredLocale = defaultLocale;
}
return supportedLanguages;
}

private Locale getDefaultLocale() {
return localeConfigService.getDefaultLocaleConfig() == null ? Locale.ENGLISH :
localeConfigService.getDefaultLocaleConfig()
.getLocale();
}

private String getAdministratorsPermission() {
return "*:" + aclService.getAdministratorsGroup();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package io.meeds.layout.rest;

import static io.meeds.layout.util.JsonUtils.toJsonString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -51,12 +52,6 @@
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import org.exoplatform.commons.exception.ObjectNotFoundException;

import io.meeds.layout.model.PageTemplate;
Expand All @@ -65,7 +60,6 @@
import io.meeds.spring.web.security.WebSecurityConfiguration;

import jakarta.servlet.Filter;
import lombok.SneakyThrows;

@SpringBootTest(classes = { PageTemplateRest.class, PortalAuthenticationManager.class, })
@ContextConfiguration(classes = { WebSecurityConfiguration.class })
Expand All @@ -80,18 +74,6 @@ public class PageTemplateRestTest {

private static final String TEST_PASSWORD = "testPassword";

static final ObjectMapper OBJECT_MAPPER;

static {
// Workaround when Jackson is defined in shared library with different
// version and without artifact jackson-datatype-jsr310
OBJECT_MAPPER = JsonMapper.builder()
.configure(JsonReadFeature.ALLOW_MISSING_VALUES, true)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.build();
OBJECT_MAPPER.registerModule(new JavaTimeModule());
}

@MockBean
private PageTemplateService pageTemplateService;

Expand Down Expand Up @@ -140,7 +122,7 @@ void getPageTemplateWithUser() throws Exception {

@Test
void createPageTemplateAnonymously() throws Exception {
ResultActions response = mockMvc.perform(post(REST_PATH).content(asJsonString(new PageTemplate()))
ResultActions response = mockMvc.perform(post(REST_PATH).content(toJsonString(new PageTemplate()))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isForbidden());
verifyNoInteractions(pageTemplateService);
Expand All @@ -150,7 +132,7 @@ void createPageTemplateAnonymously() throws Exception {
void createPageTemplateWithUser() throws Exception {
PageTemplate pageTemplate = new PageTemplate();
ResultActions response = mockMvc.perform(post(REST_PATH).with(testSimpleUser())
.content(asJsonString(pageTemplate))
.content(toJsonString(pageTemplate))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isOk());
verify(pageTemplateService).createPageTemplate(pageTemplate, SIMPLE_USER);
Expand All @@ -162,14 +144,14 @@ void createPageTemplateWithUserForbidden() throws Exception {
when(pageTemplateService.createPageTemplate(pageTemplate, SIMPLE_USER)).thenThrow(IllegalAccessException.class);

ResultActions response = mockMvc.perform(post(REST_PATH).with(testSimpleUser())
.content(asJsonString(pageTemplate))
.content(toJsonString(pageTemplate))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isForbidden());
}

@Test
void updatePageTemplateAnonymously() throws Exception {
ResultActions response = mockMvc.perform(put(REST_PATH + "/1").content(asJsonString(new PageTemplate()))
ResultActions response = mockMvc.perform(put(REST_PATH + "/1").content(toJsonString(new PageTemplate()))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isForbidden());
verifyNoInteractions(pageTemplateService);
Expand All @@ -179,7 +161,7 @@ void updatePageTemplateAnonymously() throws Exception {
void updatePageTemplateWithUser() throws Exception {
PageTemplate pageTemplate = new PageTemplate();
ResultActions response = mockMvc.perform(put(REST_PATH + "/1").with(testSimpleUser())
.content(asJsonString(pageTemplate))
.content(toJsonString(pageTemplate))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isOk());

Expand All @@ -194,7 +176,7 @@ void updatePageTemplateWithUserForbidden() throws Exception {
when(pageTemplateService.updatePageTemplate(pageTemplate, SIMPLE_USER)).thenThrow(IllegalAccessException.class);

ResultActions response = mockMvc.perform(put(REST_PATH + "/1").with(testSimpleUser())
.content(asJsonString(pageTemplate))
.content(toJsonString(pageTemplate))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isForbidden());
}
Expand All @@ -206,7 +188,7 @@ void updatePageTemplateWithUserNotFound() throws Exception {
when(pageTemplateService.updatePageTemplate(pageTemplate, SIMPLE_USER)).thenThrow(ObjectNotFoundException.class);

ResultActions response = mockMvc.perform(put(REST_PATH + "/1").with(testSimpleUser())
.content(asJsonString(pageTemplate))
.content(toJsonString(pageTemplate))
.contentType(MediaType.APPLICATION_JSON));
response.andExpect(status().isNotFound());
}
Expand Down Expand Up @@ -253,9 +235,4 @@ private RequestPostProcessor testSimpleUser() {
.authorities(new SimpleGrantedAuthority("users"));
}

@SneakyThrows
public static String asJsonString(final Object obj) {
return OBJECT_MAPPER.writeValueAsString(obj);
}

}
Loading