diff --git a/content-service/pom.xml b/content-service/pom.xml index dacb47499..f4b7a7c6d 100644 --- a/content-service/pom.xml +++ b/content-service/pom.xml @@ -36,7 +36,7 @@ 1.0 Content addon used Rest endpoints - 0.53 + 0.51 @@ -78,10 +78,8 @@ io.openapitools.swagger swagger-maven-plugin - true - - io.meeds.news.rest - + io.meeds.news.rest.NewsRest + io.meeds.news.rest.NewsTargetingRest ${rest.api.doc.title} diff --git a/content-service/src/main/java/io/meeds/news/activity/processor/ActivityNewsProcessor.java b/content-service/src/main/java/io/meeds/news/activity/processor/ActivityNewsProcessor.java index 968cde7db..8506940e4 100644 --- a/content-service/src/main/java/io/meeds/news/activity/processor/ActivityNewsProcessor.java +++ b/content-service/src/main/java/io/meeds/news/activity/processor/ActivityNewsProcessor.java @@ -20,9 +20,14 @@ package io.meeds.news.activity.processor; import java.util.HashMap; +import java.util.List; +import java.util.Map; +import jakarta.annotation.PostConstruct; +import liquibase.util.CollectionUtil; import org.apache.commons.lang3.math.NumberUtils; import org.exoplatform.container.xml.InitParams; +import org.exoplatform.container.xml.ValueParam; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.social.common.RealtimeListAccess; @@ -33,21 +38,37 @@ import io.meeds.news.model.News; import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; -import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; - +@Component public class ActivityNewsProcessor extends BaseActivityProcessorPlugin { - private static final Log LOG = ExoLogger.getLogger(ActivityNewsProcessor.class); + private static final Log LOG = ExoLogger.getLogger(ActivityNewsProcessor.class); + + private static final String ACTIVITY_PROCESSOR_NAME = "ActivityNewsProcessor"; + + private static final int processorPriority = 30; - private NewsService newsService; + @Autowired + private NewsService newsService; + + @Autowired + private ActivityManager activityManager; + + public ActivityNewsProcessor() { + super(getInitParams()); + } - private ActivityManager activityManager; + @PostConstruct + public void init() { + activityManager.addProcessorPlugin(this); + } - public ActivityNewsProcessor(ActivityManager activityManager, NewsService newsService, InitParams initParams) { - super(initParams); - this.newsService = newsService; - this.activityManager = activityManager; + @Override + public String getName() { + return ACTIVITY_PROCESSOR_NAME; } @Override @@ -72,12 +93,35 @@ public void processActivity(ExoSocialActivity activity) { activity.setMetadataObjectId(news.getId()); activity.setMetadataObjectType(NewsUtils.NEWS_METADATA_OBJECT_TYPE); - news.setIllustration(null); } catch (Exception e) { LOG.warn("Error retrieving news with id {}", activity.getTemplateParams().get("newsId"), e); } activity.getLinkedProcessedEntities().put("news", news); + try { + String newsId = news.getId(); + List articleLanguages = newsService.getArticleLanguages(newsId, false); + if (!CollectionUtils.isEmpty(articleLanguages)) { + Map newsTranslations = new HashMap<>(); + articleLanguages.stream().forEach(articleLanguage -> { + News articleTranslation = newsService.getNewsArticleByIdAndLang(newsId, articleLanguage); + if (articleTranslation != null) { + newsTranslations.put("news_" + articleLanguage, articleTranslation); + } + }); + activity.getLinkedProcessedEntities().put("newsTranslations", newsTranslations); + } + } catch (Exception exception) { + LOG.error("Error when adding the news translation to the activity linked processed entities", exception); + } } } + private static InitParams getInitParams() { + InitParams initParams = new InitParams(); + ValueParam param = new ValueParam(); + param.setName("priority"); + param.setValue(String.valueOf(processorPriority)); + initParams.addParameter(param); + return initParams; + } } diff --git a/content-service/src/main/java/io/meeds/news/listener/AnalyticsNewsListener.java b/content-service/src/main/java/io/meeds/news/listener/AnalyticsNewsListener.java index f58a50029..7eacdce14 100644 --- a/content-service/src/main/java/io/meeds/news/listener/AnalyticsNewsListener.java +++ b/content-service/src/main/java/io/meeds/news/listener/AnalyticsNewsListener.java @@ -20,70 +20,77 @@ package io.meeds.news.listener; import static io.meeds.analytics.utils.AnalyticsUtils.addSpaceStatistics; +import static io.meeds.news.utils.NewsUtils.COMMENT_NEWS; +import static io.meeds.news.utils.NewsUtils.DELETE_NEWS; +import static io.meeds.news.utils.NewsUtils.LIKE_NEWS; +import static io.meeds.news.utils.NewsUtils.POST_NEWS; +import static io.meeds.news.utils.NewsUtils.SHARE_NEWS; +import static io.meeds.news.utils.NewsUtils.UPDATE_NEWS; +import static io.meeds.news.utils.NewsUtils.VIEW_NEWS; + +import jakarta.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; -import io.meeds.analytics.model.StatisticData; -import io.meeds.analytics.utils.AnalyticsUtils; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.services.listener.Asynchronous; import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; +import org.exoplatform.services.listener.ListenerService; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider; 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.analytics.model.StatisticData; +import io.meeds.analytics.utils.AnalyticsUtils; import io.meeds.news.model.News; import io.meeds.news.utils.NewsUtils; @Asynchronous +@Component +@Profile("analytics") public class AnalyticsNewsListener extends Listener { - private static final String CREATE_CONTENT_OPERATION_NAME = "createContent"; + private static final String CREATE_CONTENT_OPERATION_NAME = "createContent"; + + private static final String UPDATE_CONTENT_OPERATION_NAME = "updateContent"; + + private static final String DELETE_CONTENT_OPERATION_NAME = "deleteContent"; - private static final String UPDATE_CONTENT_OPERATION_NAME = "updateContent"; + private static final String VIEW_CONTENT_OPERATION_NAME = "viewContent"; - private static final String DELETE_CONTENT_OPERATION_NAME = "deleteContent"; + private static final String SHARE_CONTENT_OPERATION_NAME = "shareContent"; - private static final String VIEW_CONTENT_OPERATION_NAME = "viewContent"; + private static final String LIKE_CONTENT_OPERATION_NAME = "likeContent"; - private static final String SHARE_CONTENT_OPERATION_NAME = "shareContent"; + private static final String COMMENT_CONTENT_OPERATION_NAME = "commentContent"; - private static final String LIKE_CONTENT_OPERATION_NAME = "likeContent"; + private static final String[] LISTENER_EVENTS = { POST_NEWS, UPDATE_NEWS, DELETE_NEWS, VIEW_NEWS, SHARE_NEWS, COMMENT_NEWS, LIKE_NEWS }; - private static final String COMMENT_CONTENT_OPERATION_NAME = "commentContent"; + @Autowired + private IdentityManager identityManager; - private IdentityManager identityManager; + @Autowired + private SpaceService spaceService; - private SpaceService spaceService; + @Autowired + private ListenerService listenerService; + + @PostConstruct + public void init() { + for (String listener : LISTENER_EVENTS) { + listenerService.addListener(listener, this); + } + } @Override public void onEvent(Event event) throws Exception { News news = event.getData(); - String operation = ""; - switch (event.getEventName()) { - case "exo.news.postArticle": - operation = CREATE_CONTENT_OPERATION_NAME; - break; - case "exo.news.updateArticle": - operation = UPDATE_CONTENT_OPERATION_NAME; - break; - case "exo.news.deleteArticle": - operation = DELETE_CONTENT_OPERATION_NAME; - break; - case "exo.news.viewArticle": - operation = VIEW_CONTENT_OPERATION_NAME; - break; - case "exo.news.shareArticle": - operation = SHARE_CONTENT_OPERATION_NAME; - break; - case "exo.news.commentArticle": - operation = COMMENT_CONTENT_OPERATION_NAME; - break; - case "exo.news.likeArticle": - operation = LIKE_CONTENT_OPERATION_NAME; - break; - } + String operation = mapEventNameToOperation(event.getEventName()); long userId = 0; Identity identity = getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, event.getSource()); if (identity != null) { @@ -115,6 +122,27 @@ public void onEvent(Event event) throws Exception { AnalyticsUtils.addStatisticData(statisticData); } + private String mapEventNameToOperation(String eventName) { + switch (eventName) { + case "exo.news.postArticle": + return CREATE_CONTENT_OPERATION_NAME; + case "exo.news.updateArticle": + return UPDATE_CONTENT_OPERATION_NAME; + case "exo.news.deleteArticle": + return DELETE_CONTENT_OPERATION_NAME; + case "exo.news.viewArticle": + return VIEW_CONTENT_OPERATION_NAME; + case "exo.news.shareArticle": + return SHARE_CONTENT_OPERATION_NAME; + case "exo.news.commentArticle": + return COMMENT_CONTENT_OPERATION_NAME; + case "exo.news.likeArticle": + return LIKE_CONTENT_OPERATION_NAME; + default: + throw new IllegalArgumentException("Unknown event: " + eventName); + } + } + public IdentityManager getIdentityManager() { if (identityManager == null) { identityManager = ExoContainerContext.getService(IdentityManager.class); diff --git a/content-service/src/main/java/io/meeds/news/listener/AttachedActivityCacheUpdater.java b/content-service/src/main/java/io/meeds/news/listener/AttachedActivityCacheUpdater.java index 3c502f028..112580f44 100644 --- a/content-service/src/main/java/io/meeds/news/listener/AttachedActivityCacheUpdater.java +++ b/content-service/src/main/java/io/meeds/news/listener/AttachedActivityCacheUpdater.java @@ -23,25 +23,51 @@ import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; +import org.exoplatform.services.listener.ListenerService; import org.exoplatform.social.core.activity.model.ExoSocialActivity; import org.exoplatform.social.core.storage.api.ActivityStorage; import org.exoplatform.social.core.storage.cache.CachedActivityStorage; import io.meeds.news.model.News; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; + +import static io.meeds.news.utils.NewsUtils.ADD_ARTICLE_TRANSLATION; +import static io.meeds.news.utils.NewsUtils.POST_NEWS; +import static io.meeds.news.utils.NewsUtils.REMOVE_ARTICLE_TRANSLATION; +import static io.meeds.news.utils.NewsUtils.SCHEDULE_NEWS; +import static io.meeds.news.utils.NewsUtils.SHARE_NEWS; +import static io.meeds.news.utils.NewsUtils.UNSCHEDULE_NEWS; +import static io.meeds.news.utils.NewsUtils.UPDATE_NEWS; /** * A listener to clear cached news inside * {@link ExoSocialActivity#getLinkedProcessedEntities()} after any modification * made on {@link News} */ +@Component public class AttachedActivityCacheUpdater extends Listener { + @Autowired + private ActivityStorage activityStorage; + + @Autowired + private ListenerService listenerService; + private CachedActivityStorage cachedActivityStorage; - public AttachedActivityCacheUpdater(ActivityStorage activityStorage) { + private String[] LISTENER_EVENTS = { POST_NEWS, UPDATE_NEWS, SHARE_NEWS, SCHEDULE_NEWS, UNSCHEDULE_NEWS, ADD_ARTICLE_TRANSLATION, REMOVE_ARTICLE_TRANSLATION }; + + @PostConstruct + public void init() { if (activityStorage instanceof CachedActivityStorage) { this.cachedActivityStorage = (CachedActivityStorage) activityStorage; } + for (String listener : LISTENER_EVENTS) { + listenerService.addListener(listener, this); + } } @Override diff --git a/content-service/src/main/java/io/meeds/news/listener/MetadataItemModified.java b/content-service/src/main/java/io/meeds/news/listener/MetadataItemModified.java index 5dbbbddce..76fe05af8 100644 --- a/content-service/src/main/java/io/meeds/news/listener/MetadataItemModified.java +++ b/content-service/src/main/java/io/meeds/news/listener/MetadataItemModified.java @@ -24,6 +24,7 @@ import org.exoplatform.commons.search.index.IndexingService; import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; +import org.exoplatform.services.listener.ListenerService; import org.exoplatform.social.core.storage.api.ActivityStorage; import org.exoplatform.social.core.storage.cache.CachedActivityStorage; import org.exoplatform.social.metadata.model.MetadataItem; @@ -32,21 +33,38 @@ import io.meeds.news.search.NewsIndexingServiceConnector; import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import jakarta.annotation.PostConstruct; + +@Component public class MetadataItemModified extends Listener { + @Autowired private IndexingService indexingService; + @Autowired private NewsService newsService; + @Autowired + private ActivityStorage activityStorage; + + @Autowired + private ListenerService listenerService; + private CachedActivityStorage cachedActivityStorage; - public MetadataItemModified(NewsService newsService, IndexingService indexingService, ActivityStorage activityStorage) { - this.newsService = newsService; - this.indexingService = indexingService; + private String[] LISTENER_EVENTS = { "social.metadataItem.updated", "social.metadataItem.created", "social.metadataItem.deleted" }; + + @PostConstruct + public void init() { if (activityStorage instanceof CachedActivityStorage) { this.cachedActivityStorage = (CachedActivityStorage) activityStorage; } + for (String listener : LISTENER_EVENTS) { + listenerService.addListener(listener, this); + } } @Override @@ -57,7 +75,7 @@ public void onEvent(Event event) throws Exception { if (isNewsEvent(objectType)) { // Ensure to re-execute all ActivityProcessors to compute & cache // metadatas of the activity again - News news = newsService.getNewsById(objectId, false); + News news = newsService.getNewsArticleById(StringUtils.substringBefore(objectId, "-")); if (news != null) { if (StringUtils.isNotBlank(news.getActivityId())) { clearCache(news.getActivityId()); diff --git a/content-service/src/main/java/io/meeds/news/listener/NewsActivityListener.java b/content-service/src/main/java/io/meeds/news/listener/NewsActivityListener.java index af2666dba..a22c9ad96 100644 --- a/content-service/src/main/java/io/meeds/news/listener/NewsActivityListener.java +++ b/content-service/src/main/java/io/meeds/news/listener/NewsActivityListener.java @@ -34,6 +34,10 @@ import io.meeds.news.model.News; import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import jakarta.annotation.PostConstruct; +import org.springframework.stereotype.Component; import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; @@ -42,30 +46,29 @@ * propagate sharing activity in News elements to let targeted space members to * access News */ +@Component public class NewsActivityListener extends ActivityListenerPlugin { private static final Log LOG = ExoLogger.getLogger(NewsActivityListener.class); private static final String NEWS_ID = "newsId"; + @Autowired private ActivityManager activityManager; + @Autowired private IdentityManager identityManager; + @Autowired private SpaceService spaceService; + @Autowired private NewsService newsService; - public NewsActivityListener(ActivityManager activityManager, - IdentityManager identityManager, - SpaceService spaceService, - NewsService newsService) { - this.newsService = newsService; - this.spaceService = spaceService; - this.identityManager = identityManager; - this.activityManager = activityManager; + @PostConstruct + public void init() { + activityManager.addActivityEventListener(this); } - @Override public void shareActivity(ActivityLifeCycleEvent event) { ExoSocialActivity sharedActivity = event.getActivity(); diff --git a/content-service/src/main/java/io/meeds/news/listener/NewsGamificationIntegrationListener.java b/content-service/src/main/java/io/meeds/news/listener/NewsGamificationIntegrationListener.java index ba26cd0e0..008efd5d1 100644 --- a/content-service/src/main/java/io/meeds/news/listener/NewsGamificationIntegrationListener.java +++ b/content-service/src/main/java/io/meeds/news/listener/NewsGamificationIntegrationListener.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.Map; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.exoplatform.container.ExoContainerContext; @@ -35,11 +36,19 @@ import io.meeds.news.model.News; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import static io.meeds.news.utils.NewsUtils.POST_NEWS_ARTICLE; +import static io.meeds.news.utils.NewsUtils.PUBLISH_NEWS; + +@Component public class NewsGamificationIntegrationListener extends Listener { private static final Log LOG = ExoLogger.getLogger(NewsGamificationIntegrationListener.class); + private String[] LISTENERS = {POST_NEWS_ARTICLE, PUBLISH_NEWS}; + public static final String GAMIFICATION_GENERIC_EVENT = "exo.gamification.generic.action"; public static final String GAMIFICATION_POST_NEWS_ARTICLE_RULE_TITLE = "PostArticle"; @@ -52,15 +61,18 @@ public class NewsGamificationIntegrationListener extends Listener String OBJECT_TYPE_PARAM = "objectType"; + @Autowired private PortalContainer container; + @Autowired private ListenerService listenerService; - public NewsGamificationIntegrationListener(PortalContainer container, ListenerService listenerService) { - this.container = container; - this.listenerService = listenerService; + @PostConstruct + public void init() { + for (String listener : LISTENERS) { + listenerService.addListener(listener, this); + } } - @Override public void onEvent(Event event) throws Exception { ExoContainerContext.setCurrentContainer(container); @@ -69,7 +81,7 @@ public void onEvent(Event event) throws Exception { String eventName = event.getEventName(); News news = event.getData(); String ruleTitle = ""; - if (StringUtils.equals(eventName, NewsUtils.POST_NEWS_ARTICLE)) { + if (StringUtils.equals(eventName, POST_NEWS_ARTICLE)) { ruleTitle = GAMIFICATION_POST_NEWS_ARTICLE_RULE_TITLE; } else if (StringUtils.equals(eventName, NewsUtils.PUBLISH_NEWS)) { ruleTitle = GAMIFICATION_PUBLISH_NEWS_ARTICLE_RULE_TITLE; diff --git a/content-service/src/main/java/io/meeds/news/listener/NewsMetadataListener.java b/content-service/src/main/java/io/meeds/news/listener/NewsMetadataListener.java index 1e661e3df..ecc8c27d9 100644 --- a/content-service/src/main/java/io/meeds/news/listener/NewsMetadataListener.java +++ b/content-service/src/main/java/io/meeds/news/listener/NewsMetadataListener.java @@ -21,11 +21,13 @@ import java.util.Set; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.exoplatform.commons.search.index.IndexingService; import org.exoplatform.services.listener.Event; import org.exoplatform.services.listener.Listener; +import org.exoplatform.services.listener.ListenerService; import org.exoplatform.social.core.manager.IdentityManager; import org.exoplatform.social.core.space.model.Space; import org.exoplatform.social.core.space.spi.SpaceService; @@ -36,27 +38,39 @@ import io.meeds.news.model.News; import io.meeds.news.search.NewsIndexingServiceConnector; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import static io.meeds.news.utils.NewsUtils.POST_NEWS; +import static io.meeds.news.utils.NewsUtils.SHARE_NEWS; +import static io.meeds.news.utils.NewsUtils.UPDATE_NEWS; + +@Component public class NewsMetadataListener extends Listener { - private final IndexingService indexingService; + @Autowired + private IndexingService indexingService; - private final IdentityManager identityManager; + @Autowired + private IdentityManager identityManager; - private final SpaceService spaceService; + @Autowired + private SpaceService spaceService; + @Autowired private TagService tagService; - public NewsMetadataListener(IndexingService indexingService, - SpaceService spaceService, - IdentityManager identityManager, - TagService tagService) { - this.indexingService = indexingService; - this.identityManager = identityManager; - this.spaceService = spaceService; - this.tagService = tagService; - } + @Autowired + private ListenerService listenerService; + private String[] LISTENERS = {POST_NEWS, UPDATE_NEWS, SHARE_NEWS}; + + @PostConstruct + public void init() { + for (String listener : LISTENERS) { + listenerService.addListener(listener, this); + } + } @Override public void onEvent(Event event) throws Exception { News news = event.getData(); diff --git a/content-service/src/main/java/io/meeds/news/model/News.java b/content-service/src/main/java/io/meeds/news/model/News.java index 26239eefe..3e18fa7b2 100644 --- a/content-service/src/main/java/io/meeds/news/model/News.java +++ b/content-service/src/main/java/io/meeds/news/model/News.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; +import io.meeds.notes.model.NotePageProperties; import org.exoplatform.social.metadata.model.MetadataItem; import lombok.AllArgsConstructor; @@ -36,12 +37,12 @@ public class News { private String id; + private String targetPageId; + private String title; private String name; - private String summary; - /* sanitizedBody with usernames */ private String body; @@ -68,14 +69,6 @@ public class News { private String uploadId; - private byte[] illustration; - - private Date illustrationUpdateDate; - - private String illustrationMimeType; - - private String illustrationURL; - private Date creationDate; private Date publicationDate; @@ -139,4 +132,10 @@ public class News { private boolean favorite; private boolean deleted; + + private String lang; + + private String illustrationURL; + + private NotePageProperties properties; } diff --git a/content-service/src/main/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPlugin.java b/content-service/src/main/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPlugin.java index 355d4f3cc..5fd918ceb 100644 --- a/content-service/src/main/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPlugin.java +++ b/content-service/src/main/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPlugin.java @@ -60,7 +60,7 @@ public SpaceWebNotificationItem getSpaceApplicationItem(NotificationInfo notific String newsId = notification.getValueOwnerParameter(NotificationConstants.NEWS_ID); News news = null; try { - news = newsService.getNewsById(newsId, false); + news = newsService.getNewsArticleById(newsId); } catch (Exception e) { LOG.warn("Error retrieving news by id {}", newsId, e); return null; diff --git a/content-service/src/main/java/io/meeds/news/notification/plugin/PostNewsNotificationPlugin.java b/content-service/src/main/java/io/meeds/news/notification/plugin/PostNewsNotificationPlugin.java index c07c39a90..49e150bff 100644 --- a/content-service/src/main/java/io/meeds/news/notification/plugin/PostNewsNotificationPlugin.java +++ b/content-service/src/main/java/io/meeds/news/notification/plugin/PostNewsNotificationPlugin.java @@ -185,7 +185,7 @@ protected NotificationInfo makeNotification(NotificationContext ctx) { private boolean mustSendNotification(String newsId) { News news = null; try { - news = newsService.getNewsById(newsId, false); + news = newsService.getNewsArticleById(newsId); } catch (Exception e) { LOG.warn("Error retrieving news by id {}", newsId, e); return false; diff --git a/content-service/src/main/java/io/meeds/news/plugin/NewsListViewTranslationPlugin.java b/content-service/src/main/java/io/meeds/news/plugin/NewsListViewTranslationPlugin.java new file mode 100644 index 000000000..2d08e21e0 --- /dev/null +++ b/content-service/src/main/java/io/meeds/news/plugin/NewsListViewTranslationPlugin.java @@ -0,0 +1,115 @@ +/* + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 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.news.plugin; + +import io.meeds.social.translation.plugin.TranslationPlugin; +import io.meeds.social.translation.service.TranslationService; +import jakarta.annotation.PostConstruct; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.exoplatform.container.ExoContainerContext; +import org.exoplatform.services.organization.OrganizationService; +import org.exoplatform.services.security.Identity; +import org.exoplatform.services.security.IdentityRegistry; +import org.exoplatform.services.security.MembershipEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; + +@Component +public class NewsListViewTranslationPlugin extends TranslationPlugin { + + public static final String NEWS_LIST_VIEW_OBJECT_TYPE = "newsListView"; + + private static final String PUBLISHER_MEMBERSHIP_NAME = "publisher"; + + private static final String PLATFORM_WEB_CONTRIBUTORS_GROUP = "/platform/web-contributors"; + + @Setter + private IdentityRegistry identityRegistry; + + @Autowired + private OrganizationService organizationService; + + @Autowired + private TranslationService translationService; + + @PostConstruct + public void init() { + setIdentityRegistry(ExoContainerContext.getService(IdentityRegistry.class)); + translationService.addPlugin(this); + } + + @Override + public String getName() { + return NEWS_LIST_VIEW_OBJECT_TYPE; + } + + @Override + public String getObjectType() { + return NEWS_LIST_VIEW_OBJECT_TYPE; + } + + @Override + public boolean hasAccessPermission(long objectId, String username) { + return true; + } + + @Override + public boolean hasEditPermission(long objectId, String username) { + try { + return getIdentity(username) != null + && Objects.requireNonNull(getIdentity(username)).isMemberOf(PLATFORM_WEB_CONTRIBUTORS_GROUP, PUBLISHER_MEMBERSHIP_NAME); + } catch (Exception e) { + return false; + } + } + + @Override + public long getAudienceId(long objectId) throws ObjectNotFoundException { + return 0; + } + + @Override + public long getSpaceId(long objectId) throws ObjectNotFoundException { + return 0; + } + + private Identity getIdentity(String username) throws Exception { + if (StringUtils.isBlank(username)) { + return null; + } + Identity aclIdentity = identityRegistry.getIdentity(username); + if (aclIdentity == null) { + List entries = organizationService.getMembershipHandler() + .findMembershipsByUser(username) + .stream() + .map(membership -> new MembershipEntry(membership.getGroupId(), + membership.getMembershipType())) + .toList(); + aclIdentity = new Identity(username, entries); + identityRegistry.register(aclIdentity); + } + return aclIdentity; + } +} diff --git a/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java b/content-service/src/main/java/io/meeds/news/rest/NewsRest.java similarity index 54% rename from content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java rename to content-service/src/main/java/io/meeds/news/rest/NewsRest.java index 805c91cee..3ff1620ad 100644 --- a/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java +++ b/content-service/src/main/java/io/meeds/news/rest/NewsRest.java @@ -22,37 +22,27 @@ import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import javax.annotation.security.RolesAllowed; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.CacheControl; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.EntityTag; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Request; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; + import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; + +import io.swagger.v3.oas.annotations.Parameter; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.picocontainer.Startable; + import org.exoplatform.commons.exception.ObjectNotFoundException; import org.exoplatform.commons.utils.CommonsUtils; @@ -62,8 +52,7 @@ import org.exoplatform.portal.application.localization.LocalizationFilter; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import org.exoplatform.services.rest.http.PATCH; -import org.exoplatform.services.rest.resource.ResourceContainer; + import org.exoplatform.services.security.ConversationState; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider; @@ -84,176 +73,158 @@ import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; - -@Path("v1/news") -@Tag(name = "v1/news", description = "Managing news") -public class NewsRestResourcesV1 implements ResourceContainer, Startable { - - private static final Log LOG = ExoLogger.getLogger(NewsRestResourcesV1.class); - +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("contents") +@Tag(name = "content/rest/contents", description = "Managing contents") +public class NewsRest { + + private static final Log LOG = ExoLogger.getLogger(NewsRest.class); + + @Autowired private NewsService newsService; + @Autowired private SpaceService spaceService; + @Autowired private IdentityManager identityManager; - private ScheduledExecutorService scheduledExecutor; - + @Autowired private PortalContainer container; + @Autowired private FavoriteService favoriteService; private Map newsToDeleteQueue = new HashMap<>(); - private static final int CACHE_DURATION_SECONDS = 31536000; - - private static final long CACHE_DURATION_MILLISECONDS = CACHE_DURATION_SECONDS * 1000L; - - private static final CacheControl ILLUSTRATION_CACHE_CONTROL = new CacheControl(); + private ScheduledExecutorService scheduledExecutor; - static { - ILLUSTRATION_CACHE_CONTROL.setMaxAge(CACHE_DURATION_SECONDS); - } + private static final int CACHE_DURATION_SECONDS = 31536000; private enum FilterType { PINNED, MYPOSTED, DRAFTS, SCHEDULED, ALL } - public NewsRestResourcesV1(NewsService newsService, - SpaceService spaceService, - IdentityManager identityManager, - PortalContainer container, - FavoriteService favoriteService) { - - this.newsService = newsService; - this.spaceService = spaceService; - this.identityManager = identityManager; - this.container = container; - this.favoriteService = favoriteService; - } - - @Override - public void start() { + @PostConstruct + public void init() { scheduledExecutor = Executors.newScheduledThreadPool(1); } - @Override - public void stop() { + @PreDestroy + public void destroy() { if (scheduledExecutor != null) { scheduledExecutor.shutdown(); } } - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Create a news", method = "POST", description = "This creates the news if the authenticated user is a member of the space or a spaces super manager. The news is created in draft status, unless the publicationState property is set to 'posted'.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News created"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to create the news"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response createNews(@Context - HttpServletRequest request, @RequestBody(description = "News object to create", required = true) - News news) { + public ResponseEntity createNews(@RequestBody News news) { if (news == null || StringUtils.isEmpty(news.getSpaceId())) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { News createdNews = newsService.createNews(news, currentIdentity); - return Response.ok(createdNews).build(); + return ResponseEntity.ok(createdNews); } catch (IllegalAccessException e) { - LOG.warn("User '{}' is not autorized to create news", currentIdentity.getUserId(), e); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + LOG.warn("User '{}' is not authorized to create news", currentIdentity.getUserId(), e); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (Exception e) { LOG.error("Error when creating the news " + news.getTitle(), e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.badRequest().build(); } } - @GET - @Path("canCreateNews/{spaceId}") - @Produces(MediaType.TEXT_PLAIN) - @RolesAllowed("users") + + @GetMapping(path = "canCreateNews/{spaceId}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "check if the current user can create a news in the given space", method = "GET", description = "This checks if the current user can create a news in the given space") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User ability to create a news is returned"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to create a news"), @ApiResponse(responseCode = "404", description = "Space not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response canCreateNews(@Context - HttpServletRequest request, - @Parameter(description = "space id", required = true) - @PathParam("spaceId") - String spaceId) { + public ResponseEntity canCreateNews(@PathVariable("spaceId") String spaceId) { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { if (StringUtils.isBlank(spaceId)) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } Space space = spaceService.getSpaceById(spaceId); if (space == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } - return Response.ok(String.valueOf(newsService.canCreateNews(space, currentIdentity))).build(); + return ResponseEntity.ok(newsService.canCreateNews(space, currentIdentity)); } catch (IllegalAccessException e) { LOG.warn("User '{}' is not autorized to check if we can create news", currentIdentity.getUserId(), e); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (Exception e) { LOG.error("Error when checking if the authenticated user can create a news", e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @PUT - @Path("{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + + @PutMapping(path = "{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Create a news", method = "PUT", description = "This updates the news if the authenticated user is a member of the space or a spaces super manager.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News updated"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to update the news"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response updateNews(@Parameter(description = "News id", required = true) - @PathParam("id") - String id, - @Parameter(description = "Post news", required = false) - @QueryParam("post") - boolean post, - @Parameter(description = "News object type to be updated", required = false) - @QueryParam("type") - String newsObjectType, - @Parameter(description = "News update action type to be done", required = false) - @Schema(defaultValue = "content") - @QueryParam("newsUpdateType") - String newsUpdateType, - @RequestBody(description = "News object to be updated", required = true) - News updatedNews) { + public ResponseEntity updateNews(@PathVariable("id") + String id, + @Parameter(description = "Post news") + @RequestParam(name = "post", required = false) + boolean post, + @Parameter(description = "News object type to be updated") + @RequestParam("type") + String newsObjectType, + @Parameter(description = "News update action type to be done") + @RequestParam(name = "newsUpdateType", defaultValue = "content", required = false) + String newsUpdateType, + @RequestBody + News updatedNews) { if (updatedNews == null) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { News news = newsService.getNewsById(id, currentIdentity, false, newsObjectType); if (news == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } - news.setTitle(updatedNews.getTitle()); - news.setSummary(updatedNews.getSummary()); news.setBody(updatedNews.getBody()); news.setUploadId(updatedNews.getUploadId()); news.setPublicationState(updatedNews.getPublicationState()); @@ -261,38 +232,34 @@ public Response updateNews(@Parameter(description = "News id", required = true) news.setActivityPosted(updatedNews.isActivityPosted()); news.setTargets(updatedNews.getTargets()); news.setAudience(updatedNews.getAudience()); - + news.setProperties(updatedNews.getProperties()); + news.setLang(updatedNews.getLang()); news = newsService.updateNews(news, currentIdentity.getUserId(), post, updatedNews.isPublished(), newsObjectType, newsUpdateType); - return Response.ok(news).build(); + return ResponseEntity.ok(news); } catch (IllegalAccessException e) { LOG.warn("User '{}' is not authorized to update news", currentIdentity.getUserId(), e); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (Exception e) { LOG.error("Error when updating the news " + id, e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @DELETE - @Path("{id}") - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @DeleteMapping(path = "{id}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Delete news", method = "DELETE", description = "This deletes the news") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News deleted"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to delete the news"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response deleteNews(@Context - HttpServletRequest request, - @Parameter(description = "News id", required = true) - @PathParam("id") + public Response deleteNews(@PathVariable("id") String id, - @Parameter(description = "news object to be deleted", required = true) - @QueryParam("type") + @Parameter(description = "news object to be deleted") + @RequestParam("type") String newsObjectType, - @Parameter(description = "Time to effectively delete news", required = false) - @QueryParam("delay") + @Parameter(description = "Time to effectively delete news") + @RequestParam(name = "delay", required = false) long delay) { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { @@ -339,25 +306,21 @@ public Response deleteNews(@Context } } - @Path("{id}/undoDelete") - @POST - @RolesAllowed("users") + @PostMapping("{id}/undoDelete") + @Secured("users") @Operation(summary = "Undo deleting news if not yet effectively deleted", method = "POST", description = "Undo deleting news if not yet effectively deleted") @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Request fulfilled"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "403", description = "Forbidden operation"), @ApiResponse(responseCode = "401", description = "Unauthorized operation"), @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response undoDeleteNews(@Context - HttpServletRequest request, - @Parameter(description = "News node identifier", required = true) - @PathParam("id") + public Response undoDeleteNews(@PathVariable("id") String id) { if (StringUtils.isBlank(id)) { return Response.status(Response.Status.BAD_REQUEST).entity("News identifier must not be null or empty").build(); } if (newsToDeleteQueue.containsKey(id)) {// TODO Move to service layer - String authenticatedUser = request.getRemoteUser(); + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); String originalModifierUser = newsToDeleteQueue.get(id); if (!originalModifierUser.equals(authenticatedUser)) { LOG.warn("User {} attempts to cancel deletion of a news deleted by user {}", authenticatedUser, originalModifierUser); @@ -372,47 +335,43 @@ public Response undoDeleteNews(@Context } } - @GET - @Path("{id}") - @Produces(MediaType.APPLICATION_JSON) + @GetMapping(path = "{id}", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Get a news", method = "GET", description = "This gets the news with the given id if the authenticated user is a member of the space or a spaces super manager.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News returned"), @ApiResponse(responseCode = "401", description = "User not authorized to get the news"), @ApiResponse(responseCode = "404", description = "News not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getNewsById(@Context - HttpServletRequest request, - @Parameter(description = "News id", required = true) - @PathParam("id") - String id, - @Parameter(description = "fields", required = true) - @QueryParam("fields") - String fields, - @Parameter(description = "News object type to be fetched", required = false) - @QueryParam("type") - String newsObjectType, - @Parameter(description = "Is edit mode") - @Schema(defaultValue = "false") - @QueryParam("editMode") - boolean editMode) { - String authenticatedUser = request.getRemoteUser(); + public ResponseEntity getNewsById(@PathVariable("id") + String id, + @Parameter(description = "fields") + @RequestParam(name = "fields", required = false) + String fields, + @Parameter(description = "News object type to be fetched") + @RequestParam("type") + String newsObjectType, + @Parameter(description = "Is edit mode") + @RequestParam(name = "editMode", defaultValue = "false", required = false) + boolean editMode, + @Parameter(description = "article translation") + @RequestParam(name = "lang", required = false) + String lang) { + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); try { if (StringUtils.isBlank(id)) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); - News news = newsService.getNewsById(id, currentIdentity, editMode, newsObjectType); + News news = newsService.getNewsByIdAndLang(id, currentIdentity, editMode, newsObjectType, StringUtils.isBlank(lang) ? null : lang); if (news == null || news.isDeleted()) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } Locale userLocale = LocalizationFilter.getCurrentLocale(); news.setBody(MentionUtils.substituteRoleWithLocale(news.getBody(), userLocale)); - news.setIllustration(null); // check favorite Identity userIdentity = identityManager.getOrCreateUserIdentity(currentIdentity.getUserId()); if (userIdentity != null) { news.setFavorite(favoriteService.isFavorite(new Favorite("news", - news.getId(), + news.getLang() != null ? news.getId().concat("-").concat(news.getLang()) : news.getId(), "", Long.parseLong(userIdentity.getId())))); } @@ -429,35 +388,30 @@ public Response getNewsById(@Context spacesList.add(spaceId); } filteredNews.setSharedInSpacesList(spacesList); - return Response.ok(filteredNews).build(); + return ResponseEntity.ok(filteredNews); } else { - return Response.ok(news).build(); + return ResponseEntity.ok(news); } } catch (IllegalAccessException e) { LOG.warn("User {} attempt to access unauthorized news with id {}", authenticatedUser, id); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (Exception e) { LOG.error("Error when getting the news " + id, e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @POST - @Path("markAsRead/{id}") - @RolesAllowed("users") - @Produces(MediaType.TEXT_PLAIN) + @PostMapping(path = "markAsRead/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "mark a news article as read", method = "POST", description = "This marks a news article as read by the user who accessed its details.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), @ApiResponse(responseCode = "401", description = "User not authorized to get the news"), @ApiResponse(responseCode = "404", description = "News not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response markNewsAsRead(@Context - HttpServletRequest request, - @Parameter(description = "News id", required = true) - @PathParam("id") + public Response markNewsAsRead(@PathVariable("id") String id) { - String authenticatedUser = request.getRemoteUser(); + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); try { if (StringUtils.isBlank(id)) { return Response.status(Response.Status.BAD_REQUEST).build(); @@ -468,7 +422,7 @@ public Response markNewsAsRead(@Context return Response.status(Response.Status.NOT_FOUND).build(); } newsService.markAsRead(news, authenticatedUser); - return Response.ok("ok").type(MediaType.TEXT_PLAIN).build(); + return Response.ok("ok").type(MediaType.APPLICATION_JSON_VALUE).build(); } catch (IllegalAccessException e) { LOG.warn("User {} has no access rights on news with id {}", authenticatedUser, id); return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); @@ -478,44 +432,39 @@ public Response markNewsAsRead(@Context } } - @GET - @RolesAllowed("users") - @Produces(MediaType.APPLICATION_JSON) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Get news list", method = "GET", description = "This gets the list of news with the given search text, of the given author, in the given space or spaces, with the given publication state, with the given pinned state if the authenticated user is a member of the spaces or a super manager.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News list returned"), @ApiResponse(responseCode = "401", description = "User not authorized to get the news list"), @ApiResponse(responseCode = "404", description = "News list not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getNews(@Context - HttpServletRequest request, - @Parameter(description = "News author", required = true) - @QueryParam("author") - String author, - @Parameter(description = "News spaces", required = true) - @QueryParam("spaces") - String spaces, - @Parameter(description = "News filter", required = true) - @QueryParam("filter") - String filter, - @Parameter(description = "search text", required = true) - @QueryParam("text") - String text, - @Parameter(description = "News pagination offset") - @Schema(defaultValue = "0") - @QueryParam("offset") - int offset, - @Parameter(description = "News pagination limit") - @Schema(defaultValue = "10") - @QueryParam("limit") - int limit, - @Parameter(description = "News total size") - @Schema(defaultValue = "false") - @QueryParam("returnSize") - boolean returnSize) { + public ResponseEntity getNews(@Parameter(description = "News author") + @RequestParam("author") + String author, + @Parameter(description = "News spaces") + @RequestParam(name = "spaces", required = false) + String spaces, + @Parameter(description = "News filter") + @RequestParam("filter") + String filter, + @Parameter(description = "search text") + @RequestParam(name = "text", required = false) + String text, + @Parameter(description = "News pagination offset") + @RequestParam(name = "offset", defaultValue = "0", required = false) + int offset, + @Parameter(description = "News pagination limit") + @RequestParam(name = "limit", defaultValue = "10") + int limit, + @Parameter(description = "News total size") + @RequestParam(name = "returnSize", defaultValue = "false", required = false) + boolean returnSize, + HttpServletRequest request) { try {// TODO Move to service layer - String authenticatedUser = request.getRemoteUser(); + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); if (StringUtils.isBlank(author) || !authenticatedUser.equals(author)) { - return Response.status(Response.Status.UNAUTHORIZED).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } NewsEntity newsEntity = new NewsEntity(); @@ -527,18 +476,18 @@ public Response getNews(@Context Space space = spaceService.getSpaceById(spaceId); if (space == null || (!spaceService.isSuperManager(authenticatedUser) && !spaceService.isMember(space, authenticatedUser))) { - return Response.status(Response.Status.UNAUTHORIZED).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } spacesList.add(spaceId); } } NewsFilter newsFilter = buildFilter(spacesList, filter, text, author, limit, offset); + String lang = request.getLocale().getLanguage(); + newsFilter.setLang(lang); List news; org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); // Set text to search news with if (StringUtils.isNotEmpty(text)) { - String lang = request.getLocale().getLanguage(); - newsFilter.setLang(lang); TagService tagService = CommonsUtils.getService(TagService.class); long userIdentityId = RestUtils.getCurrentUserIdentityId(); if (text.indexOf("#") == 0) { @@ -554,14 +503,11 @@ public Response getNews(@Context news = newsService.getNews(newsFilter, currentIdentity); } - if (news != null && news.size() != 0) { - for (News newsItem : news) { - newsItem.setIllustration(null); - } - } if (news != null) { Locale userLocale = LocalizationFilter.getCurrentLocale(); - news.forEach(news1 -> news1.setBody(MentionUtils.substituteRoleWithLocale(news1.getBody(), userLocale))); + news.stream() + .filter(Objects::nonNull) + .forEach(news1 -> news1.setBody(MentionUtils.substituteRoleWithLocale(news1.getBody(), userLocale))); } newsEntity.setNews(news); newsEntity.setOffset(offset); @@ -569,50 +515,44 @@ public Response getNews(@Context if (returnSize) { newsEntity.setSize(newsService.getNewsCount(newsFilter)); } - return Response.ok(newsEntity).build(); + return ResponseEntity.ok(newsEntity); } catch (Exception e) { LOG.error("Error when getting the news with params author=" + author + ", spaces=" + spaces, e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @GET - @Path("byTarget/{targetName}") - @Produces(MediaType.APPLICATION_JSON) + @GetMapping(path = "byTarget/{targetName}", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Get news list", method = "GET", description = "This gets the list of news by the given target.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News list returned"), @ApiResponse(responseCode = "401", description = "User not authorized to get the news list"), @ApiResponse(responseCode = "404", description = "News list not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getNewsByTarget(@Context - HttpServletRequest request, - @Parameter(description = "News target name", required = true) - @PathParam("targetName") - String targetName, - @Parameter(description = "News pagination offset") - @Schema(defaultValue = "0") - @QueryParam("offset") - int offset, - @Parameter(description = "News pagination limit") - @Schema(defaultValue = "10") - @QueryParam("limit") - int limit, - @Parameter(description = "News total size") - @Schema(defaultValue = "false") - @QueryParam("returnSize") - boolean returnSize) { + public ResponseEntity getNewsByTarget(@PathVariable("targetName") + String targetName, + @Parameter(description = "News pagination offset") + @RequestParam(name = "offset", defaultValue = "0", required = false) + int offset, + @Parameter(description = "News pagination limit") + @RequestParam(name = "limit", defaultValue = "10") + int limit, + @Parameter(description = "News total size") + @RequestParam(name = "returnSize", required = false) + boolean returnSize, + HttpServletRequest request) { try { - String authenticatedUser = request.getRemoteUser(); + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); if (StringUtils.isBlank(targetName)) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } if (offset < 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("Offset must be 0 or positive").build(); + ResponseEntity.badRequest().build(); } if (limit < 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("Limit must be positive").build(); + return ResponseEntity.badRequest().build(); } NewsFilter newsFilter = buildFilter(null, "", "", authenticatedUser, limit, offset); + newsFilter.setLang(request.getLocale().getLanguage()); NewsEntity newsEntity = new NewsEntity(); org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); List news = newsService.getNewsByTargetName(newsFilter, targetName, currentIdentity); @@ -624,139 +564,124 @@ public Response getNewsByTarget(@Context if (returnSize) { newsEntity.setSize(news.size()); } - return Response.ok(newsEntity).build(); + return ResponseEntity.ok(newsEntity); } catch (Exception e) { LOG.error("Error when getting the news with target name=" + targetName, e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @GET - @Path("byActivity/{activityId}") - @RolesAllowed("users") - @Produces(MediaType.APPLICATION_JSON) + @GetMapping(path = "byActivity/{activityId}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Get a news identified by its activity or shared activity identifier", method = "GET", description = "This gets the news with the given id if the authenticated user is a member of the space or a spaces super manager.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News returned"), @ApiResponse(responseCode = "401", description = "User not authorized to get the news"), @ApiResponse(responseCode = "404", description = "News not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getNewsByActivityId(@Parameter(description = "Activity id", required = true) - @PathParam("activityId") - String activityId) { + public ResponseEntity getNewsByActivityId(@PathVariable("activityId") + String activityId, + @RequestParam(name = "lang", defaultValue = "null", required = false) + String lang) { if (StringUtils.isBlank(activityId)) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { - News news = newsService.getNewsByActivityId(activityId, currentIdentity); + News news = newsService.getNewsByActivityIdAndLang(activityId, currentIdentity, lang); if (news == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } - news.setIllustration(null); Locale userLocale = LocalizationFilter.getCurrentLocale(); news.setBody(MentionUtils.substituteRoleWithLocale(news.getBody(), userLocale)); Identity userIdentity = identityManager.getOrCreateUserIdentity(currentIdentity.getUserId()); if (userIdentity != null) { news.setFavorite(favoriteService.isFavorite(new Favorite("news", - news.getId(), + news.getLang() != null ? news.getId().concat("-").concat(news.getLang()) : news.getId(), "", Long.parseLong(userIdentity.getId())))); } - return Response.ok(news).build(); + return ResponseEntity.ok(news); } catch (IllegalAccessException e) { LOG.warn("User {} attempt to access unauthorized news with id {}", currentIdentity.getUserId(), activityId); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (ObjectNotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity(e.getMessage()).build(); + return ResponseEntity.notFound().build(); } catch (Exception e) { LOG.error("Error when getting the news " + activityId, e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @PATCH - @Path("schedule") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @PatchMapping(path = "schedule", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Schedule a news", method = "POST", description = "This schedules the news if the authenticated user is a member of the space or a spaces super manager. The news is created in staged status, after reaching a date of publication startPublishedDate, the publicationState property is set to 'posted'.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News scheduled"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to schedule the news"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response scheduleNews(@Context - HttpServletRequest request, - @Parameter(description = "News object type to be fetched", required = false) - @QueryParam("type") - String newsObjectType, - @RequestBody(description = "News object to be scheduled", required = true) - News scheduledNews) { + public ResponseEntity scheduleNews(@Parameter(description = "News object type to be fetched") + @RequestParam("type") + String newsObjectType, + @RequestBody + News scheduledNews) { if (scheduledNews == null || StringUtils.isEmpty(scheduledNews.getId())) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { News news = newsService.getNewsById(scheduledNews.getId(), currentIdentity, false, newsObjectType); if (news == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } news = newsService.scheduleNews(scheduledNews, currentIdentity, newsObjectType); - return Response.ok(news).build(); + return ResponseEntity.ok(news); } catch (IllegalAccessException e) { LOG.warn("User '{}' is not autorized to schedule news", currentIdentity.getUserId(), e); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } catch (Exception e) { LOG.error("Error when scheduling the news " + scheduledNews.getTitle(), e); - return Response.serverError().entity(e.getMessage()).build(); + return ResponseEntity.internalServerError().build(); } } - @Path("search") - @GET - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @GetMapping(path = "search", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "Search the list of news available with query", method = "GET", description = "Search the list of news available with query") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "500", description = "Internal server error"), }) - public Response search(@Context - UriInfo uriInfo, @Context - HttpServletRequest request, - @Parameter(description = "Term to search", required = true) - @QueryParam("query") - String query, - @Parameter(description = "Properties to expand") - @QueryParam("expand") - String expand, - @Parameter(description = "Offset") - @Schema(defaultValue = "0") - @QueryParam("offset") - int offset, - @Parameter(description = "Tag names used to search news", required = true) - @QueryParam("tags") - List tagNames, - @Parameter(description = "Limit") - @Schema(defaultValue = "20") - @QueryParam("limit") - int limit, - @Parameter(description = "Favorites") - @Schema(defaultValue = "false") - @QueryParam("favorites") - boolean favorites) { + public ResponseEntity> search(@Parameter(description = "Term to search") + @RequestParam(name = "query", required = false) + String query, + @Parameter(description = "Properties to expand") + @RequestParam(name = "expand", required = false) + String expand, + @Parameter(description = "Offset") + @RequestParam(name = "offset", defaultValue = "0", required = false) + int offset, + @Parameter(description = "Tag names used to search news") + @RequestParam(name = "tags", required = false) + List tagNames, + @Parameter(description = "Limit") + @RequestParam(name = "limit", defaultValue = "10") + int limit, + @Parameter(description = "Favorites") + @RequestParam(name = "favorites", defaultValue = "false", required = false) + boolean favorites) { if (StringUtils.isBlank(query) && !favorites && CollectionUtils.isEmpty(tagNames)) { - return Response.status(Response.Status.BAD_REQUEST).entity("'query' parameter is mandatory").build(); + return ResponseEntity.badRequest().build(); } - String authenticatedUser = request.getRemoteUser(); + String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); Identity currentIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, authenticatedUser); if (offset < 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("Offset must be 0 or positive").build(); + return ResponseEntity.badRequest().build(); } if (limit < 0) { - return Response.status(Response.Status.BAD_REQUEST).entity("Limit must be positive").build(); + return ResponseEntity.badRequest().build(); } NewsFilter filter = new NewsFilter(); filter.setSearchText(query); @@ -769,255 +694,55 @@ public Response search(@Context searchResults.stream() .map(searchResult -> io.meeds.news.utils.EntityBuilder.fromNewsSearchResult(favoriteService, searchResult, - currentIdentity, - uriInfo)) + currentIdentity)) .collect(Collectors.toList()); - return Response.ok(results).build(); + return ResponseEntity.ok(results); } - @GET - @Path("{id}/illustration") - @Operation(summary = "Get a news illustration", method = "GET", description = "This gets the news illustration with the given id if the authenticated user is a member of the space or a spaces super manager.") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News returned"), - @ApiResponse(responseCode = "401", description = "User not authorized to get the news"), - @ApiResponse(responseCode = "404", description = "News not found"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getNewsIllustration(@Context - Request rsRequest, @Context - HttpServletRequest request, - @Parameter(description = "News id", required = true) - @PathParam("id") - String id, - @Parameter(description = "last modified date") - @QueryParam("v") - long lastModified, - @Parameter(description = "News object type to be fetched", required = false) - @QueryParam("type") - String newsObjectType, - @Parameter(description = "resized image size") - @QueryParam("size") - String size) { - try { - org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); - News news = newsService.getNewsById(id, currentIdentity, false, newsObjectType); - if (news == null || news.getIllustration() == null || news.getIllustration().length == 0) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - - if (!news.isPublished()) {// TODO Check if necessary - Space space = spaceService.getSpaceById(news.getSpaceId()); - if (space == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } - - long lastUpdated = news.getIllustrationUpdateDate().getTime(); - EntityTag eTag = (size == null || size.isBlank()) ? new EntityTag(String.valueOf(lastUpdated)) - : new EntityTag(lastUpdated + "-" + size); - Response.ResponseBuilder builder = rsRequest.evaluatePreconditions(eTag); - if (builder == null) { - if (size != null) { - // if there is no cache (browser cache or server cache with the etag), - // the image is resized - // it can be improved a little by storing the thumbnail in the news. - // in this case we need to add a security mechanism to prevent a user - // to generate one image for each (width,height) combination - } - builder = Response.ok(news.getIllustration(), news.getIllustrationMimeType()); - } - - if (lastModified > 0) { - builder.lastModified(new Date(lastUpdated)); - builder.expires(new Date(System.currentTimeMillis() + CACHE_DURATION_MILLISECONDS)); - builder.cacheControl(ILLUSTRATION_CACHE_CONTROL); - } - builder.tag(eTag); - return builder.build(); - } catch (Exception e) { - LOG.error("Error when getting the news " + id, e); - return Response.serverError().build(); - } - -// try { -// boolean isDefault = bannerId == 0; -// EntityTag eTag = !isDefault ? new EntityTag(String.valueOf(bannerId)) : new EntityTag(siteName); -// Response.ResponseBuilder builder = request.evaluatePreconditions(eTag); -// if (builder == null) { -// InputStream stream = isDefault ? layoutService.getDefaultSiteBannerStream(siteName) -// : layoutService.getSiteBannerStream(siteName); -// builder = Response.ok(stream, "image/png"); -// builder.tag(eTag); -// } -// builder.cacheControl(BANNER_CACHE_CONTROL); -// builder.lastModified(new Date(System.currentTimeMillis())); -// builder.expires(new Date(System.currentTimeMillis() + CACHE_IN_MILLI_SECONDS)); -// return builder.build(); -// } catch (ObjectNotFoundException e) { -// return Response.status(Response.Status.NOT_FOUND).build(); -// } catch (IOException e) { -// return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); -// } - } - - @POST - @Path("{id}/click") - @RolesAllowed("users") - @Operation(summary = "Log a click action on a news", method = "POST", description = "This logs a message when the user performs a click on a news") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Click logged"), - @ApiResponse(responseCode = "400", description = "Invalid query input"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response clickOnNews(@Context - UriInfo uriInfo, - @Parameter(description = "News id", required = true) - @PathParam("id") - String id, - @Parameter(description = "The clicked element", required = true) - String clickedElement) { - - String authenticatedUser = ConversationState.getCurrent().getIdentity().getUserId(); - Identity currentUser = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, authenticatedUser, false); - - News news; - try { - org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); - news = newsService.getNewsById(id, currentIdentity, false); - if (news == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } catch (Exception e) { - LOG.error("Error while getting news with id " + id, e); - return Response.serverError().build(); - } - - Space space = spaceService.getSpaceById(news.getSpaceId()); - - LOG.info("service=news operation=click_on_{} parameters=\"news_id:{},space_name:{},space_id:{},user_id:{}\"", - clickedElement, - news.getId(), - space != null ? space.getPrettyName() : "", - space != null ? space.getId() : "", - currentUser.getId()); - - return Response.status(Response.Status.OK).build(); - } - - @PATCH - @Path("{id}") - @Consumes(MediaType.APPLICATION_JSON) - @RolesAllowed("users") - @Operation(summary = "Update a news", method = "PATCH", description = "This updates the sent fields of a news") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News updated"), - @ApiResponse(responseCode = "400", description = "Invalid query input"), - @ApiResponse(responseCode = "401", description = "User not authorized to update the news"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response patchNews(@Context - HttpServletRequest request, - @Parameter(description = "News id", required = true) - @PathParam("id") - String id, - @RequestBody(description = "News object", required = true) - News updatedNews) { - if (updatedNews == null) { - return Response.status(Response.Status.BAD_REQUEST).build(); - } - String authenticatedUser = request.getRemoteUser(); - try { - org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); - News news = newsService.getNewsById(id, currentIdentity, false); - if (news == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - Space space = spaceService.getSpaceById(news.getSpaceId()); - if (space == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - boolean isUpdatedTitle = (updatedNews.getTitle() != null) && !updatedNews.getTitle().equals(news.getTitle()); - boolean isUpdatedSummary = (updatedNews.getSummary() != null) && !updatedNews.getSummary().equals(news.getSummary()); - boolean isUpdatedBody = (updatedNews.getBody() != null) && !updatedNews.getBody().equals(news.getBody()); - boolean isUpdatedIllustration = - (updatedNews.getUploadId() != null) && !updatedNews.getUploadId().equals(news.getUploadId()); - if (isUpdatedTitle || isUpdatedSummary || isUpdatedBody || isUpdatedIllustration) { - if (!news.isCanEdit()) { - return Response.status(Response.Status.UNAUTHORIZED).build(); - } - if (isUpdatedTitle) { - news.setTitle(updatedNews.getTitle()); - } - if (isUpdatedSummary) { - news.setSummary(updatedNews.getSummary()); - } - if (isUpdatedBody) { - news.setBody(updatedNews.getBody()); - } - if (isUpdatedIllustration) { - news.setUploadId(updatedNews.getUploadId()); - } - news = newsService.updateNews(news, authenticatedUser, null, updatedNews.isPublished()); - } - - return Response.ok(news).build(); - } catch (IllegalAccessException e) { - LOG.warn("User '{}' is not autorized to patch news", authenticatedUser, e); - return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); - } catch (Exception e) { - LOG.error("Error when trying to update the news " + id, e); - return Response.serverError().build(); - } - } - - @GET - @Path("canScheduleNews/{spaceId}") - @Produces(MediaType.TEXT_PLAIN) - @RolesAllowed("users") + @GetMapping(path = "canScheduleNews/{spaceId}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "check if the current user can schedule a news in the given space", method = "GET", description = "This checks if the current user can schedule a news in the given space") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User ability to schedule a news"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to schedule a news"), @ApiResponse(responseCode = "404", description = "Space not found"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response canScheduleNews(@Parameter(description = "space id", required = true) - @PathParam("spaceId") - String spaceId) { + public ResponseEntity canScheduleNews(@PathVariable("spaceId") String spaceId) { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { if (StringUtils.isBlank(spaceId)) { - return Response.status(Response.Status.BAD_REQUEST).build(); + return ResponseEntity.badRequest().build(); } Space space = spaceService.getSpaceById(spaceId); if (space == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } - return Response.ok(String.valueOf(newsService.canScheduleNews(space, currentIdentity))).build(); + return ResponseEntity.ok(newsService.canScheduleNews(space, currentIdentity)); } catch (Exception e) { LOG.error("Error when checking if the authenticated user can schedule a news", e); - return Response.serverError().build(); + return ResponseEntity.internalServerError().build(); } } - @GET - @Path("canPublishNews") - @Produces(MediaType.TEXT_PLAIN) - @RolesAllowed("users") + @GetMapping(path = "canPublishNews", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") @Operation(summary = "check if the current user can publish a news to all users", method = "GET", description = "This checks if the current user can publish a news to all users") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User ability to publish a news is returned"), - @ApiResponse(responseCode = "401", description = "User not authorized to publish a news") }) - public Response canPublishNews(@Parameter(description = "space id", required = true) - @QueryParam("spaceId") - String spaceId) { + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "User ability to publish a news is returned"), @ApiResponse(responseCode = "401", description = "User not authorized to publish a news") }) + public ResponseEntity canPublishNews(@RequestParam(name = "spaceId", required = false) String spaceId) { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { if (!StringUtils.isBlank(spaceId)) { Space space = spaceService.getSpaceById(spaceId); if (space == null) { - return Response.status(Response.Status.NOT_FOUND).build(); + return ResponseEntity.notFound().build(); } } - return Response.ok(String.valueOf(NewsUtils.canPublishNews(spaceId, currentIdentity))).build(); + return ResponseEntity.ok(NewsUtils.canPublishNews(spaceId, currentIdentity)); } catch (Exception e) { LOG.error("Error when checking if the authenticated user can publish a news to all users", e); - return Response.serverError().build(); + return ResponseEntity.internalServerError().build(); } } @@ -1065,4 +790,69 @@ private NewsFilter buildFilter(List spaces, String filter, String text, return newsFilter; } + + @DeleteMapping(path = "translation/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") + @Operation(summary = "Delete article version with language", method = "DELETE", description = "This deletes the article version ") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "article version deleted"), + @ApiResponse(responseCode = "400", description = "Invalid query input"), + @ApiResponse(responseCode = "401", description = "User not authorized to delete the article"), + @ApiResponse(responseCode = "500", description = "Internal server error") }) + public Response deleteArticleTranslation(@PathVariable("id") + String id, + @Parameter(description = "article version language") + @RequestParam(name = "lang") + String lang) { + org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); + try { + if (StringUtils.isBlank(id)) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + // fetch always the original news + News news = newsService.getNewsById(id, currentIdentity, false, ARTICLE.name()); + if (news == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + if (!news.isCanDelete()) { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + newsService.deleteVersionsByArticleIdAndLang(id, lang); + return Response.ok().build(); + } catch (IllegalAccessException e) { + LOG.warn("User '{}' is not authorized to delete article translation", currentIdentity.getUserId(), e); + return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + } catch (Exception e) { + LOG.error("Error when deleting the article translation with id " + id, e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + /** + * Get available translation languages for an article + * + * @param articleId the ID of the article + * @param withDrafts boolean flag to include drafts translation languages + * @return a list of available translation languages + */ + @GetMapping(path = "translation/{articleId}", produces = MediaType.APPLICATION_JSON_VALUE) + @Secured("users") + @Operation(summary = "Get article available translation languages", method = "GET", description = "Get article available translation languages") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Article available translation languages returned"), + @ApiResponse(responseCode = "400", description = "Invalid query input"), + @ApiResponse(responseCode = "401", description = "User not authorized to get the article available translation languages "), + @ApiResponse(responseCode = "500", description = "Internal server error") }) + public ResponseEntity> getAvailableTranslationLanguages(@PathVariable("articleId") + String articleId, + @RequestParam(name = "withDrafts") + boolean withDrafts) { + try { + if (StringUtils.isBlank(articleId)) { + return ResponseEntity.badRequest().build(); + } + return ResponseEntity.ok(newsService.getArticleLanguages(articleId, withDrafts)); + } catch (Exception e) { + LOG.error("Error when getting the article available translation languages with id " + articleId, e); + return ResponseEntity.internalServerError().build(); + } + } } diff --git a/content-service/src/main/java/io/meeds/news/rest/NewsSearchResultEntity.java b/content-service/src/main/java/io/meeds/news/rest/NewsSearchResultEntity.java index ff0d73d86..712137f44 100644 --- a/content-service/src/main/java/io/meeds/news/rest/NewsSearchResultEntity.java +++ b/content-service/src/main/java/io/meeds/news/rest/NewsSearchResultEntity.java @@ -21,6 +21,7 @@ import java.util.List; +import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.rest.entity.BaseEntity; import org.exoplatform.social.rest.entity.IdentityEntity; @@ -30,8 +31,6 @@ public class NewsSearchResultEntity extends BaseEntity { private static final long serialVersionUID = 1L; - private IdentityEntity poster; - private String title; private String body; @@ -50,6 +49,10 @@ public class NewsSearchResultEntity extends BaseEntity { private String activityId; + private String posterFullName; + + private String posterUserName; + public NewsSearchResultEntity() { } @@ -63,14 +66,23 @@ public NewsSearchResultEntity(NewsESSearchResult newsESSearchResult) { this.postedTime = newsESSearchResult.getPostedTime(); this.lastUpdatedTime = newsESSearchResult.getLastUpdatedTime(); this.activityId = newsESSearchResult.getActivityId(); + this.posterFullName = newsESSearchResult.getPoster().getProfile().getFullName(); + this.posterUserName = newsESSearchResult.getPoster().getRemoteId(); + } + public String getPosterFullName() { + return posterFullName; + } + + public void setPosterFullName(String posterFullName) { + this.posterFullName = posterFullName; } - public IdentityEntity getPoster() { - return poster; + public String getPosterUserName() { + return posterUserName; } - public void setPoster(IdentityEntity poster) { - this.poster = poster; + public void setPosterUserName(String posterUserName) { + this.posterUserName = posterUserName; } public String getBody() { diff --git a/content-service/src/main/java/io/meeds/news/rest/NewsTargetingRestResourcesV1.java b/content-service/src/main/java/io/meeds/news/rest/NewsTargetingRest.java similarity index 74% rename from content-service/src/main/java/io/meeds/news/rest/NewsTargetingRestResourcesV1.java rename to content-service/src/main/java/io/meeds/news/rest/NewsTargetingRest.java index 5d8bb19ec..14979acf7 100644 --- a/content-service/src/main/java/io/meeds/news/rest/NewsTargetingRestResourcesV1.java +++ b/content-service/src/main/java/io/meeds/news/rest/NewsTargetingRest.java @@ -26,125 +26,114 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.annotation.security.RolesAllowed; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; + import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import io.swagger.v3.oas.annotations.Parameter; import org.apache.commons.lang3.StringUtils; -import org.picocontainer.Startable; import org.exoplatform.container.ExoContainerContext; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.component.RequestLifeCycle; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; -import org.exoplatform.services.rest.resource.ResourceContainer; import org.exoplatform.services.security.ConversationState; import org.exoplatform.social.metadata.model.Metadata; import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; -@Path("v1/news/targeting") -@Tag(name = "v1/news/targeting", description = "Manage news targeting operations") -public class NewsTargetingRestResourcesV1 implements ResourceContainer, Startable { +@RestController +@RequestMapping("targeting") +@Tag(name = "content/rest/targeting", description = "Manage targeting operations") +public class NewsTargetingRest { - private static final Log LOG = ExoLogger.getLogger(NewsTargetingRestResourcesV1.class); + private static final Log LOG = ExoLogger.getLogger(NewsTargetingRest.class); + @Autowired private NewsTargetingService newsTargetingService; - private ScheduledExecutorService scheduledExecutor; - + @Autowired private PortalContainer container; + private ScheduledExecutorService scheduledExecutor; + private Map newsTargetToDeleteQueue = new HashMap<>(); - public NewsTargetingRestResourcesV1(NewsTargetingService newsTargetingService, PortalContainer container) { - this.newsTargetingService = newsTargetingService; - this.container = container; - } - @Override - public void start() { + @PostConstruct + public void init() { scheduledExecutor = Executors.newScheduledThreadPool(1); } - @Override - public void stop() { + @PreDestroy + public void destroy() { if (scheduledExecutor != null) { scheduledExecutor.shutdown(); } } - @GET - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @GetMapping(produces = MediaType.APPLICATION_JSON) + @Secured("users") @Operation(summary = "Get all news targets", method = "GET", description = "Get all news targets") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getAllTargets(@Context - HttpServletRequest request) { + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) + public ResponseEntity> getAllTargets() { try { List targets = newsTargetingService.getAllTargets(); - return Response.ok(targets).build(); + return ResponseEntity.ok(targets); } catch (Exception e) { LOG.error("Error when getting the news targets", e); - return Response.serverError().build(); + return ResponseEntity.internalServerError().build(); } } - @Path("allowed") - @GET - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @GetMapping(path = "allowed", produces = MediaType.APPLICATION_JSON) + @Secured("users") @Operation(summary = "Get all allowed news targets of the current user", method = "GET", description = "Get all allowed news targets of the current user") - @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response getAllowedTargets(@Context - HttpServletRequest request) { + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Request fulfilled"), + @ApiResponse(responseCode = "500", description = "Internal server error")}) + public ResponseEntity> getAllowedTargets() { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { List allowedTargets = newsTargetingService.getAllowedTargets(currentIdentity); - return Response.ok(allowedTargets).build(); + return ResponseEntity.ok(allowedTargets); } catch (Exception e) { LOG.error("Error when getting allowed news targets for the user " + currentIdentity.getUserId(), e); - return Response.serverError().build(); + return ResponseEntity.internalServerError().build(); } } - @DELETE - @Path("{targetName}") - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @DeleteMapping(path = "{targetName}", produces = MediaType.APPLICATION_JSON) + @Secured("users") @Operation(summary = "Delete news target", method = "DELETE", description = "This deletes news target") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "News target deleted"), @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "401", description = "User not authorized to delete the news target"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response deleteTarget(@Context - HttpServletRequest request, - @Parameter(description = "Target name", required = true) - @PathParam("targetName") + public Response deleteTarget(@PathVariable("targetName") String targetName, - @Parameter(description = "Time to effectively delete news target", required = false) - @QueryParam("delay") + @Parameter(description = "Time to effectively delete news target") + @RequestParam(name = "delay", required = false) long delay) { org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { @@ -182,16 +171,12 @@ public Response deleteTarget(@Context } } - @Path("{targetName}/undoDelete") - @POST - @RolesAllowed("users") + @PostMapping(path = "{targetName}/undoDelete") + @Secured("users") @Operation(summary = "Undo deleting news target if not yet effectively deleted", method = "POST", description = "Undo deleting news target if not yet effectively deleted") @ApiResponses(value = { @ApiResponse(responseCode = "400", description = "Invalid query input"), @ApiResponse(responseCode = "403", description = "Forbidden operation") }) - public Response undoDeleteTarget(@Context - HttpServletRequest request, - @Parameter(description = "News target name identifier", required = true) - @PathParam("targetName") + public Response undoDeleteTarget(@PathVariable("targetName") String targetName) { if (StringUtils.isBlank(targetName)) { return Response.status(Response.Status.BAD_REQUEST).entity("Target name ist mandatory").build(); @@ -215,21 +200,17 @@ public Response undoDeleteTarget(@Context } } - @POST - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @PostMapping(consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + @Secured("users") @Operation(summary = "Create news target", method = "POST", description = "Create news target") @ApiResponses(value = { @ApiResponse(responseCode = "401", description = "User not authorized to create news target"), @ApiResponse(responseCode = "403", description = "Forbidden operation"), @ApiResponse(responseCode = "409", description = "Conflict operation"), - @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response createNewsTarget(@Context - HttpServletRequest request, @RequestBody(description = "News target to create", required = true) - NewsTargetingEntity newsTargetingEntity) { + @ApiResponse(responseCode = "500", description = "Internal server error")}) + public Response createNewsTarget(@RequestBody NewsTargetingEntity newsTargetingEntity) { if (newsTargetingEntity.getProperties() == null - || newsTargetingEntity.getProperties().get(NewsUtils.TARGET_PERMISSIONS) == null - || newsTargetingEntity.getProperties().get(NewsUtils.TARGET_PERMISSIONS).isEmpty()) { + || newsTargetingEntity.getProperties().get(NewsUtils.TARGET_PERMISSIONS) == null + || newsTargetingEntity.getProperties().get(NewsUtils.TARGET_PERMISSIONS).isEmpty()) { return Response.status(Response.Status.FORBIDDEN).build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); @@ -252,21 +233,16 @@ public Response createNewsTarget(@Context } } - @PUT - @Path("{originalTargetName}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @RolesAllowed("users") + @PutMapping(path = "{originalTargetName}", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + @Secured("users") @Operation(summary = "Update an existing news target", method = "PUT", description = "Update an existing news target") @ApiResponses(value = { @ApiResponse(responseCode = "401", description = "Unauthorized operation"), @ApiResponse(responseCode = "403", description = "Forbidden operation"), @ApiResponse(responseCode = "404", description = "Object not found"), @ApiResponse(responseCode = "409", description = "Conflict operation"), @ApiResponse(responseCode = "500", description = "Internal server error") }) - public Response updateNewsTarget(@Parameter(description = "News target to create", required = true) - NewsTargetingEntity newsTargetingEntity, - @Parameter(description = "Original news target name", required = true) - @PathParam("originalTargetName") + public Response updateNewsTarget(@RequestBody NewsTargetingEntity newsTargetingEntity, + @PathVariable("originalTargetName") String originalTargetName) { if (newsTargetingEntity.getProperties() == null || newsTargetingEntity.getProperties().get(NewsUtils.TARGET_PERMISSIONS) == null diff --git a/content-service/src/main/java/io/meeds/news/search/NewsESSearchResult.java b/content-service/src/main/java/io/meeds/news/search/NewsESSearchResult.java index 378b4c608..e9ed8b500 100644 --- a/content-service/src/main/java/io/meeds/news/search/NewsESSearchResult.java +++ b/content-service/src/main/java/io/meeds/news/search/NewsESSearchResult.java @@ -21,8 +21,10 @@ import java.util.List; +import lombok.Data; import org.exoplatform.social.core.identity.model.Identity; +@Data public class NewsESSearchResult { private String id; @@ -45,83 +47,5 @@ public class NewsESSearchResult { private String activityId; - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public Identity getPoster() { - return poster; - } - - public void setPoster(Identity poster) { - this.poster = poster; - } - - public String getBody() { - return body; - } - - public void setBody(String body) { - this.body = body; - } - - public long getPostedTime() { - return postedTime; - } - - public void setPostedTime(long postedTime) { - this.postedTime = postedTime; - } - - public long getLastUpdatedTime() { - return lastUpdatedTime; - } - - public void setLastUpdatedTime(long lastUpdatedTime) { - this.lastUpdatedTime = lastUpdatedTime; - } - - public String getSpaceDisplayName() { - return spaceDisplayName; - } - - public void setSpaceDisplayName(String spaceDisplayName) { - this.spaceDisplayName = spaceDisplayName; - } - - public String getNewsUrl() { - return newsUrl; - } - - public void setNewsUrl(String newsUrl) { - this.newsUrl = newsUrl; - } - - public List getExcerpts() { - return excerpts; - } - - public void setExcerpts(List excerpts) { - this.excerpts = excerpts; - } - - public String getActivityId() { - return activityId; - } - - public void setActivityId(String activityId) { - this.activityId = activityId; - } + private String lang; } diff --git a/content-service/src/main/java/io/meeds/news/search/NewsIndexingServiceConnector.java b/content-service/src/main/java/io/meeds/news/search/NewsIndexingServiceConnector.java index 651155a63..11da4fbc1 100644 --- a/content-service/src/main/java/io/meeds/news/search/NewsIndexingServiceConnector.java +++ b/content-service/src/main/java/io/meeds/news/search/NewsIndexingServiceConnector.java @@ -50,9 +50,9 @@ public class NewsIndexingServiceConnector extends ElasticIndexingServiceConnector { - public static final String TYPE = "news"; + public static final String TYPE = "news"; - private static final Log LOG = ExoLogger.getLogger(NewsIndexingServiceConnector.class); + private static final Log LOG = ExoLogger.getLogger(NewsIndexingServiceConnector.class); private final NewsService newsService; @@ -62,6 +62,7 @@ public class NewsIndexingServiceConnector extends ElasticIndexingServiceConnecto private final MetadataService metadataService; + public NewsIndexingServiceConnector(IdentityManager identityManager, InitParams initParams, NewsService newsService, @@ -100,8 +101,14 @@ private Document getDocument(String id) { } LOG.debug("Index document for news id={}", id); News news = null; + String newsId = null; + String lang = null; try { - news = newsService.getNewsArticleById(id); + if (StringUtils.contains(id, "-")) { + newsId = StringUtils.substringBefore(id, "-"); + lang = StringUtils.substringAfter(id, "-"); + } + news = newsId != null ? newsService.getNewsArticleByIdAndLang(newsId, lang) : newsService.getNewsArticleById(id); } catch (Exception e) { LOG.error("Error when getting the news " + id, e); } @@ -114,7 +121,10 @@ private Document getDocument(String id) { fields.put("title", news.getTitle()); String body = news.getBody(); - String summary = news.getSummary(); + String summary = ""; + if (news.getProperties() != null) { + summary = news.getProperties().getSummary(); + } if (StringUtils.isBlank(body)) { body = news.getTitle(); } @@ -183,12 +193,13 @@ private Document getDocument(String id) { if (news.getUpdateDate() != null) { fields.put("lastUpdatedTime", String.valueOf(news.getUpdateDate().getTime())); } + fields.put("lang", news.getLang()); DocumentWithMetadata document = new DocumentWithMetadata(); document.setId(id); document.setLastUpdatedDate(news.getUpdateDate()); document.setPermissions(Collections.singleton(ownerIdentityId)); document.setFields(fields); - addDocumentMetadata(document, news.getId()); + addDocumentMetadata(document, id); return document; } diff --git a/content-service/src/main/java/io/meeds/news/search/NewsSearchConnector.java b/content-service/src/main/java/io/meeds/news/search/NewsSearchConnector.java index 6cf79eab2..3c136ecf9 100644 --- a/content-service/src/main/java/io/meeds/news/search/NewsSearchConnector.java +++ b/content-service/src/main/java/io/meeds/news/search/NewsSearchConnector.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.stream.Collectors; +import jakarta.annotation.PostConstruct; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONArray; @@ -44,8 +45,6 @@ import org.exoplatform.commons.utils.PropertyManager; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.configuration.ConfigurationManager; -import org.exoplatform.container.xml.InitParams; -import org.exoplatform.container.xml.PropertiesParam; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.social.core.identity.model.Identity; @@ -56,58 +55,49 @@ import org.exoplatform.social.metadata.tag.TagService; import io.meeds.news.filter.NewsFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +@Component public class NewsSearchConnector { - private static final Log LOG = ExoLogger.getLogger(NewsSearchConnector.class); - - private static final String SEARCH_QUERY_FILE_PATH_PARAM = "query.file.path"; - - public static final String SEARCH_QUERY_TERM = """ - "must":{ "query_string" :{ - "fields": ["body", "posterName", "summary","title"], - "default_operator": "AND", - "query": "@term@"} - },"""; - private final ConfigurationManager configurationManager; + @Autowired + private ConfigurationManager configurationManager; - private final IdentityManager identityManager; + @Autowired + private IdentityManager identityManager; - private final ActivityStorage activityStorage; + @Autowired + private ActivityStorage activityStorage; - private final ElasticSearchingClient client; + @Autowired + private ElasticSearchingClient client; - private final String index; + @Value("${content.es.index:news_alias}") + private String index; - private final String searchType; + @Value("${content.search.type:news}") + private String searchType; + @Value("${content.es.query.path:jar:/news-search-query.json}") private String searchQueryFilePath; private String searchQuery; - public NewsSearchConnector(ConfigurationManager configurationManager, - IdentityManager identityManager, - ActivityStorage activityStorage, - ElasticSearchingClient client, - InitParams initParams) { - this.configurationManager = configurationManager; - this.identityManager = identityManager; - this.activityStorage = activityStorage; - this.client = client; - - PropertiesParam param = initParams.getPropertiesParam("constructor.params"); - this.index = param.getProperty("index"); - this.searchType = param.getProperty("searchType"); - if (initParams.containsKey(SEARCH_QUERY_FILE_PATH_PARAM)) { - searchQueryFilePath = initParams.getValueParam(SEARCH_QUERY_FILE_PATH_PARAM).getValue(); - try { - retrieveSearchQuery(); - } catch (Exception e) { - LOG.error("Can't read elasticsearch search query from path {}", searchQueryFilePath, e); - } - } - } + private static final Log LOG = ExoLogger.getLogger(NewsSearchConnector.class); + + public static final String SEARCH_QUERY_TERM = """ + "must":{ "query_string" :{ + "fields": ["body", "posterName", "summary","title"], + "default_operator": "AND", + "query": "@term@"} + },"""; + @PostConstruct + public void init() { + retrieveSearchQuery(); + } public List search(Identity viewerIdentity, NewsFilter filter) { if (viewerIdentity == null) { throw new IllegalArgumentException("Viewer identity is mandatory"); @@ -121,7 +111,7 @@ public List search(Identity viewerIdentity, NewsFilter filte if (StringUtils.isBlank(filter.getSearchText()) && !filter.isFavorites() && CollectionUtils.isEmpty(filter.getTagNames())) { throw new IllegalArgumentException("Filter term is mandatory"); } - Set streamFeedOwnerIds = activityStorage.getStreamFeedOwnerIds(viewerIdentity); + Set streamFeedOwnerIds = this.activityStorage.getStreamFeedOwnerIds(viewerIdentity); String esQuery = buildQueryStatement(viewerIdentity, streamFeedOwnerIds, filter); String jsonResponse = this.client.sendRequest(esQuery, this.index); return buildResult(jsonResponse); @@ -170,6 +160,7 @@ private List buildResult(String jsonResponse) { String posterId = (String) hitSource.get("posterId"); String spaceDisplayName = (String) hitSource.get("spaceDisplayName"); String newsActivityId = (String) hitSource.get("newsActivityId"); + String language = (String) hitSource.get("lang"); Long postedTime = parseLong(hitSource, "postedTime"); Long lastUpdatedTime = parseLong(hitSource, "lastUpdatedTime"); @@ -185,6 +176,7 @@ private List buildResult(String jsonResponse) { } } newsSearchResult.setId(id); + newsSearchResult.setLang(language); newsSearchResult.setTitle(title); if (posterId != null) { Identity posterIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, posterId); @@ -198,6 +190,9 @@ private List buildResult(String jsonResponse) { String portalName = PortalContainer.getCurrentPortalContainerName(); String portalOwner = CommonsUtils.getCurrentPortalOwner(); newsSearchResult.setNewsUrl("/" + portalName + "/" + portalOwner + "/activity?id=" + newsActivityId); + if (language != null) { + newsSearchResult.setNewsUrl(newsSearchResult.getNewsUrl().concat("&lang=" + language)); + } newsSearchResult.setBody(body); newsSearchResult.setExcerpts(excerpts); diff --git a/content-service/src/main/java/io/meeds/news/service/NewsService.java b/content-service/src/main/java/io/meeds/news/service/NewsService.java index a0226f166..9262f8985 100644 --- a/content-service/src/main/java/io/meeds/news/service/NewsService.java +++ b/content-service/src/main/java/io/meeds/news/service/NewsService.java @@ -19,7 +19,6 @@ */ package io.meeds.news.service; -import java.util.Date; import java.util.List; import org.exoplatform.commons.exception.ObjectNotFoundException; @@ -31,7 +30,9 @@ import io.meeds.news.filter.NewsFilter; import io.meeds.news.model.News; import io.meeds.news.search.NewsESSearchResult; +import org.springframework.stereotype.Service; +@Service public interface NewsService { /** @@ -68,20 +69,6 @@ public interface NewsService { */ boolean canCreateNews(Space space, org.exoplatform.services.security.Identity currentIdentity) throws Exception; - /** - * Update a news If the uploadId of the news is null, the illustration is not - * updated. If the uploadId of the news is empty, the illustration is removed - * (if any). - * - * @param news - * @param updater user attempting to update news - * @param post - * @param publish - * @return updated News - * @throws Exception - */ - News updateNews(News news, String updater, Boolean post, boolean publish) throws Exception; - /** * Update a news If the uploadId of the news is null, the illustration is not * updated. If the uploadId of the news is empty, the illustration is removed @@ -131,44 +118,38 @@ News updateNews(News news, void unpublishNews(String newsId, String publisher) throws Exception; /** - * Retrives a news identified by its technical identifier - * - * @param newsId {@link News} identifier - * @param editMode access mode to news: whether to edit news to to view it. - * @return {@link News} if found else null - * @throws Exception when user doesn't have access to {@link News} - */ - News getNewsById(String newsId, boolean editMode) throws Exception; - - /** - * Retrives a news identified by its technical identifier - * + * Retrieves a news identified by its technical identifier + * * @param newsId {@link News} identifier * @param currentIdentity user attempting to access news * @param editMode access mode to news: whether to edit news to to view it. + * @param newsObjectType news object type to be retrieved. * @return {@link News} if found else null * @throws IllegalAccessException when user doesn't have access to * {@link News} */ News getNewsById(String newsId, org.exoplatform.services.security.Identity currentIdentity, - boolean editMode) throws IllegalAccessException; + boolean editMode, + String newsObjectType) throws IllegalAccessException; /** - * Retrieves a news identified by its technical identifier + * Retrieves a news identified by its technical identifier and corresponding translation * * @param newsId {@link News} identifier * @param currentIdentity user attempting to access news * @param editMode access mode to news: whether to edit news to to view it. * @param newsObjectType news object type to be retrieved. + * @param lang news translate version * @return {@link News} if found else null * @throws IllegalAccessException when user doesn't have access to * {@link News} */ - News getNewsById(String newsId, + News getNewsByIdAndLang(String newsId, org.exoplatform.services.security.Identity currentIdentity, boolean editMode, - String newsObjectType) throws IllegalAccessException; + String newsObjectType, + String lang) throws IllegalAccessException; /** * Retrives a news identified by its technical identifier @@ -178,6 +159,15 @@ News getNewsById(String newsId, */ News getNewsArticleById(String newsId); + /** + * Retrieves a news identified by its technical identifier + * + * @param newsId {@link News} identifier + * @param lang {@link News} news translation language + * @return {@link News} if found else null + */ + News getNewsArticleByIdAndLang(String newsId, String lang); + /** * Get all news * @@ -245,6 +235,21 @@ News getNewsByActivityId(String activityId, org.exoplatform.services.security.Identity currentIdentity) throws IllegalAccessException, ObjectNotFoundException; + /** + * Retrieves a {@link News} by its related activity identifier or its shared activity identifier + * @param activityId {@link ExoSocialActivity} identifier + * @param currentIdentity user attempting to access news + * @param lang {@link News} translation language + * @return {@link News} if found else null + * @throws IllegalAccessException when user doesn't have access to + * {@link News} or {@link ExoSocialActivity} + * @throws ObjectNotFoundException when a {@link News} wasn't found for the given + * activity identifier + */ + News getNewsByActivityIdAndLang(String activityId, + org.exoplatform.services.security.Identity currentIdentity, + String lang) throws IllegalAccessException, ObjectNotFoundException; + /** * Schedule publishing a News * @@ -345,10 +350,28 @@ News createDraftArticleForNewPage(News draftArticle, void deleteArticle(News news, String articleCreator) throws Exception; /** - * @param draftArticleId - * @param draftArticleCreator - * @param deleteIllustration + * Deletes a draft article by its given id + * + * @param draftArticleId draft article id + * @param draftArticleCreator creator + * @throws Exception when error occurs + */ + void deleteDraftArticle(String draftArticleId, String draftArticleCreator) throws Exception; + + /** + * Deletes an article version by its given id and lang + * + * @param articleId article id + * @param lang article version language + * @throws Exception when error occurs + */ + void deleteVersionsByArticleIdAndLang(String articleId, String lang) throws Exception; + + /** + * Get all article available languages by its given id + * + * @param articleId article id * @throws Exception when error occurs */ - void deleteDraftArticle(String draftArticleId, String draftArticleCreator, boolean deleteIllustration) throws Exception; + List getArticleLanguages(String articleId, boolean withDrafts) throws Exception; } diff --git a/content-service/src/main/java/io/meeds/news/service/NewsTargetingService.java b/content-service/src/main/java/io/meeds/news/service/NewsTargetingService.java index c6939bbd6..4406aed3d 100644 --- a/content-service/src/main/java/io/meeds/news/service/NewsTargetingService.java +++ b/content-service/src/main/java/io/meeds/news/service/NewsTargetingService.java @@ -28,7 +28,9 @@ import io.meeds.news.model.News; import io.meeds.news.rest.NewsTargetingEntity; +import org.springframework.stereotype.Service; +@Service public interface NewsTargetingService { public static final MetadataType METADATA_TYPE = new MetadataType(4, "newsTarget"); diff --git a/content-service/src/main/java/io/meeds/news/service/impl/NewsServiceImpl.java b/content-service/src/main/java/io/meeds/news/service/impl/NewsServiceImpl.java index a9e9a7397..cfb59d196 100644 --- a/content-service/src/main/java/io/meeds/news/service/impl/NewsServiceImpl.java +++ b/content-service/src/main/java/io/meeds/news/service/impl/NewsServiceImpl.java @@ -21,28 +21,18 @@ import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; import static io.meeds.news.utils.NewsUtils.NewsObjectType.LATEST_DRAFT; -import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT; +import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT_AND_TITLE; -import java.io.FileInputStream; -import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.OffsetTime; import java.time.ZoneId; import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.TimeZone; +import java.util.*; import java.util.regex.Matcher; import java.util.stream.Stream; +import io.meeds.notes.model.NotePageProperties; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -50,9 +40,6 @@ import org.exoplatform.commons.api.notification.NotificationContext; import org.exoplatform.commons.api.notification.model.PluginKey; import org.exoplatform.commons.exception.ObjectNotFoundException; -import org.exoplatform.commons.file.model.FileItem; -import org.exoplatform.commons.file.services.FileService; -import org.exoplatform.commons.file.services.FileStorageException; import org.exoplatform.commons.notification.impl.NotificationContextImpl; import org.exoplatform.commons.search.index.IndexingService; import org.exoplatform.commons.utils.CommonsUtils; @@ -61,7 +48,6 @@ import org.exoplatform.services.log.Log; import org.exoplatform.services.security.ConversationState; import org.exoplatform.services.security.Identity; -import org.exoplatform.services.security.IdentityConstants; import org.exoplatform.social.common.RealtimeListAccess; import org.exoplatform.social.core.activity.model.ExoSocialActivity; import org.exoplatform.social.core.activity.model.ExoSocialActivityImpl; @@ -78,8 +64,6 @@ import org.exoplatform.social.metadata.model.MetadataObject; import org.exoplatform.social.metadata.model.MetadataType; import org.exoplatform.social.notification.LinkProviderUtils; -import org.exoplatform.upload.UploadResource; -import org.exoplatform.upload.UploadService; import org.exoplatform.wiki.WikiException; import org.exoplatform.wiki.model.DraftPage; import org.exoplatform.wiki.model.Page; @@ -87,6 +71,7 @@ import org.exoplatform.wiki.model.Wiki; import org.exoplatform.wiki.model.WikiType; import org.exoplatform.wiki.service.NoteService; +import org.exoplatform.wiki.service.PageUpdateType; import org.exoplatform.wiki.service.WikiService; import io.meeds.news.filter.NewsFilter; @@ -107,7 +92,12 @@ import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; import io.meeds.news.utils.NewsUtils.NewsObjectType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; +@Primary +@Service public class NewsServiceImpl implements NewsService { public static final String NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME = "Articles"; @@ -122,14 +112,6 @@ public class NewsServiceImpl implements NewsService { public static final String NEWS_METADATA_DRAFT_OBJECT_TYPE = "newsDraftPage"; - public static final String NEWS_FILE_API_NAME_SPACE = "news"; - - public static final String NEWS_SUMMARY = "summary"; - - public static final String NEWS_ILLUSTRATION_ID = "illustrationId"; - - public static final String NEWS_UPLOAD_ID = "uploadId"; - /** The Constant PUBLISHED. */ public final static String PUBLISHED = "published"; @@ -187,51 +169,33 @@ public class NewsServiceImpl implements NewsService { private static final Log LOG = ExoLogger.getLogger(NewsServiceImpl.class); - private final SpaceService spaceService; + @Autowired + private SpaceService spaceService; - private final NoteService noteService; + @Autowired + private NoteService noteService; - private final MetadataService metadataService; + @Autowired + private MetadataService metadataService; - private final FileService fileService; - private final UploadService uploadService; + @Autowired + private NewsTargetingService newsTargetingService; - private final NewsTargetingService newsTargetingService; + @Autowired + private IndexingService indexingService; - private final IndexingService indexingService; + @Autowired + private IdentityManager identityManager; - private final IdentityManager identityManager; + @Autowired + private ActivityManager activityManager; - private final ActivityManager activityManager; + @Autowired + private WikiService wikiService; - private final WikiService wikiService; - - private final NewsSearchConnector newsSearchConnector; - - public NewsServiceImpl(SpaceService spaceService, - NoteService noteService, - MetadataService metadataService, - FileService fileService, - NewsTargetingService newsTargetingService, - IndexingService indexingService, - IdentityManager identityManager, - ActivityManager activityManager, - WikiService wikiService, - UploadService uploadService, - NewsSearchConnector newsSearchConnector) { - this.spaceService = spaceService; - this.noteService = noteService; - this.metadataService = metadataService; - this.fileService = fileService; - this.uploadService = uploadService; - this.newsTargetingService = newsTargetingService; - this.indexingService = indexingService; - this.identityManager = identityManager; - this.activityManager = activityManager; - this.wikiService = wikiService; - this.newsSearchConnector = newsSearchConnector; - } + @Autowired + private NewsSearchConnector newsSearchConnector; /** * {@inheritDoc} @@ -287,14 +251,6 @@ public boolean canCreateNews(Space space, Identity currentIdentity) throws Excep && (NewsUtils.canPublishNews(space.getId(), currentIdentity) || spaceService.canRedactOnSpace(space, currentIdentity)); } - /** - * {@inheritDoc} - */ - @Override - public News updateNews(News news, String updater, Boolean post, boolean publish) throws Exception { - return null; - } - /** * {@inheritDoc} */ @@ -310,7 +266,8 @@ public News updateNews(News news, throw new IllegalAccessException("User " + updater + " is not authorized to update news"); } Identity updaterIdentity = NewsUtils.getUserIdentity(updater); - News originalNews = getNewsById(news.getId(), updaterIdentity, false, newsObjectType); + String newsId = news.getTargetPageId() != null ? news.getTargetPageId() : news.getId(); + News originalNews = getNewsById(newsId, updaterIdentity, false, newsObjectType); List oldTargets = newsTargetingService.getTargetsByNews(news); boolean canPublish = NewsUtils.canPublishNews(news.getSpaceId(), updaterIdentity); Set previousMentions = NewsUtils.processMentions(originalNews.getOriginalBody(), @@ -320,12 +277,15 @@ public News updateNews(News news, } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { return createOrUpdateDraftForExistingPage(news, updater); } + else if (ARTICLE.name().equalsIgnoreCase(newsObjectType) && CONTENT_AND_TITLE.name().equalsIgnoreCase(newsUpdateType) && StringUtils.isNotEmpty(news.getLang())) { + return addNewArticleVersionWithLang(news, updaterIdentity); + } if (publish != news.isPublished() && news.isCanPublish()) { news.setPublished(publish); if (news.isPublished()) { publishNews(news, updater); } else { - unpublishNews(news.getId(), updater); + unpublishNews(newsId, updater); } } boolean displayed = !(StringUtils.equals(news.getPublicationState(), STAGED)); @@ -349,7 +309,7 @@ public News updateNews(News news, if (POSTED.equals(news.getPublicationState())) { // Send mention notifs - if (StringUtils.isNotEmpty(news.getId()) && news.getCreationDate() != null) { + if (StringUtils.isNotEmpty(newsId) && news.getCreationDate() != null) { News newMentionedNews = news; if (!previousMentions.isEmpty()) { // clear old mentions from news body before sending a custom object to @@ -359,7 +319,7 @@ public News updateNews(News news, } sendNotification(updater, newMentionedNews, NotificationConstants.NOTIFICATION_CONTEXT.MENTION_IN_NEWS); } - indexingService.reindex(NewsIndexingServiceConnector.TYPE, String.valueOf(news.getId())); + indexingService.reindex(NewsIndexingServiceConnector.TYPE, String.valueOf(newsId)); } if (!news.getPublicationState().isEmpty() && !DRAFT.equals(news.getPublicationState())) { if (post != null) { @@ -380,7 +340,7 @@ public void deleteNews(String newsId, Identity currentIdentity, String newsObjec throw new IllegalAccessException("User " + currentIdentity.getUserId() + " is not authorized to delete news"); } if (NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { - deleteDraftArticle(newsId, currentIdentity.getUserId(), true); + deleteDraftArticle(newsId, currentIdentity.getUserId()); } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { Page newsArticlePage = noteService.getNoteById(newsId); if (newsArticlePage != null) { @@ -391,8 +351,7 @@ public void deleteNews(String newsId, Identity currentIdentity, String newsObjec // check if the latest draft has the same illustration // with the news article to do not remove it. deleteDraftArticle(draft.getId(), - currentIdentity.getUserId(), - !isSameIllustration(draft.getId(), newsArticlePage.getId())); + currentIdentity.getUserId()); } } } else { @@ -404,6 +363,10 @@ public void deleteNews(String newsId, Identity currentIdentity, String newsObjec MetadataObject newsMetadataObject = new MetadataObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, newsId); metadataService.deleteMetadataItemsByObject(newsMetadataObject); indexingService.unindex(NewsIndexingServiceConnector.TYPE, String.valueOf(news.getId())); + List articleLanguages = getArticleLanguages(newsId, false); + if (CollectionUtils.isNotEmpty(articleLanguages)) { + articleLanguages.forEach(lang -> indexingService.unindex(NewsIndexingServiceConnector.TYPE, news.getId().concat("-").concat(lang))); + } NewsUtils.broadcastEvent(NewsUtils.DELETE_NEWS, currentIdentity.getUserId(), news); } } @@ -436,15 +399,19 @@ public void publishNews(News newsToPublish, String publisher) throws Exception { Date updatedDate = Calendar.getInstance().getTime(); metadataItem.setUpdatedDate(updatedDate.getTime()); String publisherId = identityManager.getOrCreateUserIdentity(publisherIdentity.getUserId()).getId(); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(publisherId)); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(publisherId), false); } if (newsToPublish.getTargets() != null) { newsTargetingService.deleteNewsTargets(news, publisher); newsTargetingService.saveNewsTarget(news, displayed, newsToPublish.getTargets(), publisher); } + news.setAudience(newsToPublish.getAudience()); NewsUtils.broadcastEvent(NewsUtils.PUBLISH_NEWS, news.getId(), news); + Space space = spaceService.getSpaceById(news.getSpaceId()); + Map shareArticleEventListenerData = new HashMap<>(); + shareArticleEventListenerData.putAll(Map.of(NEWS_ATTACHMENTS_IDS, getArticleAttachmentIdsToShare(Long.parseLong(news.getSpaceId()), Long.parseLong(newsPageObject.getId())),"space", space, NEWS_AUDIENCE, news.getAudience(),ARTICLE_CONTENT, news.getBody())); + NewsUtils.broadcastEvent(NewsUtils.SHARE_CONTENT_ATTACHMENTS,this, shareArticleEventListenerData); try { - news.setAudience(newsToPublish.getAudience()); sendNotification(publisher, news, NotificationConstants.NOTIFICATION_CONTEXT.PUBLISH_NEWS); } catch (Error | Exception e) { LOG.warn("Error sending notification when publishing news with Id " + news.getId(), e); @@ -478,7 +445,7 @@ public void unpublishNews(String newsId, String publisher) throws Exception { Date updatedDate = Calendar.getInstance().getTime(); newsMetadataItem.setUpdatedDate(updatedDate.getTime()); String publisherId = identityManager.getOrCreateUserIdentity(publisher).getId(); - metadataService.updateMetadataItem(newsMetadataItem, Long.parseLong(publisherId)); + metadataService.updateMetadataItem(newsMetadataItem, Long.parseLong(publisherId), false); } } @@ -486,37 +453,33 @@ public void unpublishNews(String newsId, String publisher) throws Exception { * {@inheritDoc} */ @Override - public News getNewsById(String newsId, boolean editMode) throws Exception { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public News getNewsById(String newsId, Identity currentIdentity, boolean editMode) throws IllegalAccessException { - return null; + public News getNewsById(String newsId, + Identity currentIdentity, + boolean editMode, + String newsObjectType) throws IllegalAccessException { + return getNewsByIdAndLang(newsId, currentIdentity, editMode, newsObjectType, null); } /** * {@inheritDoc} */ @Override - public News getNewsById(String newsId, + public News getNewsByIdAndLang(String newsId, Identity currentIdentity, boolean editMode, - String newsObjectType) throws IllegalAccessException { + String newsObjectType, + String lang) throws IllegalAccessException { News news = null; try { if (newsObjectType == null) { throw new IllegalArgumentException("Required argument news object type could not be null"); } - if (NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { + if (NewsObjectType.DRAFT.name().equalsIgnoreCase(newsObjectType)) { news = buildDraftArticle(newsId, currentIdentity.getUserId()); - } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { - news = buildLatestDraftArticle(newsId, currentIdentity.getUserId()); - } else if (ARTICLE.name().toLowerCase().equals(newsObjectType)) { - news = buildArticle(newsId); + } else if (LATEST_DRAFT.name().equalsIgnoreCase(newsObjectType)) { + news = buildLatestDraftArticle(newsId, currentIdentity.getUserId(), lang); + } else if (ARTICLE.name().equalsIgnoreCase(newsObjectType)) { + news = buildArticle(newsId, lang, true); } } catch (Exception exception) { LOG.error("An error occurred while retrieving news with id {}", newsId, exception); @@ -550,9 +513,14 @@ public News getNewsById(String newsId, @Override public News getNewsArticleById(String newsId) { + return getNewsArticleByIdAndLang(newsId, null); + } + + @Override + public News getNewsArticleByIdAndLang(String newsId, String lang) { News news = null; try { - news = buildArticle(newsId); + news = buildArticle(newsId, lang, true); news.setTargets(newsTargetingService.getTargetsByNews(news)); } catch (Exception exception) { LOG.error("An error occurred while retrieving news with id {}", newsId, exception); @@ -602,7 +570,7 @@ public List getNewsByTargetName(NewsFilter newsFilter, String targetName, newsTargetingService.getNewsTargetItemsByTargetName(targetName, newsFilter.getOffset(), 0); return newsTargetItems.stream().filter(target -> { try { - News news = getNewsById(target.getObjectId(), currentIdentity, false, ARTICLE.name().toLowerCase()); + News news = getNewsArticleById(target.getObjectId()); return news != null && (StringUtils.isEmpty(news.getAudience()) || news.getAudience().equals(NewsUtils.ALL_NEWS_AUDIENCE) || news.isSpaceMember()); } catch (Exception e) { @@ -610,9 +578,8 @@ public List getNewsByTargetName(NewsFilter newsFilter, String targetName, } }).map(target -> { try { - News news = getNewsById(target.getObjectId(), currentIdentity, false, ARTICLE.name().toLowerCase()); + News news = getNewsByIdAndLang(target.getObjectId(), currentIdentity, false, ARTICLE.name().toLowerCase(), newsFilter.getLang()); news.setPublishDate(new Date(target.getCreatedDate())); - news.setIllustration(null); return news; } catch (Exception e) { return null; @@ -667,7 +634,7 @@ public void markAsRead(News news, String userId) throws Exception { } metadataItem.setProperties(properties); String userIdentityId = identityManager.getOrCreateUserIdentity(userId).getId(); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentityId)); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentityId), false); } } catch (Exception exception) { LOG.error("Failed to mark news article " + news.getId() + " as read for current user", exception); @@ -698,6 +665,12 @@ public List searchNews(NewsFilter filter, @Override public News getNewsByActivityId(String activityId, Identity currentIdentity) throws IllegalAccessException, ObjectNotFoundException { + return getNewsByActivityIdAndLang(activityId, currentIdentity, null); + } + + @Override + public News getNewsByActivityIdAndLang(String activityId, Identity currentIdentity, String lang) throws IllegalAccessException, + ObjectNotFoundException { ExoSocialActivity activity = activityManager.getActivity(activityId); if (activity == null) { throw new ObjectNotFoundException("Activity with id " + activityId + " wasn't found"); @@ -721,13 +694,12 @@ public News getNewsByActivityId(String activityId, Identity currentIdentity) thr throw new IllegalAccessException("Shared Activity '" + activityId + "' Poster " + activity.getPosterId() + " isn't found"); } - return getNewsByActivityId(originalActivityId, NewsUtils.getUserIdentity(sharedActivityPosterIdentity.getRemoteId())); + return getNewsByActivityIdAndLang(originalActivityId, NewsUtils.getUserIdentity(sharedActivityPosterIdentity.getRemoteId()), lang); } throw new ObjectNotFoundException("Activity with id " + activityId + " isn't of type news nor a shared news"); } - return getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase()); + return getNewsByIdAndLang(newsId, currentIdentity, false, ARTICLE.name().toLowerCase(), lang); } - /** * {@inheritDoc} */ @@ -747,10 +719,12 @@ public News scheduleNews(News news, Identity currentIdentity, String newsObjectT updateNewsArticle(news, currentIdentity, NewsUtils.NewsUpdateType.SCHEDULE.name().toLowerCase()); } if (news != null) { - if (news.isPublished()) { - publishNews(news, currentIdentity.getUserId()); - } else { - unpublishNews(news.getId(), currentIdentity.getUserId()); + if (NewsUtils.canPublishNews(space.getId(), currentIdentity)) { + if (news.isPublished()) { + publishNews(news, currentIdentity.getUserId()); + } else { + unpublishNews(news.getId(), currentIdentity.getUserId()); + } } // set the url and the space url to the scheduled news news.setUrl(NewsUtils.buildNewsArticleUrl(news, currentIdentity.getUserId())); @@ -767,36 +741,7 @@ public News scheduleNews(News news, Identity currentIdentity, String newsObjectT public News unScheduleNews(News news, String pageOwnerId, String articleCreator) throws Exception { News existingNews = getNewsArticleById(news.getId()); if (existingNews != null) { - Map illustrationInfo = getArticleIllustrationInfo(news); - - news.setId(null); - news.setUploadId(null); news = createDraftArticleForNewPage(news, pageOwnerId, articleCreator, System.currentTimeMillis()); - - if (!MapUtils.isEmpty(illustrationInfo)) { - MetadataItem draftMetadataItem = - metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, - news.getId(), - null, - Long.parseLong(news.getSpaceId()))) - .stream() - .findFirst() - .orElse(null); - Map draftProperties = draftMetadataItem.getProperties(); - if (draftProperties == null) { - draftProperties = new HashMap<>(); - } - if (illustrationInfo.get(NEWS_UPLOAD_ID) != null) { - draftProperties.put(NEWS_UPLOAD_ID, illustrationInfo.get(NEWS_UPLOAD_ID)); - } - if (illustrationInfo.get(NEWS_ILLUSTRATION_ID) != null) { - draftProperties.put(NEWS_ILLUSTRATION_ID, illustrationInfo.get(NEWS_ILLUSTRATION_ID)); - } - draftMetadataItem.setProperties(draftProperties); - String draftArticleMetadataItemUpdaterIdentityId = identityManager.getOrCreateUserIdentity(articleCreator).getId(); - metadataService.updateMetadataItem(draftMetadataItem, Long.parseLong(draftArticleMetadataItemUpdaterIdentityId)); - } deleteArticle(existingNews, articleCreator); return buildDraftArticle(news.getId(), articleCreator); } @@ -893,39 +838,26 @@ public void shareNews(News news, } metadataItem.setProperties(properties); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentity.getId())); - - NewsUtils.broadcastEvent(NewsUtils.SHARE_CONTENT_ATTACHMENTS, - Map.of(NEWS_ATTACHMENTS_IDS, - getArticleAttachmentIdsToShare(news, - Long.parseLong(space.getId()), - Long.parseLong(newsPageObject.getId())), - ARTICLE_CONTENT, - news.getBody()), - space); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentity.getId()), false); + + Map shareArticleEventListenerData = new HashMap<>(); + shareArticleEventListenerData.put(NEWS_ATTACHMENTS_IDS, getArticleAttachmentIdsToShare( + Long.parseLong(space.getId()), + Long.parseLong(newsPageObject.getId()))); + shareArticleEventListenerData.putAll(Map.of("space", space, NEWS_AUDIENCE, news.getAudience(),ARTICLE_CONTENT, news.getBody())); + NewsUtils.broadcastEvent(NewsUtils.SHARE_CONTENT_ATTACHMENTS,this, shareArticleEventListenerData); NewsUtils.broadcastEvent(NewsUtils.SHARE_NEWS, userIdentity.getRemoteId(), news); } } - private List getArticleAttachmentIdsToShare(News article, long spaceId, long articlePageId) { - List attachmentIds = new ArrayList<>(); - PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(articlePageId, null); - NewsPageVersionObject newsPageVersionObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, - pageVersion.getId(), - null, - spaceId); - List newsPageVersionMetadataItems = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - newsPageVersionObject); - Map newsPageVersionMetadataItemProperties = newsPageVersionMetadataItems.get(0).getProperties(); - if (!MapUtils.isEmpty(newsPageVersionMetadataItems.get(0).getProperties())) { - - if (newsPageVersionMetadataItemProperties.containsKey(NEWS_ATTACHMENTS_IDS) - && newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS) != null) { - attachmentIds.addAll(List.of(newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS).split(";"))); - } - } - return attachmentIds; + @Override + public void deleteVersionsByArticleIdAndLang(String id, String lang) throws Exception { + News article = getNewsArticleById(id); + noteService.deleteVersionsByNoteIdAndLang(Long.parseLong(id), lang); + NewsUtils.broadcastEvent(NewsUtils.REMOVE_ARTICLE_TRANSLATION, article.getAuthor(), article); + String newsTranslationId = id.concat("-").concat(lang); + indexingService.unindex(NewsIndexingServiceConnector.TYPE, newsTranslationId); } /** @@ -961,8 +893,16 @@ public News createDraftArticleForNewPage(News draftArticle, draftArticlePage.setContent(draftArticle.getBody()); draftArticlePage.setParentPageId(newsArticlesRootNotePage.getId()); draftArticlePage.setAuthor(draftArticle.getAuthor()); - draftArticlePage = noteService.createDraftForNewPage(draftArticlePage, creationDate); + draftArticlePage.setProperties(draftArticle.getProperties()); + draftArticlePage = + noteService.createDraftForNewPage(draftArticlePage, + creationDate, + Long.parseLong(identityManager.getOrCreateUserIdentity(draftArticleCreator) + .getId())); + + draftArticle.setProperties(draftArticlePage.getProperties()); + draftArticle.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftArticle.getProperties(), draftArticlePage.getLang())); draftArticle.setId(draftArticlePage.getId()); draftArticle.setCreationDate(draftArticlePage.getCreatedDate()); draftArticle.setUpdateDate(draftArticlePage.getUpdatedDate()); @@ -974,20 +914,11 @@ public News createDraftArticleForNewPage(News draftArticle, Long.parseLong(draftArticleSpace.getId())); String draftArticleMetadataItemCreatorIdentityId = identityManager.getOrCreateUserIdentity(draftArticleCreator).getId(); Map draftArticleMetadataItemProperties = new HashMap<>(); - // save illustration - if (StringUtils.isNotEmpty(draftArticle.getUploadId())) { - Long draftArticleIllustrationId = saveArticleIllustration(draftArticle.getUploadId(), null); - setArticleIllustration(draftArticle, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); - draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, draftArticle.getUploadId()); - } - if (StringUtils.isNotEmpty(draftArticle.getSummary())) { - draftArticleMetadataItemProperties.put(NEWS_SUMMARY, draftArticle.getSummary()); - } metadataService.createMetadataItem(draftArticleMetaDataObject, NEWS_METADATA_KEY, draftArticleMetadataItemProperties, - Long.parseLong(draftArticleMetadataItemCreatorIdentityId)); + Long.parseLong(draftArticleMetadataItemCreatorIdentityId), + false); return draftArticle; } @@ -1033,6 +964,7 @@ public News createNewsArticlePage(News newsArticle, String newsArticleCreator) t newsArticlePage.setParentPageId(newsArticlesRootNotePage.getId()); newsArticlePage.setAuthor(newsArticle.getAuthor()); newsArticlePage.setLang(null); + newsArticlePage.setProperties(newsArticle.getProperties()); newsArticlePage = noteService.createNote(wiki, newsArticlesRootNotePage.getName(), newsArticlePage, poster); // create the version noteService.createVersionOfNote(newsArticlePage, poster.getUserId()); @@ -1040,7 +972,10 @@ public News createNewsArticlePage(News newsArticle, String newsArticleCreator) t PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(newsArticlePage.getId()), null); // set properties newsArticle.setId(newsArticlePage.getId()); + newsArticle.setLang(newsArticlePage.getLang()); newsArticle.setCreationDate(pageVersion.getCreatedDate()); + newsArticle.setProperties(newsArticlePage.getProperties()); + newsArticle.setIllustrationURL(NewsUtils.buildIllustrationUrl(newsArticlePage.getProperties(), newsArticle.getLang())); NewsPageVersionObject newsArticleVersionMetaDataObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, pageVersion.getId(), @@ -1049,36 +984,12 @@ public News createNewsArticlePage(News newsArticle, String newsArticleCreator) t String newsArticleMetadataItemCreatorIdentityId = identityManager.getOrCreateUserIdentity(newsArticleCreator).getId(); Map newsArticleVersionMetadataItemProperties = new HashMap<>(); - NewsDraftObject newsDraftObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, - draftNewsId, - null, - Long.parseLong(space.getId())); - MetadataItem draftMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsDraftObject) - .stream() - .findFirst() - .orElse(null); - - if (draftMetadataItem != null && draftMetadataItem.getProperties() != null - && !draftMetadataItem.getProperties().isEmpty()) { - if (draftMetadataItem.getProperties().containsKey(NEWS_UPLOAD_ID)) { - newsArticleVersionMetadataItemProperties.put(NEWS_UPLOAD_ID, draftMetadataItem.getProperties().get(NEWS_UPLOAD_ID)); - } - if (draftMetadataItem.getProperties().containsKey(NEWS_ILLUSTRATION_ID)) { - newsArticleVersionMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, - draftMetadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); - setArticleIllustration(newsArticle, - Long.parseLong(newsArticleVersionMetadataItemProperties.get(NEWS_ILLUSTRATION_ID)), - ARTICLE.name().toLowerCase()); - } - } // create the page version metadata item - if (StringUtils.isNotEmpty(newsArticle.getSummary())) { - newsArticleVersionMetadataItemProperties.put(NEWS_SUMMARY, newsArticle.getSummary()); - } metadataService.createMetadataItem(newsArticleVersionMetaDataObject, NEWS_METADATA_KEY, newsArticleVersionMetadataItemProperties, - Long.parseLong(newsArticleMetadataItemCreatorIdentityId)); + Long.parseLong(newsArticleMetadataItemCreatorIdentityId), + false); // create metadata item page NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, @@ -1101,9 +1012,10 @@ public News createNewsArticlePage(News newsArticle, String newsArticleCreator) t metadataService.createMetadataItem(newsPageObject, NEWS_METADATA_KEY, newsPageProperties, - Long.parseLong(newsArticleMetadataItemCreatorIdentityId)); + Long.parseLong(newsArticleMetadataItemCreatorIdentityId), + false); // delete the draft - deleteDraftArticle(draftNewsId, poster.getUserId(), newsArticle.getIllustration() == null); + deleteDraftArticle(draftNewsId, poster.getUserId()); return newsArticle; } } @@ -1125,12 +1037,15 @@ public News createDraftForExistingPage(News draftArticle, draftArticlePage.setContent(draftArticle.getBody()); draftArticlePage.setParentPageId(targetArticlePage.getParentPageId()); draftArticlePage.setAuthor(draftArticle.getAuthor()); - draftArticlePage.setLang(null); + draftArticlePage.setLang(draftArticle.getLang()); + draftArticlePage.setProperties(draftArticle.getProperties()); draftArticlePage = noteService.createDraftForExistPage(draftArticlePage, targetArticlePage, null, creationDate, updater); draftArticle.setDraftUpdateDate(draftArticlePage.getCreatedDate()); draftArticle.setDraftUpdater(draftArticlePage.getAuthor()); + draftArticle.setTargetPageId(draftArticlePage.getTargetPageId()); + draftArticle.setProperties(draftArticlePage.getProperties()); draftArticle.setId(draftArticlePage.getId()); NewsLatestDraftObject latestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, draftArticlePage.getId(), @@ -1138,40 +1053,14 @@ public News createDraftForExistingPage(News draftArticle, Long.parseLong(draftArticle.getSpaceId())); Map draftArticleMetadataItemProperties = new HashMap<>(); - if (StringUtils.isNotEmpty(draftArticle.getSummary())) { - draftArticleMetadataItemProperties.put(NEWS_SUMMARY, draftArticle.getSummary()); - } draftArticleMetadataItemProperties.put(NEWS_ACTIVITY_POSTED, String.valueOf(draftArticle.isActivityPosted())); - // check if the article has an illustration to link it to the created draft - PageVersion latestPageVersion = - noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(targetArticlePage.getId()), null); - if (latestPageVersion != null) { - // fetch the version related metadata item - MetadataItem pageVersionMetadataItem = - metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, - latestPageVersion.getId(), - null, - Long.parseLong(draftArticle.getSpaceId()))) - .stream() - .findFirst() - .orElse(null); - Map pageVersionMetadataItemProperties = pageVersionMetadataItem.getProperties(); - if (pageVersionMetadataItemProperties != null && !pageVersionMetadataItemProperties.isEmpty()) { - if (pageVersionMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID)) { - draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, - pageVersionMetadataItemProperties.get(NEWS_ILLUSTRATION_ID)); - } - if (pageVersionMetadataItemProperties.containsKey(NEWS_UPLOAD_ID)) { - draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, pageVersionMetadataItemProperties.get(NEWS_UPLOAD_ID)); - } - } - } + String draftArticleMetadataItemCreatorIdentityId = identityManager.getOrCreateUserIdentity(updater).getId(); metadataService.createMetadataItem(latestDraftObject, NEWS_METADATA_KEY, draftArticleMetadataItemProperties, - Long.parseLong(draftArticleMetadataItemCreatorIdentityId)); + Long.parseLong(draftArticleMetadataItemCreatorIdentityId), + false); return draftArticle; } @@ -1187,7 +1076,7 @@ public void deleteArticle(News news, String articleCreator) throws Exception { try { DraftPage latestDraftPage = noteService.getLatestDraftOfPage(articlePage, articleCreator); if (latestDraftPage != null) { - deleteDraftArticle(latestDraftPage.getId(), articleCreator, true); + deleteDraftArticle(latestDraftPage.getId(), articleCreator); } else { hasDraft = false; } @@ -1210,7 +1099,7 @@ public void deleteArticle(News news, String articleCreator) throws Exception { properties.put(NEWS_DELETED, String.valueOf(true)); metadataItem.setProperties(properties); String currentIdentityId = identityManager.getOrCreateUserIdentity(articleCreator).getId(); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(currentIdentityId)); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(currentIdentityId), false); } } } @@ -1220,9 +1109,18 @@ public void deleteArticle(News news, String articleCreator) throws Exception { * {@inheritDoc} */ @Override - public void deleteDraftArticle(String draftArticleId, String draftArticleCreator, boolean deleteIllustration) throws Exception { + public void deleteDraftArticle(String draftArticleId, String draftArticleCreator) throws Exception { DraftPage draftArticlePage = noteService.getDraftNoteById(draftArticleId, draftArticleCreator); if (draftArticlePage != null) { + if (draftArticlePage.getProperties() != null && draftArticlePage.getProperties().getFeaturedImage() != null) { + long featuredImageId = draftArticlePage.getProperties().getFeaturedImage().getId(); + String userIdentityId = identityManager.getOrCreateUserIdentity(draftArticleCreator).getId(); + noteService.removeNoteFeaturedImage(Long.parseLong(draftArticlePage.getId()), + featuredImageId, + null, + true, + Long.parseLong(userIdentityId)); + } noteService.removeDraftById(draftArticlePage.getId()); Space draftArticleSpace = spaceService.getSpaceByGroupId(draftArticlePage.getWikiOwner()); MetadataObject draftArticleMetaDataObject = @@ -1234,86 +1132,28 @@ public void deleteDraftArticle(String draftArticleId, String draftArticleCreator List draftArticleMetadataItems = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, draftArticleMetaDataObject); - if (draftArticleMetadataItems != null && !draftArticleMetadataItems.isEmpty()) { - Map draftArticleMetadataItemProperties = draftArticleMetadataItems.get(0).getProperties(); - if (deleteIllustration) { - if (draftArticleMetadataItemProperties != null && draftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - FileItem draftArticleIllustrationFileItem = - fileService.getFile(Long.parseLong(draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID))); - fileService.deleteFile(draftArticleIllustrationFileItem.getFileInfo().getId()); - } - } - metadataService.deleteMetadataItem(draftArticleMetadataItems.get(0).getId(), false); - } + metadataService.deleteMetadataItem(draftArticleMetadataItems.getFirst().getId(), false); } } + @Override + public List getArticleLanguages(String articleId, boolean withDrafts) throws WikiException { + return noteService.getPageAvailableTranslationLanguages(Long.parseLong(articleId), withDrafts); + } + private News updateDraftArticleForNewPage(News draftArticle, String draftArticleUpdater) throws WikiException, - IllegalAccessException, - FileStorageException { + IllegalAccessException { DraftPage draftArticlePage = noteService.getDraftNoteById(draftArticle.getId(), draftArticleUpdater); if (draftArticlePage != null) { draftArticlePage.setTitle(draftArticle.getTitle()); draftArticlePage.setContent(draftArticle.getBody()); + draftArticlePage.setProperties(draftArticle.getProperties()); // created and updated date set by default during the draft creation - // process - draftArticlePage = noteService.updateDraftForNewPage(draftArticlePage, System.currentTimeMillis()); - Space draftArticleSpace = spaceService.getSpaceByGroupId(draftArticlePage.getWikiOwner()); - NewsDraftObject draftArticleMetaDataObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, - draftArticlePage.getId(), - null, - Long.parseLong(draftArticleSpace.getId())); - List draftArticleMetadataItems = - metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - draftArticleMetaDataObject); - if (draftArticleMetadataItems != null && !draftArticleMetadataItems.isEmpty()) { - MetadataItem draftArticleMetadataItem = draftArticleMetadataItems.get(0); - Map draftArticleMetadataItemProperties = draftArticleMetadataItem.getProperties(); - if (draftArticleMetadataItemProperties == null) { - draftArticleMetadataItemProperties = new HashMap<>(); - } - // create or update the illustration - if (StringUtils.isNotEmpty(draftArticle.getUploadId())) { - if (draftArticleMetadataItemProperties.containsKey(NEWS_UPLOAD_ID) - && draftArticleMetadataItemProperties.get(NEWS_UPLOAD_ID) != null - && draftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - if (!draftArticleMetadataItemProperties.get(NEWS_UPLOAD_ID).equals(draftArticle.getUploadId())) { - FileItem draftArticleIllustrationFileItem = - fileService.getFile(Long.parseLong(draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID))); - Long draftArticleIllustrationId = saveArticleIllustration(draftArticle.getUploadId(), - draftArticleIllustrationFileItem.getFileInfo().getId()); - draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - setArticleIllustration(draftArticle, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); - } - } else { - Long draftArticleIllustrationId = saveArticleIllustration(draftArticle.getUploadId(), null); - draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, draftArticle.getUploadId()); - setArticleIllustration(draftArticle, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); - } - draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, draftArticle.getUploadId()); - } else { - if (draftArticleMetadataItemProperties.containsKey(NEWS_UPLOAD_ID) - && draftArticleMetadataItemProperties.get(NEWS_UPLOAD_ID) != null - && draftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null && draftArticle.getUploadId() != null) { - draftArticleMetadataItemProperties.remove(NEWS_UPLOAD_ID); - FileItem draftArticleIllustrationFileItem = - fileService.getFile(Long.parseLong(draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID))); - draftArticleMetadataItemProperties.remove(NEWS_ILLUSTRATION_ID); - - fileService.deleteFile(draftArticleIllustrationFileItem.getFileInfo().getId()); - } - } - if (StringUtils.isNotEmpty(draftArticle.getSummary())) { - draftArticleMetadataItemProperties.put(NEWS_SUMMARY, draftArticle.getSummary()); - } - draftArticleMetadataItem.setProperties(draftArticleMetadataItemProperties); - String draftArticleMetadataItemUpdaterIdentityId = identityManager.getOrCreateUserIdentity(draftArticleUpdater).getId(); - metadataService.updateMetadataItem(draftArticleMetadataItem, Long.parseLong(draftArticleMetadataItemUpdaterIdentityId)); - } + DraftPage draftPage = noteService.updateDraftForNewPage(draftArticlePage, + System.currentTimeMillis(), + Long.parseLong(identityManager.getOrCreateUserIdentity(draftArticleUpdater).getId())); + draftArticle.setProperties(draftPage.getProperties()); + draftArticle.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftPage.getProperties(), draftArticle.getLang())); return draftArticle; } return null; @@ -1330,6 +1170,13 @@ private News buildDraftArticle(String draftArticleId, String currentUserId) thro draftArticle.setUpdateDate(draftArticlePage.getUpdatedDate()); draftArticle.setDraftUpdateDate(draftArticlePage.getUpdatedDate()); draftArticle.setDraftUpdaterUserName(draftArticlePage.getAuthor()); + draftArticle.setLang(draftArticlePage.getLang()); + draftArticle.setProperties(draftArticlePage.getProperties()); + if (draftArticlePage.getProperties() != null && draftArticlePage.getProperties().getFeaturedImage() != null + && draftArticlePage.getProperties().getFeaturedImage().getId() != 0) { + draftArticle.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftArticlePage.getProperties(), + draftArticlePage.getLang())); + } org.exoplatform.social.core.identity.model.Identity draftUpdaterIdentity = identityManager.getOrCreateUserIdentity(currentUserId); if (draftUpdaterIdentity != null && draftUpdaterIdentity.getProfile() != null) { @@ -1381,21 +1228,8 @@ private News buildDraftArticle(String draftArticleId, String currentUserId) thro private void buildArticleVersionProperties(News article, List newsPageVersionMetadataItems) { if (!CollectionUtils.isEmpty(newsPageVersionMetadataItems)) { - Map newsPageVersionMetadataItemProperties = newsPageVersionMetadataItems.get(0).getProperties(); + Map newsPageVersionMetadataItemProperties = newsPageVersionMetadataItems.getFirst().getProperties(); if (!MapUtils.isEmpty(newsPageVersionMetadataItemProperties)) { - if (newsPageVersionMetadataItemProperties.containsKey(NEWS_SUMMARY)) { - article.setSummary(newsPageVersionMetadataItemProperties.get(NEWS_SUMMARY)); - } - if (newsPageVersionMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && newsPageVersionMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - setArticleIllustration(article, - Long.valueOf(newsPageVersionMetadataItemProperties.get(NEWS_ILLUSTRATION_ID)), - ARTICLE.name().toLowerCase()); - } - if (newsPageVersionMetadataItemProperties.containsKey(NEWS_UPLOAD_ID) - && newsPageVersionMetadataItemProperties.get(NEWS_UPLOAD_ID) != null) { - article.setUploadId(newsPageVersionMetadataItemProperties.get(NEWS_UPLOAD_ID)); - } if (newsPageVersionMetadataItemProperties.containsKey(NEWS_ATTACHMENTS_IDS) && newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS) != null) { List attachmentsIds = List.of(newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS).split(";")); @@ -1406,7 +1240,6 @@ private void buildArticleVersionProperties(News article, List news } private void buildArticleProperties(News article, - Page articlePage, String currentUsername, MetadataItem metadataItem) throws Exception { if (metadataItem != null && !MapUtils.isEmpty(metadataItem.getProperties())) { @@ -1458,20 +1291,11 @@ private void buildDraftArticleProperties(News draftArticle, MetadataItem metadat if (metadataItem != null) { Map draftArticleMetadataItemProperties = metadataItem.getProperties(); if (!MapUtils.isEmpty(draftArticleMetadataItemProperties)) { - if (draftArticleMetadataItemProperties.containsKey(NEWS_SUMMARY)) { - draftArticle.setSummary(draftArticleMetadataItemProperties.get(NEWS_SUMMARY)); - } if (draftArticleMetadataItemProperties.containsKey(NEWS_ACTIVITY_POSTED)) { draftArticle.setActivityPosted(Boolean.parseBoolean(draftArticleMetadataItemProperties.get(NEWS_ACTIVITY_POSTED))); } else { draftArticle.setActivityPosted(false); } - if (draftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - setArticleIllustration(draftArticle, - Long.valueOf(draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID)), - NewsObjectType.DRAFT.name().toLowerCase()); - } } if (metadataItem.getParentObjectId() != null) { NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, @@ -1520,12 +1344,13 @@ private List getPublishedArticles(NewsFilter filter, Identity currentIdent .stream() .map(article -> { try { - return buildArticle(article.getObjectId()); + return buildArticle(article.getObjectId(), filter.getLang(), true); } catch (Exception e) { LOG.error("Error while building published news article", e); return null; } }) + .filter(Objects::nonNull) .toList(); } @@ -1549,12 +1374,13 @@ private List getPostedArticles(NewsFilter filter, Identity currentIdentity .stream() .map(article -> { try { - return buildArticle(article.getObjectId()); + return buildArticle(article.getObjectId(), filter.getLang(), true); } catch (Exception e) { LOG.error("Error while building news article", e); return null; } }) + .filter(Objects::nonNull) .toList(); } @@ -1570,12 +1396,13 @@ private List getScheduledArticles(NewsFilter filter, Identity currentIdent .stream() .map(article -> { try { - return buildArticle(article.getObjectId()); + return buildArticle(article.getObjectId(), filter.getLang(), true); } catch (Exception e) { LOG.error("Error while building news article", e); return null; } }) + .filter(Objects::nonNull) .toList(); } @@ -1600,12 +1427,13 @@ private List getMyPostedArticles(NewsFilter filter, Identity currentIdenti .stream() .map(article -> { try { - return buildArticle(article.getObjectId()); + return buildArticle(article.getObjectId(), filter.getLang(), true); } catch (Exception e) { LOG.error("Error while building news article", e); return null; } }) + .filter(Objects::nonNull) .toList(); } @@ -1633,6 +1461,7 @@ private List buildDraftArticles(NewsFilter filter, Identity currentIdentit return null; } }) + .filter(Objects::nonNull) .toList(); } @@ -1651,54 +1480,6 @@ private boolean canEditNews(News news, String authenticatedUser) { || spaceService.canRedactOnSpace(space, authenticatedUserIdentity); } - private void setArticleIllustration(News article, Long articleIllustrationId, String newsObjectType) { - try { - FileItem articleIllustrationFileItem = fileService.getFile(articleIllustrationId); - if (articleIllustrationFileItem != null && !articleIllustrationFileItem.getFileInfo().isDeleted()) { - article.setIllustration(articleIllustrationFileItem.getAsByte()); - article.setIllustrationMimeType(articleIllustrationFileItem.getFileInfo().getMimetype()); - article.setIllustrationUpdateDate(articleIllustrationFileItem.getFileInfo().getUpdatedDate()); - long lastModified = article.getIllustrationUpdateDate().getTime(); - article.setIllustrationURL("/portal/rest/v1/news/" + article.getId() + "/illustration?v=" + lastModified + "&type=" - + newsObjectType); - } - } catch (Exception exception) { - LOG.info("Failed to set article illustration"); - } - } - - private Long saveArticleIllustration(String articleUploadId, Long oldArticleIllustrationFileId) { - if (StringUtils.isEmpty(articleUploadId)) { - throw new IllegalArgumentException("Article uploadId is mandatory"); - } - if (oldArticleIllustrationFileId != null && oldArticleIllustrationFileId != 0) { - fileService.deleteFile(oldArticleIllustrationFileId); - } - UploadResource articleUploadResource = uploadService.getUploadResource(articleUploadId); - if (articleUploadResource == null) { - throw new IllegalStateException("Can't find article uploaded resource with id : " + articleUploadId); - } - try { - InputStream articleIllustrationFileInputStream = new FileInputStream(articleUploadResource.getStoreLocation()); - FileItem articleIllustrationFileItem = new FileItem(null, - articleUploadResource.getFileName(), - articleUploadResource.getMimeType(), - NEWS_FILE_API_NAME_SPACE, - (long) articleUploadResource.getUploadedSize(), - new Date(), - IdentityConstants.SYSTEM, - false, - articleIllustrationFileInputStream); - articleIllustrationFileItem = fileService.writeFile(articleIllustrationFileItem); - return articleIllustrationFileItem != null - && articleIllustrationFileItem.getFileInfo() != null ? articleIllustrationFileItem.getFileInfo().getId() : null; - } catch (Exception e) { - throw new IllegalStateException("Error while saving article illustration file", e); - } finally { - uploadService.removeUploadResource(articleUploadResource.getUploadId()); - } - } - private boolean canDeleteNews(Identity currentIdentity, String posterId, String spaceId) { Space space = spaceId == null ? null : spaceService.getSpaceById(spaceId); if (space == null) { @@ -1751,7 +1532,10 @@ private String formatWikiOwnerToGroupId(String wikiOwner) { private void sendNotification(String currentUserId, News news, NotificationConstants.NOTIFICATION_CONTEXT context) throws Exception { - String newsId = news.getId(); + if (news.getActivities() == null || news.getActivities().isEmpty()) { + return; + } + String newsId = news.getTargetPageId() != null ? news.getTargetPageId() : news.getId(); String contentAuthor = news.getAuthor(); String currentUser = currentUserId != null ? currentUserId : contentAuthor; String activities = news.getActivities(); @@ -1919,7 +1703,7 @@ private void updateNewsActivities(String activityId, News news) throws Exception String updaterId = identityManager.getOrCreateUserIdentity(news.getAuthor()).getId(); Date updateDate = Calendar.getInstance().getTime(); metadataItem.setUpdatedDate(updateDate.getTime()); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(updaterId)); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(updaterId), false); news.setActivities(properties.get(NEWS_ACTIVITIES)); news.setActivityId(activityId); } @@ -1952,23 +1736,27 @@ private void postNewsActivity(News news) throws Exception { } private News updateNewsArticle(News news, Identity updater, String newsUpdateType) throws Exception { - Page existingPage = noteService.getNoteById(news.getId()); + String newsId = news.getTargetPageId() != null ? news.getTargetPageId() : news.getId(); + Page existingPage = noteService.getNoteById(newsId); if (existingPage != null) { - if (newsUpdateType.equals(CONTENT.name().toLowerCase())) { + if (newsUpdateType.equals(CONTENT_AND_TITLE.name())) { existingPage.setTitle(news.getTitle()); existingPage.setContent(news.getBody()); } - existingPage.setUpdatedDate(Calendar.getInstance().getTime()); - existingPage = noteService.updateNote(existingPage); + existingPage.setProperties(news.getProperties()); + existingPage = noteService.updateNote(existingPage, PageUpdateType.EDIT_PAGE_CONTENT_AND_TITLE, updater); news.setUpdateDate(existingPage.getUpdatedDate()); news.setUpdater(existingPage.getAuthor()); + news.setLang(existingPage.getLang()); news.setUpdaterFullName(existingPage.getAuthorFullName()); + news.setProperties(existingPage.getProperties()); + news.setIllustrationURL(NewsUtils.buildIllustrationUrl(existingPage.getProperties(), news.getLang())); String newsArticleUpdaterIdentityId = identityManager.getOrCreateUserIdentity(updater.getUserId()).getId(); // update the metadata item page NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, - news.getId(), + newsId, null, Long.parseLong(news.getSpaceId())); MetadataItem existingPageMetadataItem = @@ -1994,62 +1782,19 @@ private News updateNewsArticle(News news, Identity updater, String newsUpdateTyp existingPageMetadataItem.setProperties(newsPageProperties); Date updateDate = Calendar.getInstance().getTime(); existingPageMetadataItem.setUpdatedDate(updateDate.getTime()); - metadataService.updateMetadataItem(existingPageMetadataItem, Long.parseLong(newsArticleUpdaterIdentityId)); + metadataService.updateMetadataItem(existingPageMetadataItem, Long.parseLong(newsArticleUpdaterIdentityId), false); } else { - throw new ObjectNotFoundException("No such news article metadata item exists with id " + news.getId()); + throw new ObjectNotFoundException("No such news article metadata item exists with id " + newsId); } // create the version - if (newsUpdateType.equals(CONTENT.name().toLowerCase())) { + if (newsUpdateType.equalsIgnoreCase(CONTENT_AND_TITLE.name())) { noteService.createVersionOfNote(existingPage, updater.getUserId()); - PageVersion createdVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(existingPage.getId()), null); - // create the version metadata item - NewsPageVersionObject newsArticleVersionMetaDataObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, - createdVersion.getId(), - null, - Long.parseLong(news.getSpaceId())); - Map newsArticleVersionMetadataItemProperties = new HashMap<>(); - - String draftNewsId = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(existingPage.getId()), - updater.getUserId(), - null) - .getId(); - - NewsLatestDraftObject newsLatestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, - draftNewsId, - existingPage.getId(), - Long.parseLong(news.getSpaceId())); - MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsLatestDraftObject) - .stream() - .findFirst() - .orElse(null); - if (metadataItem != null && metadataItem.getProperties() != null && !metadataItem.getProperties().isEmpty()) { - Map properties = metadataItem.getProperties(); - if (properties.containsKey(NEWS_UPLOAD_ID)) { - newsArticleVersionMetadataItemProperties.put(NEWS_UPLOAD_ID, properties.get(NEWS_UPLOAD_ID)); - } - if (properties.containsKey(NEWS_ILLUSTRATION_ID)) { - newsArticleVersionMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, properties.get(NEWS_ILLUSTRATION_ID)); - setArticleIllustration(news, Long.parseLong(properties.get(NEWS_ILLUSTRATION_ID)), ARTICLE.name().toLowerCase()); - } - } else { - throw new ObjectNotFoundException("No such news draft article metadata item exists with id " + draftNewsId); - } - if (StringUtils.isNotEmpty(news.getSummary())) { - newsArticleVersionMetadataItemProperties.put(NEWS_SUMMARY, news.getSummary()); - } - metadataService.createMetadataItem(newsArticleVersionMetaDataObject, - NEWS_METADATA_KEY, - newsArticleVersionMetadataItemProperties, - Long.parseLong(newsArticleUpdaterIdentityId)); - - } - // remove the draft - if (newsUpdateType.equalsIgnoreCase(CONTENT.name())) { + // remove the draft DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(existingPage.getId()), updater.getUserId(), null); - deleteDraftArticle(draftPage.getId(), updater.getUserId(), news.getIllustration() == null); + deleteDraftArticle(draftPage.getId(), updater.getUserId()); } return news; } @@ -2057,24 +1802,26 @@ private News updateNewsArticle(News news, Identity updater, String newsUpdateTyp } private News buildArticle(String newsId) throws Exception { + return buildArticle(newsId, null, false); + } + + private News buildArticle(String newsId, String lang, boolean fetchOriginal) throws Exception { if (StringUtils.isNumeric(newsId)) { Page articlePage = noteService.getNoteById(newsId); Identity userIdentity = getCurrentIdentity(); String currentUsername = userIdentity == null ? null : userIdentity.getUserId(); if (articlePage != null) { Space space = spaceService.getSpaceByGroupId(articlePage.getWikiOwner()); + // fetch the last version of the given lang + PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(articlePage.getId()), lang); + if (pageVersion == null && fetchOriginal) { + pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(articlePage.getId()), null); + } News news = new News(); news.setId(articlePage.getId()); news.setCreationDate(articlePage.getCreatedDate()); - news.setAuthor(articlePage.getAuthor()); - news.setUpdater(articlePage.getAuthor()); - - // fetch related metadata item properties - NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, - articlePage.getId(), - null, - Long.parseLong(space.getId())); - MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject).get(0); + news.setAuthor(pageVersion.getAuthor()); + news.setUpdater(pageVersion.getAuthor()); news.setSpaceId(space.getId()); news.setSpaceAvatarUrl(space.getAvatarUrl()); news.setSpaceDisplayName(space.getDisplayName()); @@ -2095,16 +1842,28 @@ private News buildArticle(String newsId) throws Exception { news.setAuthorAvatarUrl(identity.getProfile().getAvatarUrl()); } - buildArticleProperties(news, articlePage, currentUsername, metadataItem); + // fetch related metadata item properties + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, + articlePage.getId(), + null, + Long.parseLong(space.getId())); + MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject).get(0); + buildArticleProperties(news, currentUsername, metadataItem); news.setDeleted(articlePage.isDeleted()); - news.setUrl(NewsUtils.buildNewsArticleUrl(news, currentUsername)); news.setPublicationDate(articlePage.getCreatedDate()); - news.setUpdateDate(new Date(metadataItem.getUpdatedDate())); - // fetch the last version of the given lang - PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(articlePage.getId()), null); news.setTitle(pageVersion.getTitle()); processPageContent(pageVersion, news); news.setUpdaterFullName(pageVersion.getAuthorFullName()); + news.setLang(pageVersion.getLang()); + news.setUpdateDate(new Date(metadataItem.getUpdatedDate())); + news.setProperties(pageVersion.getProperties()); + news.setUrl(NewsUtils.buildNewsArticleUrl(news, currentUsername)); + if (news.getProperties() != null && news.getProperties().getFeaturedImage() != null + && news.getProperties().getFeaturedImage().getId() != 0) { + news.setIllustrationURL(NewsUtils.buildIllustrationUrl(news.getProperties(), pageVersion.getLang())); + + } + NewsPageVersionObject newsPageVersionObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, pageVersion.getId(), @@ -2121,12 +1880,12 @@ private News buildArticle(String newsId) throws Exception { } private News createOrUpdateDraftForExistingPage(News news, String updater) throws Exception { - String pageId = news.getId(); + String pageId = news.getTargetPageId() != null ? news.getTargetPageId() : news.getId(); Page existingPage = noteService.getNoteById(pageId); if (existingPage == null) { return null; } - DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(pageId), updater, null); + DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(pageId), updater, news.getLang()); if (draftPage == null) { news = createDraftForExistingPage(news, updater, existingPage, System.currentTimeMillis()); } else { @@ -2141,72 +1900,38 @@ private News updateDraftForExistingPage(News news, String updater, Page page, Dr draftPage.setContent(news.getBody()); draftPage.setAuthor(news.getAuthor()); draftPage.setTargetPageId(page.getId()); - draftPage.setLang(null); + draftPage.setLang(news.getLang()); + draftPage.setProperties(news.getProperties()); draftPage = noteService.updateDraftForExistPage(draftPage, page, null, System.currentTimeMillis(), updater); news.setDraftUpdateDate(draftPage.getUpdatedDate()); news.setDraftUpdater(draftPage.getAuthor()); + news.setTargetPageId(draftPage.getTargetPageId()); + news.setProperties(draftPage.getProperties()); + news.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftPage.getProperties(), news.getLang())); NewsLatestDraftObject latestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, draftPage.getId(), page.getId(), Long.parseLong(news.getSpaceId())); - List latestDraftArticleMetadataItems = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - latestDraftObject); - if (latestDraftArticleMetadataItems != null && !latestDraftArticleMetadataItems.isEmpty()) { - MetadataItem latestDraftArticleMetadataItem = latestDraftArticleMetadataItems.get(0); + MetadataItem latestDraftArticleMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, latestDraftObject).stream().findFirst().orElse(null); + if (latestDraftArticleMetadataItem != null) { Map latestDraftArticleMetadataItemProperties = latestDraftArticleMetadataItem.getProperties(); if (latestDraftArticleMetadataItemProperties == null) { latestDraftArticleMetadataItemProperties = new HashMap<>(); } - // create or update the illustration - if (StringUtils.isNotEmpty(news.getUploadId())) { - // update the illustration if exist - if (latestDraftArticleMetadataItemProperties.containsKey(NEWS_UPLOAD_ID) - && latestDraftArticleMetadataItemProperties.get(NEWS_UPLOAD_ID) != null - && latestDraftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && latestDraftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - if (!latestDraftArticleMetadataItemProperties.get(NEWS_UPLOAD_ID).equals(news.getUploadId())) { - FileItem draftArticleIllustrationFileItem = - fileService.getFile(Long.parseLong(latestDraftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID))); - Long draftArticleIllustrationId = saveArticleIllustration(news.getUploadId(), - draftArticleIllustrationFileItem.getFileInfo().getId()); - latestDraftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - setArticleIllustration(news, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); - } - } else { - // create the illustration if not exist - Long draftArticleIllustrationId = saveArticleIllustration(news.getUploadId(), null); - latestDraftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - latestDraftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, news.getUploadId()); - setArticleIllustration(news, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); - } - latestDraftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, news.getUploadId()); - } else { - // if the upload id is empty we should remove the existing - // illustration - if (latestDraftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && latestDraftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null && news.getUploadId() != null) { - latestDraftArticleMetadataItemProperties.remove(NEWS_UPLOAD_ID); - FileItem draftArticleIllustrationFileItem = - fileService.getFile(Long.parseLong(latestDraftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID))); - latestDraftArticleMetadataItemProperties.remove(NEWS_ILLUSTRATION_ID); - - fileService.deleteFile(draftArticleIllustrationFileItem.getFileInfo().getId()); - } - } - if (StringUtils.isNotEmpty(news.getSummary())) { - latestDraftArticleMetadataItemProperties.put(NEWS_SUMMARY, news.getSummary()); - } - latestDraftArticleMetadataItemProperties.put(NEWS_ACTIVITY_POSTED, String.valueOf(news.isActivityPosted())); + setLatestDraftProperties(latestDraftArticleMetadataItemProperties, news); latestDraftArticleMetadataItem.setProperties(latestDraftArticleMetadataItemProperties); String draftArticleMetadataItemUpdaterIdentityId = identityManager.getOrCreateUserIdentity(updater).getId(); metadataService.updateMetadataItem(latestDraftArticleMetadataItem, - Long.parseLong(draftArticleMetadataItemUpdaterIdentityId)); + Long.parseLong(draftArticleMetadataItemUpdaterIdentityId), false); } else { - throw new ObjectNotFoundException("No metadata item found for the draft " + news.getId()); + Map latestDraftArticleMetadataItemProperties = new HashMap<>(); + setLatestDraftProperties(latestDraftArticleMetadataItemProperties, news); + metadataService.createMetadataItem(latestDraftObject, NEWS_METADATA_KEY, latestDraftArticleMetadataItemProperties, false); + } } catch (Exception exception) { return null; @@ -2214,7 +1939,11 @@ private News updateDraftForExistingPage(News news, String updater, Page page, Dr return news; } - private News buildLatestDraftArticle(String parentPageId, String currentIdentityId) throws Exception { + private void setLatestDraftProperties(Map properties, News news) { + properties.put(NEWS_ACTIVITY_POSTED, String.valueOf(news.isActivityPosted())); + } + + private News buildLatestDraftArticle(String parentPageId, String currentIdentityId, String lang) throws Exception { Page parentPage = noteService.getNoteById(parentPageId); if (parentPage == null) { return null; @@ -2222,14 +1951,15 @@ private News buildLatestDraftArticle(String parentPageId, String currentIdentity // if the latest draft exist return it , else return the article DraftPage latestDraft = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(parentPageId), currentIdentityId, - null); + lang); if (latestDraft == null) { - return buildArticle(parentPageId); + return buildArticle(parentPageId, lang, true); } News draftArticle = buildDraftArticle(latestDraft.getId(), currentIdentityId); - // set always the article id to use it to fetch the article if the draft not - // exist - draftArticle.setId(parentPageId); + + draftArticle.setId(latestDraft.getId()); + draftArticle.setTargetPageId(latestDraft.getTargetPageId()); + draftArticle.setLang(latestDraft.getLang()); return draftArticle; } @@ -2263,37 +1993,6 @@ private void setSchedulePostDate(News news, Map newsProperties) newsProperties.put(SCHEDULE_POST_DATE, startPublishedDateString); } - private boolean isSameIllustration(String newsDraftId, String newsArticleId) throws ObjectNotFoundException, - FileStorageException { - - News news = getNewsArticleById(newsArticleId); - if (news == null || news.getIllustration() == null) { - return false; - } - NewsLatestDraftObject draftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, - newsDraftId, - newsArticleId, - Long.parseLong(news.getSpaceId())); - MetadataItem draftMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, draftObject) - .stream() - .findFirst() - .orElse(null); - if (draftMetadataItem == null) { - throw new ObjectNotFoundException("Metadata items not found for news draft " + newsDraftId); - } - - // Retrieve illustration ID from metadata - Map draftProperties = draftMetadataItem.getProperties(); - if (draftProperties != null) { - String draftIllustrationId = draftProperties.getOrDefault(NEWS_ILLUSTRATION_ID, null); - FileItem fileItem = fileService.getFile(Long.parseLong(draftIllustrationId)); - if (fileItem != null) { - return Arrays.equals(fileItem.getAsByte(), news.getIllustration()); - } - } - return false; - } - private News postScheduledArticle(News news) throws ObjectNotFoundException { NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, news.getId(), @@ -2313,7 +2012,7 @@ private News postScheduledArticle(News news) throws ObjectNotFoundException { String poster = identityManager.getOrCreateUserIdentity(news.getAuthor()).getId(); Date updateDate = Calendar.getInstance().getTime(); metadataItem.setUpdatedDate(updateDate.getTime()); - metadataService.updateMetadataItem(metadataItem, Long.parseLong(poster)); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(poster), false); news.setSchedulePostDate(null); return news; } @@ -2323,26 +2022,59 @@ private News postScheduledArticle(News news) throws ObjectNotFoundException { return null; } - private Map getArticleIllustrationInfo(News news) { - Map illustrationInfo = new HashMap<>(); - if (news.getIllustration() != null) { - PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(news.getId()), null); - if (pageVersion != null) { - MetadataItem metadataItem = - metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, - pageVersion.getId(), - null, - Long.parseLong(news.getSpaceId()))) - .stream() - .findFirst() - .orElse(null); - if (metadataItem != null && metadataItem.getProperties() != null && !metadataItem.getProperties().isEmpty()) { - illustrationInfo.put(NEWS_ILLUSTRATION_ID, metadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); - illustrationInfo.put(NEWS_UPLOAD_ID, metadataItem.getProperties().get(NEWS_UPLOAD_ID)); - } + private News addNewArticleVersionWithLang(News news, Identity versionCreator) throws Exception { + News existingNews = getNewsArticleById(news.getId()); + String newsId = news.getTargetPageId() != null ? news.getTargetPageId() : news.getId(); + Page existingPage = noteService.getNoteById(newsId); + if (existingPage != null) { + existingPage.setLang(news.getLang()); + existingPage = noteService.updateNote(existingPage, PageUpdateType.EDIT_PAGE_CONTENT_AND_TITLE, versionCreator); + news.setPublicationState(POSTED); + // update the metadata item + MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, newsId, null, Long.parseLong(existingNews.getSpaceId()))).stream().findFirst().orElse(null); + if (metadataItem != null) { + Calendar calendar = Calendar.getInstance(); + metadataItem.setUpdatedDate(calendar.getTime().getTime()); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(identityManager.getOrCreateUserIdentity(versionCreator.getUserId()).getId()), false); } + existingPage.setTitle(news.getTitle()); + existingPage.setContent(news.getBody()); + NotePageProperties properties = news.getProperties(); + if (properties != null) { + properties.setDraft(false); + } + existingPage.setProperties(properties); + noteService.createVersionOfNote(existingPage, versionCreator.getUserId()); + news.setIllustrationURL(NewsUtils.buildIllustrationUrl(news.getProperties(), news.getLang())); + DraftPage draftPage = noteService.getLatestDraftPageByTargetPageAndLang(Long.parseLong(newsId), news.getLang()); + if (draftPage != null) { + deleteDraftArticle(draftPage.getId(), draftPage.getAuthor()); + } + NewsUtils.broadcastEvent(NewsUtils.ADD_ARTICLE_TRANSLATION, versionCreator, news); + String newsTranslationId = news.getId().concat("-").concat(news.getLang()); + indexingService.index(NewsIndexingServiceConnector.TYPE, newsTranslationId); + return news; } - return illustrationInfo; + return null; + } + + private List getArticleAttachmentIdsToShare(long spaceId, long articlePageId) { + List attachmentIds = new ArrayList<>(); + PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(articlePageId, null); + NewsPageVersionObject newsPageVersionObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, + pageVersion.getId(), + null, + spaceId); + List newsPageVersionMetadataItems = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, + newsPageVersionObject); + Map newsPageVersionMetadataItemProperties = newsPageVersionMetadataItems.get(0).getProperties(); + if (!MapUtils.isEmpty(newsPageVersionMetadataItems.get(0).getProperties())) { + + if (newsPageVersionMetadataItemProperties.containsKey(NEWS_ATTACHMENTS_IDS) + && newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS) != null) { + attachmentIds.addAll(List.of(newsPageVersionMetadataItemProperties.get(NEWS_ATTACHMENTS_IDS).split(";"))); + } + } + return attachmentIds; } } diff --git a/content-service/src/main/java/io/meeds/news/service/impl/NewsTargetingServiceImpl.java b/content-service/src/main/java/io/meeds/news/service/impl/NewsTargetingServiceImpl.java index b8a2768b3..afbdc33a7 100644 --- a/content-service/src/main/java/io/meeds/news/service/impl/NewsTargetingServiceImpl.java +++ b/content-service/src/main/java/io/meeds/news/service/impl/NewsTargetingServiceImpl.java @@ -48,10 +48,15 @@ import io.meeds.news.rest.NewsTargetingPermissionsEntity; import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; /** * Service managing News Targeting */ +@Primary +@Service public class NewsTargetingServiceImpl implements NewsTargetingService { private static final Log LOG = ExoLogger.getLogger(NewsTargetingServiceImpl.class); @@ -60,24 +65,18 @@ public class NewsTargetingServiceImpl implements NewsTargetingService { private static final String PUBLISHER_MEMBERSHIP_NAME = "publisher"; + @Autowired private MetadataService metadataService; + @Autowired private IdentityManager identityManager; + @Autowired private SpaceService spaceService; + @Autowired private OrganizationService organizationService; - public NewsTargetingServiceImpl(MetadataService metadataService, - IdentityManager identityManager, - SpaceService spaceService, - OrganizationService organizationService) { - this.metadataService = metadataService; - this.identityManager = identityManager; - this.spaceService = spaceService; - this.organizationService = organizationService; - } - @Override public List getAllTargets() { List targets = metadataService.getMetadatas(METADATA_TYPE.getName(), 0); @@ -152,7 +151,7 @@ public void saveNewsTarget(News news, targets.stream().forEach(targetName -> { try { MetadataKey metadataKey = new MetadataKey(NewsTargetingService.METADATA_TYPE.getName(), targetName, 0); - metadataService.createMetadataItem(newsTargetObject, metadataKey, properties, Long.parseLong(currentSocIdentity.getId())); + metadataService.createMetadataItem(newsTargetObject, metadataKey, properties, Long.parseLong(currentSocIdentity.getId()), false); } catch (ObjectAlreadyExistsException e) { LOG.warn("Targets with name {} is already associated to object {}. Ignore error since it will not affect result.", targetName, diff --git a/content-service/src/main/java/io/meeds/news/utils/EntityBuilder.java b/content-service/src/main/java/io/meeds/news/utils/EntityBuilder.java index 2f4f495f2..7d92232d3 100644 --- a/content-service/src/main/java/io/meeds/news/utils/EntityBuilder.java +++ b/content-service/src/main/java/io/meeds/news/utils/EntityBuilder.java @@ -19,9 +19,6 @@ */ package io.meeds.news.utils; -import javax.ws.rs.core.UriInfo; - -import io.meeds.news.model.News; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.metadata.favorite.FavoriteService; import org.exoplatform.social.metadata.favorite.model.Favorite; @@ -36,14 +33,10 @@ private EntityBuilder() { public static NewsSearchResultEntity fromNewsSearchResult(FavoriteService favoriteService, NewsESSearchResult newsESSearchResult, - Identity currentIdentity, - UriInfo uriInfo) { + Identity currentIdentity) { NewsSearchResultEntity newsSearchResultEntity = new NewsSearchResultEntity(newsESSearchResult); - newsSearchResultEntity.setPoster(org.exoplatform.social.rest.api.EntityBuilder.buildEntityIdentity(newsESSearchResult.getPoster(), - uriInfo.getPath(), - "all")); Favorite favorite = new Favorite(NewsUtils.NEWS_METADATA_OBJECT_TYPE, - newsESSearchResult.getId(), + newsESSearchResult.getLang() != null ? newsESSearchResult.getId().concat("-").concat(newsESSearchResult.getLang()) : newsESSearchResult.getId(), null, Long.parseLong(currentIdentity.getId())); newsSearchResultEntity.setFavorite(favoriteService.isFavorite(favorite)); diff --git a/content-service/src/main/java/io/meeds/news/utils/NewsUtils.java b/content-service/src/main/java/io/meeds/news/utils/NewsUtils.java index 12d284ccb..cc3f1fa3a 100644 --- a/content-service/src/main/java/io/meeds/news/utils/NewsUtils.java +++ b/content-service/src/main/java/io/meeds/news/utils/NewsUtils.java @@ -27,6 +27,8 @@ import java.util.stream.Collectors; import io.meeds.news.model.News; +import io.meeds.notes.model.NoteFeaturedImage; +import io.meeds.notes.model.NotePageProperties; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -92,13 +94,17 @@ public class NewsUtils { public static final String PLATFORM_WEB_CONTRIBUTORS_GROUP = "/platform/web-contributors"; public static final String SHARE_CONTENT_ATTACHMENTS = "content.share.attachments"; + + public static final String ADD_ARTICLE_TRANSLATION = "content.add.article.translation"; + + public static final String REMOVE_ARTICLE_TRANSLATION = "content.remove.article.translation"; public enum NewsObjectType { DRAFT, LATEST_DRAFT, ARTICLE; } public enum NewsUpdateType { - CONTENT, SCHEDULE, POSTING_AND_PUBLISHING + CONTENT_AND_TITLE, SCHEDULE, POSTING_AND_PUBLISHING } public static void broadcastEvent(String eventName, Object source, Object data) { @@ -253,6 +259,10 @@ public static String buildNewsArticleUrl(News news, String currentUsername) thro .append(news.getId()) .append("&type=article"); } + if (news.getLang() != null) { + newsArticleUrl.append("&lang="); + newsArticleUrl.append(news.getLang()); + } return newsArticleUrl.toString(); } public static String buildSpaceUrl(String spaceId) { @@ -270,9 +280,31 @@ public static String buildSpaceUrl(String spaceId) { return null; } + public static String buildIllustrationUrl(NotePageProperties properties, String lang) { + if (properties == null || properties.getFeaturedImage() == null || properties.getFeaturedImage().getId() == null + || properties.getFeaturedImage().getId() == 0L) { + return null; + } + NoteFeaturedImage featuredImage = properties.getFeaturedImage(); + StringBuilder illustrationUrl = new StringBuilder(); + illustrationUrl.append("/portal/rest/notes/illustration/"); + illustrationUrl.append(properties.getNoteId()); + illustrationUrl.append("?v="); + illustrationUrl.append(featuredImage.getLastUpdated()); + illustrationUrl.append("&isDraft="); + illustrationUrl.append(properties.isDraft()); + if (lang != null) { + illustrationUrl.append("&lang="); + illustrationUrl.append(lang); + } + return illustrationUrl.toString(); + } + private static List getMySpaces(org.exoplatform.services.security.Identity userIdentity) throws Exception { SpaceService spaceService = CommonsUtils.getService(SpaceService.class); ListAccess memberSpacesListAccess = spaceService.getMemberSpaces(userIdentity.getUserId()); return Arrays.asList(memberSpacesListAccess.load(0, memberSpacesListAccess.getSize())); } + + } diff --git a/content-service/src/main/resources/locale/portlet/news/News_en.properties b/content-service/src/main/resources/locale/portlet/news/News_en.properties index cf3217c5f..b587ebbe8 100644 --- a/content-service/src/main/resources/locale/portlet/news/News_en.properties +++ b/content-service/src/main/resources/locale/portlet/news/News_en.properties @@ -1,3 +1,12 @@ +news.editor.publish=Publish +news.editor.save=Save +news.editor.label.create=Create +news.editor.label.edit=Edit +news.save.success.message=Article saved successfully +news.publish.success.message=Article published successfully +news.save.error.message=Error occurred when trying to post an article {0} +news.update.success.message=Article updated successfully +news.view.label=View UIActivityComposer.label.UINewsActivityComposer=News news.title=Article Notification.label.types.news=Article @@ -211,6 +220,7 @@ news.list.settings.drawer.advancedSettings.showArticleReactionsCounter=Show reac news.list.settings.newsTargets.description=Display articles published toward this target news.list.settings.viewTemplate.description=Customize the display of this news block news.list.settings.information=This news block displays published articles. As a publisher, you can tailor how it looks using the settings below. +news.list.settings.translation.header=Translate header name newsTargets.settings.title=News Publication Targets newsTargets.settings.button.addTarget=Add a target @@ -255,3 +265,12 @@ news.alertView.rightArrowButtonTitle=Next visual # For news page template UIWizardPageSelectLayoutForm.label.newsPage.newsLayout=News + +# content editor translation options +content.label.button.translations.options=Translation options +content.message.firstVersionShouldBeCreated=Create a first version to have translation available +content.alert.success.label.translation.deleted=Translation successfully deleted + +article.automatic.translation.label=Automatic translation +article.label.translation.originalVersion=Original version +article.label.chooseLanguage=Choose a language diff --git a/content-service/src/test/java/io/meeds/news/listener/MetadataItemModifiedTest.java b/content-service/src/test/java/io/meeds/news/listener/MetadataItemModifiedTest.java index 95e107e32..279e8b446 100644 --- a/content-service/src/test/java/io/meeds/news/listener/MetadataItemModifiedTest.java +++ b/content-service/src/test/java/io/meeds/news/listener/MetadataItemModifiedTest.java @@ -27,8 +27,11 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import org.exoplatform.services.listener.ListenerService; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -55,9 +58,19 @@ public class MetadataItemModifiedTest { @Mock private CachedActivityStorage activityStorage; + @Mock + private ListenerService listenerService; + + @InjectMocks + MetadataItemModified metadataItemModified; + + @Before + public void setUp() { + metadataItemModified.init(); + } + @Test public void testNoInteractionWhenMetadataNotForNews() throws Exception { - MetadataItemModified metadataItemModified = new MetadataItemModified(newsService, indexingService, activityStorage); MetadataItem metadataItem = mock(MetadataItem.class); Event event = mock(Event.class); when(event.getData()).thenReturn(metadataItem); @@ -71,7 +84,6 @@ public void testNoInteractionWhenMetadataNotForNews() throws Exception { @Test public void testReindexNewsWhenNewsSetAsFavorite() throws Exception { - MetadataItemModified metadataItemModified = new MetadataItemModified(newsService, indexingService, activityStorage); String newsId = "100"; MetadataItem metadataItem = mock(MetadataItem.class); @@ -83,16 +95,15 @@ public void testReindexNewsWhenNewsSetAsFavorite() throws Exception { News news = new News(); news.setId(newsId); - when(newsService.getNewsById(eq(newsId), anyBoolean())).thenReturn(news); + when(newsService.getNewsArticleById(eq(newsId))).thenReturn(news); metadataItemModified.onEvent(event); - verify(newsService, times(1)).getNewsById(newsId, false); + verify(newsService, times(1)).getNewsArticleById(newsId); verify(indexingService, times(1)).reindex(NewsIndexingServiceConnector.TYPE, newsId); } @Test public void testCleanNewsActivityCacheWhenMarkAsFavorite() throws Exception { - MetadataItemModified metadataItemModified = new MetadataItemModified(newsService, indexingService, activityStorage); String newsId = "200"; MetadataItem metadataItem = mock(MetadataItem.class); @@ -106,10 +117,10 @@ public void testCleanNewsActivityCacheWhenMarkAsFavorite() throws Exception { News news = new News(); news.setId(newsId); news.setActivityId(activityId); - when(newsService.getNewsById(eq(newsId), anyBoolean())).thenReturn(news); + when(newsService.getNewsArticleById(eq(newsId))).thenReturn(news); metadataItemModified.onEvent(event); - verify(newsService, times(1)).getNewsById(newsId, false); + verify(newsService, times(1)).getNewsArticleById(newsId); verify(indexingService, times(1)).reindex(NewsIndexingServiceConnector.TYPE, newsId); verify(activityStorage, times(1)).clearActivityCached(activityId); } diff --git a/content-service/src/test/java/io/meeds/news/listener/NewsActivityListenerTest.java b/content-service/src/test/java/io/meeds/news/listener/NewsActivityListenerTest.java index 09dd30fb7..aed2a7853 100644 --- a/content-service/src/test/java/io/meeds/news/listener/NewsActivityListenerTest.java +++ b/content-service/src/test/java/io/meeds/news/listener/NewsActivityListenerTest.java @@ -31,8 +31,10 @@ import java.util.Map; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -65,13 +67,11 @@ public class NewsActivityListenerTest { @Mock private NewsService newsService; + @InjectMocks + NewsActivityListener newsActivityListener; + @Test public void testNotShareWhenActivityNotFound() { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); newsActivityListener.shareActivity(event); @@ -80,11 +80,6 @@ public void testNotShareWhenActivityNotFound() { @Test public void testNotShareWhenActivityNotHavingTemplates() { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); @@ -95,11 +90,6 @@ public void testNotShareWhenActivityNotHavingTemplates() { @Test public void testNotShareWhenActivityNotSharedOne() { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); @@ -113,11 +103,6 @@ public void testNotShareWhenActivityNotSharedOne() { @Test public void testNotShareWhenSharedActivityNotFound() { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); @@ -135,11 +120,6 @@ public void testNotShareWhenSharedActivityNotFound() { @Test public void testNotShareWhenSharedActivityNotNewsActivity() { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); @@ -160,11 +140,6 @@ public void testNotShareWhenSharedActivityNotNewsActivity() { @Test public void testNotShareWhenSharedActivityWhenNewsNotFound() throws Exception { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); @@ -198,11 +173,6 @@ public void testNotShareWhenSharedActivityWhenNewsNotFound() throws Exception { @Test public void testShareWhenNewsFound() throws Exception { - NewsActivityListener newsActivityListener = new NewsActivityListener(activityManager, - identityManager, - spaceService, - newsService); - ActivityLifeCycleEvent event = mock(ActivityLifeCycleEvent.class); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(event.getActivity()).thenReturn(activity); diff --git a/content-service/src/test/java/io/meeds/news/listener/NewsMetadataListenerTest.java b/content-service/src/test/java/io/meeds/news/listener/NewsMetadataListenerTest.java index e88508c52..fd5ff9540 100644 --- a/content-service/src/test/java/io/meeds/news/listener/NewsMetadataListenerTest.java +++ b/content-service/src/test/java/io/meeds/news/listener/NewsMetadataListenerTest.java @@ -27,8 +27,11 @@ import java.util.Arrays; import java.util.HashSet; +import org.exoplatform.services.listener.ListenerService; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -64,12 +67,11 @@ public class NewsMetadataListenerTest { @Mock private TagService tagService; + @InjectMocks + NewsMetadataListener newsMetadataListener; + @Test public void testCreateNewsTagsWhenNewsSaved() throws Exception { - NewsMetadataListener newsMetadataListener = new NewsMetadataListener(indexingService, - spaceService, - identityManager, - tagService); String newsId = "newsId"; String spaceId = "spaceId"; String content = "Test #tag1 Test #tag2."; diff --git a/content-service/src/test/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPluginTest.java b/content-service/src/test/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPluginTest.java index d5e237baa..8e45e005b 100644 --- a/content-service/src/test/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPluginTest.java +++ b/content-service/src/test/java/io/meeds/news/notification/plugin/NewsSpaceWebNotificationPluginTest.java @@ -91,7 +91,7 @@ public void testGetSpaceApplicationItem() throws Exception { String metadataObjectType = ExoSocialActivityImpl.DEFAULT_ACTIVITY_METADATA_OBJECT_TYPE; String metadataObjectId = activityId; when(notificationInfo.getValueOwnerParameter(NotificationConstants.NEWS_ID)).thenReturn(newsId); - when(newsService.getNewsById(newsId, false)).thenReturn(news); + when(newsService.getNewsArticleById(newsId)).thenReturn(news); when(news.getActivityId()).thenReturn(activityId); when(identityManager.getOrCreateUserIdentity(USERNAME)).thenReturn(userIdentity); when(userIdentity.getId()).thenReturn(String.valueOf(userIdentityId)); diff --git a/content-service/src/test/java/io/meeds/news/notification/plugin/PostNewsNotificationPluginTest.java b/content-service/src/test/java/io/meeds/news/notification/plugin/PostNewsNotificationPluginTest.java index 9e72757bb..b6e2e474c 100644 --- a/content-service/src/test/java/io/meeds/news/notification/plugin/PostNewsNotificationPluginTest.java +++ b/content-service/src/test/java/io/meeds/news/notification/plugin/PostNewsNotificationPluginTest.java @@ -155,7 +155,7 @@ public void shouldMakeNotificationForPostNewsContext() throws Exception { News news = mock(News.class); when(news.getActivityId()).thenReturn("12345"); - when(newsService.getNewsById(Mockito.anyString(), Mockito.anyBoolean())).thenReturn(news); + when(newsService.getNewsArticleById(Mockito.anyString())).thenReturn(news); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(activity.isHidden()).thenReturn(false); @@ -230,7 +230,7 @@ public void shouldMakeNotificationForPostNewsContextAndDoNotSendNotificationToCr News news = mock(News.class); when(news.getActivityId()).thenReturn("12345"); - when(newsService.getNewsById(Mockito.anyString(), Mockito.anyBoolean())).thenReturn(news); + when(newsService.getNewsArticleById(Mockito.anyString())).thenReturn(news); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(activity.isHidden()).thenReturn(false); @@ -306,7 +306,7 @@ public void shouldMakeNotificationForPostNewsContextAndAuthorUserIsNull() throws News news = mock(News.class); when(news.getActivityId()).thenReturn("12345"); - when(newsService.getNewsById(Mockito.anyString(), Mockito.anyBoolean())).thenReturn(news); + when(newsService.getNewsArticleById(Mockito.anyString())).thenReturn(news); ExoSocialActivity activity = mock(ExoSocialActivity.class); when(activity.isHidden()).thenReturn(false); diff --git a/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java b/content-service/src/test/java/io/meeds/news/rest/NewsRestTest.java similarity index 68% rename from content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java rename to content-service/src/test/java/io/meeds/news/rest/NewsRestTest.java index eac5b3029..f6b7a2863 100644 --- a/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java +++ b/content-service/src/test/java/io/meeds/news/rest/NewsRestTest.java @@ -21,7 +21,7 @@ import static io.meeds.news.service.impl.NewsServiceImpl.POSTED; import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; -import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT; +import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT_AND_TITLE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -43,20 +43,20 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.RuntimeDelegate; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; @@ -80,9 +80,10 @@ import io.meeds.news.model.News; import io.meeds.news.service.NewsService; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.ResponseEntity; @RunWith(MockitoJUnitRunner.class) -public class NewsRestResourcesV1Test { +public class NewsRestTest { public static final String JOHN = "john"; @@ -108,12 +109,15 @@ public class NewsRestResourcesV1Test { @Mock TagService tagService; - private NewsRestResourcesV1 newsRestResourcesV1; + @InjectMocks + private NewsRest newsRestController; + + private HttpServletRequest request; @Before public void setup() { + newsRestController.init(); RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); - this.newsRestResourcesV1 = new NewsRestResourcesV1(newsService, spaceService, identityManager, container, favoriteService); org.exoplatform.social.core.identity.model.Identity userIdentity = new org.exoplatform.social.core.identity.model.Identity("1", JOHN, @@ -124,6 +128,8 @@ public void setup() { null, null); when(identityManager.getOrCreateUserIdentity(JOHN)).thenReturn(userIdentity); + request = mock(HttpServletRequest.class); + when(request.getLocale()).thenReturn(Locale.ENGLISH); } @AfterClass @@ -135,33 +141,27 @@ public static void afterRunBare() throws Exception { // NOSONAR @Test public void shouldGetNewsWhenNewsExistsAndUserIsMemberOfTheSpace() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); - news.setIllustration("illustration".getBytes()); - lenient().when(newsService.getNewsById(nullable(String.class), any(), nullable(Boolean.class), nullable(String.class))) + lenient().when(newsService.getNewsByIdAndLang(nullable(String.class), any(), nullable(Boolean.class), nullable(String.class), nullable(String.class))) .thenReturn(news); lenient().when(spaceService.getSpaceById(nullable(String.class))).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(false); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - News fetchedNews = (News) response.getEntity(); + assertEquals(200, response.getStatusCodeValue()); + News fetchedNews = (News) response.getBody(); assertNotNull(fetchedNews); - assertNull(fetchedNews.getIllustration()); } @Test public void shouldGetNewsByGivenTargetName() throws Exception { - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); List newsList = new LinkedList<>(); @@ -173,15 +173,15 @@ public void shouldGetNewsByGivenTargetName() throws Exception { newsList.add(news); NewsFilter newsFilter = new NewsFilter(); newsFilter.setLimit(10); - lenient().when(newsService.getNewsByTargetName(newsFilter, "sliderNews", currentIdentity)).thenReturn(newsList); + lenient().when(newsService.getNewsByTargetName(any(NewsFilter.class), anyString(), any(Identity.class))).thenReturn(newsList); // When - Response response = newsRestResourcesV1.getNewsByTarget(request, "sliderNews", 0, 10, false); + ResponseEntity response = newsRestController.getNewsByTarget( "sliderNews", 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - assertNotNull(response.getEntity()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(200, response.getStatusCode().value()); + assertNotNull(response.getBody()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsEntityNews = newsEntity.getNews(); assertEquals(1, newsEntityNews.size()); } @@ -192,23 +192,23 @@ public void shouldReturnBadRequestWhenNoActivityId() throws Exception { Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); // When - Response response = newsRestResourcesV1.getNewsByActivityId(null); + ResponseEntity response = newsRestController.getNewsByActivityId(null, null); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(400, response.getStatusCode().value()); } @Test - public void shouldReturnNotFoundwhenNewsNotFound() throws Exception { + public void shouldReturnNotFoundWhenNewsNotFound() throws Exception { // Given Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); String activityId = "activityId"; // When - Response response = newsRestResourcesV1.getNewsByActivityId(activityId); + ResponseEntity response = newsRestController.getNewsByActivityId(activityId, null); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(404, response.getStatusCode().value()); } @Test @@ -219,13 +219,13 @@ public void shouldReturnNotFoundWhenNotAccessible() throws Exception { Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - when(newsService.getNewsByActivityId(activityId, currentIdentity)).thenThrow(IllegalAccessException.class); + when(newsService.getNewsByActivityIdAndLang(activityId, currentIdentity, null)).thenThrow(IllegalAccessException.class); // When - Response response = newsRestResourcesV1.getNewsByActivityId(activityId); + ResponseEntity response = newsRestController.getNewsByActivityId(activityId, null); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test @@ -235,13 +235,13 @@ public void shouldReturnNotFoundWhenNewsWithActivityNotFoundException() throws E Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - when(newsService.getNewsByActivityId(activityId, currentIdentity)).thenThrow(ObjectNotFoundException.class); + when(newsService.getNewsByActivityIdAndLang(activityId, currentIdentity, null)).thenThrow(ObjectNotFoundException.class); // When - Response response = newsRestResourcesV1.getNewsByActivityId(activityId); + ResponseEntity response = newsRestController.getNewsByActivityId(activityId, null); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode().value()); } @Test @@ -251,13 +251,13 @@ public void shouldReturnServerErrorWhenNewsWithActivitythrowsException() throws Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - when(newsService.getNewsByActivityId(activityId, currentIdentity)).thenThrow(RuntimeException.class); + when(newsService.getNewsByActivityIdAndLang(activityId, currentIdentity, null)).thenThrow(RuntimeException.class); // When - Response response = newsRestResourcesV1.getNewsByActivityId(activityId); + ResponseEntity response = newsRestController.getNewsByActivityId(activityId, null); // Then - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode().value()); } @Test @@ -269,41 +269,37 @@ public void shouldReturnNewsWhenNewsIsFound() throws Exception { ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = mock(News.class); - when(newsService.getNewsByActivityId(activityId, currentIdentity)).thenReturn(news); + when(newsService.getNewsByActivityIdAndLang(activityId, currentIdentity, null)).thenReturn(news); // When - Response response = newsRestResourcesV1.getNewsByActivityId(activityId); + ResponseEntity response = newsRestController.getNewsByActivityId(activityId, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - assertEquals(news, response.getEntity()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + assertEquals(news, response.getBody()); } @Test public void shouldGetNewsWhenNewsExistsAndUserIsNotMemberOfTheSpaceButSuperManager() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(news); + lenient().when(newsService.getNewsByIdAndLang(anyString(), any(), anyBoolean(), nullable(String.class), nullable(String.class))).thenReturn(news); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(false); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNotFoundWhenNewsNotExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(null); @@ -312,22 +308,19 @@ public void shouldGetNotFoundWhenNewsNotExists() throws Exception { lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNewsSpacesWhenNewsExistsAndUserIsMemberOfTheSpace() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); - news.setIllustration("illustration".getBytes()); news.setActivities("1:1;2:2"); news.setSpaceId("1"); Space space1 = new Space(); @@ -336,7 +329,7 @@ public void shouldGetNewsSpacesWhenNewsExistsAndUserIsMemberOfTheSpace() throws Space space2 = new Space(); space1.setId("2"); space1.setPrettyName("space2"); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(news); + lenient().when(newsService.getNewsByIdAndLang(anyString(), any(), anyBoolean(), nullable(String.class), nullable(String.class))).thenReturn(news); lenient().when(spaceService.getSpaceById("1")).thenReturn(space1); lenient().when(spaceService.getSpaceById("2")).thenReturn(space2); lenient().when(spaceService.isMember(space1, JOHN)).thenReturn(true); @@ -344,10 +337,10 @@ public void shouldGetNewsSpacesWhenNewsExistsAndUserIsMemberOfTheSpace() throws lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(false); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", "spaces", null, false); + ResponseEntity response = newsRestController.getNewsById("1", "spaces", null, false, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test @@ -357,37 +350,34 @@ public void shouldGetOKWhenUpdatingNewsAndNewsExistsAndUserIsAuthorized() throws ConversationState.setCurrent(new ConversationState(currentIdentity)); News existingNews = new News(); existingNews.setTitle("Title"); - existingNews.setSummary("Summary"); existingNews.setBody("Body"); existingNews.setPublicationState("draft"); existingNews.setCanEdit(true); lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), eq(null))).thenReturn(existingNews); News updatedNews = new News(); updatedNews.setTitle("Updated Title"); - updatedNews.setSummary("Updated Summary"); updatedNews.setBody("Updated Body"); updatedNews.setPublicationState(POSTED); - lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT.name().toLowerCase())).then(returnsFirstArg()); + lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT_AND_TITLE.name())).then(returnsFirstArg()); // When - Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews); + ResponseEntity response = newsRestController.updateNews("1", false, null, CONTENT_AND_TITLE.name(), updatedNews); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - News returnedNews = (News) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + News returnedNews = (News) response.getBody(); assertNotNull(returnedNews); assertEquals("Updated Title", returnedNews.getTitle()); - assertEquals("Updated Summary", returnedNews.getSummary()); assertEquals("Updated Body", returnedNews.getBody()); assertEquals(POSTED, returnedNews.getPublicationState()); - when(newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews)).thenThrow(IllegalAccessException.class); + when(newsRestController.updateNews("1", false, null, CONTENT_AND_TITLE.name(), updatedNews)).thenThrow(IllegalAccessException.class); // When - response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews); + response = newsRestController.updateNews("1", false, null, CONTENT_AND_TITLE.name(), updatedNews); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test @@ -398,57 +388,17 @@ public void shouldGetNotFoundWhenUpdatingNewsAndNewsNotExists() throws Exception lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(null); // When - Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), new News()); + ResponseEntity response = newsRestController.updateNews("1", false, null, CONTENT_AND_TITLE.name(), new News()); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode().value()); } - - @Test - public void shouldGetOKWhenPinNewsAndNewsExistsAndUserIsAuthorized() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - - News oldnews = new News(); - oldnews.setTitle("unpinned"); - oldnews.setSummary("unpinned summary"); - oldnews.setBody("unpinned body"); - oldnews.setUploadId(null); - String sDate1 = "22/08/2019"; - Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1); - oldnews.setCreationDate(date1); - oldnews.setPublished(false); - oldnews.setId("id123"); - oldnews.setSpaceId("space"); - oldnews.setCanEdit(true); - - News updatedNews = new News(); - updatedNews.setPublished(true); - - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - List memberships = new LinkedList(); - memberships.add(new MembershipEntry("/platform/web-contributors", "publisher")); - currentIdentity.setMemberships(memberships); - Space space = mock(Space.class); - - lenient().when(newsService.getNewsById("id123", currentIdentity, false)).thenReturn(oldnews); - lenient().when(spaceService.getSpaceById(anyString())).thenReturn(space); - - // When - Response response = newsRestResourcesV1.patchNews(request, "id123", updatedNews); - - // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - } - + @Test public void shouldGetOKWhenUpdatingAndPinNewsAndNewsExistsAndAndUserIsAuthorized() throws Exception { // Given News existingNews = new News(); existingNews.setTitle("unpinned title"); - existingNews.setSummary("unpinned summary"); existingNews.setBody("unpinned body"); existingNews.setUploadId(null); String sDate1 = "22/08/2019"; @@ -462,7 +412,6 @@ public void shouldGetOKWhenUpdatingAndPinNewsAndNewsExistsAndAndUserIsAuthorized News updatedNews = new News(); updatedNews.setPublished(true); updatedNews.setTitle("pinned title"); - updatedNews.setSummary("pinned summary"); updatedNews.setBody("pinned body"); Identity currentIdentity = new Identity(JOHN); @@ -472,219 +421,42 @@ public void shouldGetOKWhenUpdatingAndPinNewsAndNewsExistsAndAndUserIsAuthorized currentIdentity.setMemberships(memberships); lenient().when(newsService.getNewsById("id123", currentIdentity, false, null)).thenReturn(existingNews); - lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT.name().toLowerCase())).then(returnsFirstArg()); + lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT_AND_TITLE.name())).then(returnsFirstArg()); // When - Response response = newsRestResourcesV1.updateNews("id123", false, null, CONTENT.name().toLowerCase(), updatedNews); + ResponseEntity response = newsRestController.updateNews("id123", false, null, CONTENT_AND_TITLE.name(), updatedNews); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - News returnedNews = (News) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + News returnedNews = (News) response.getBody(); assertNotNull(returnedNews); assertEquals("pinned title", returnedNews.getTitle()); - assertEquals("pinned summary", returnedNews.getSummary()); assertEquals("pinned body", returnedNews.getBody()); } - @Test - public void shouldGetOKWhenUpdatingAndUnpinNewsAndNewsExistsAndAndUserIsAuthorized() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - - News oldnews = new News(); - oldnews.setTitle("unpinned"); - oldnews.setSummary("unpinned summary"); - oldnews.setBody("unpinned body"); - oldnews.setUploadId(null); - String sDate1 = "22/08/2019"; - Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1); - oldnews.setCreationDate(date1); - oldnews.setPublished(true); - oldnews.setId("id123"); - oldnews.setSpaceId("space"); - oldnews.setCanEdit(true); - - News updatedNews = new News(); - updatedNews.setPublished(false); - oldnews.setTitle("pinned"); - - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - List memberships = new LinkedList(); - memberships.add(new MembershipEntry("/platform/web-contributors", "publisher")); - currentIdentity.setMemberships(memberships); - - lenient().when(newsService.getNewsById("id123", currentIdentity, false, null)).thenReturn(oldnews); - - // When - Response response = newsRestResourcesV1.updateNews("id123", false, null, CONTENT.name().toLowerCase(), updatedNews); - - // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - } - - @Test - public void shouldGetNotFoundWhenNewsIsNull() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - News updatedNews = new News(); - updatedNews.setPublished(true); - - lenient().when(newsService.getNewsById("id123", currentIdentity, false)).thenReturn(null); - - // When - Response response = newsRestResourcesV1.patchNews(request, "id123", updatedNews); - - // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); - } - - @Test - public void shouldGetOKWhenPatchNewsAndUserIsAuthorized() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - - News oldnews = new News(); - oldnews.setTitle("unpinned"); - oldnews.setSummary("unpinned summary"); - oldnews.setBody("unpinned body"); - oldnews.setUploadId(null); - String sDate1 = "22/08/2019"; - Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1); - oldnews.setCreationDate(date1); - oldnews.setPublished(false); - oldnews.setId("id123"); - oldnews.setSpaceId("space"); - oldnews.setCanEdit(true); - - News updatedNews = new News(); - updatedNews.setPublished(true); - updatedNews.setTitle("title updated"); - updatedNews.setSummary("summary updated"); - updatedNews.setBody("body updated"); - - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - List memberships = new LinkedList(); - memberships.add(new MembershipEntry("/platform/web-contributors", "publisher")); - currentIdentity.setMemberships(memberships); - Space space = mock(Space.class); - - lenient().when(newsService.getNewsById("id123", currentIdentity, false)).thenReturn(oldnews); - lenient().when(spaceService.getSpaceById(anyString())).thenReturn(space); - - // When - Response response = newsRestResourcesV1.patchNews(request, "id123", updatedNews); - - // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - } - - @Test - public void shouldGetOKWhenUnpinNewsAndNewsExistsAndUserIsAuthorized() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - - News oldnews = new News(); - oldnews.setTitle("unpinned"); - oldnews.setSummary("unpinned summary"); - oldnews.setBody("unpinned body"); - oldnews.setUploadId(null); - String sDate1 = "22/08/2019"; - Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1); - oldnews.setCreationDate(date1); - oldnews.setPublished(true); - oldnews.setId("id123"); - oldnews.setSpaceId("space"); - oldnews.setCanEdit(true); - - News updatedNews = new News(); - updatedNews.setPublished(false); - - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - List memberships = new LinkedList(); - memberships.add(new MembershipEntry("/platform/web-contributors", "publisher")); - currentIdentity.setMemberships(memberships); - Space space = mock(Space.class); - - lenient().when(newsService.getNewsById("id123", currentIdentity, false)).thenReturn(oldnews); - lenient().when(spaceService.getSpaceById(anyString())).thenReturn(space); - - // When - Response response = newsRestResourcesV1.patchNews(request, "id123", updatedNews); - - // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - } - @Test public void shouldGetBadRequestWhenUpdatingNewsAndUpdatedNewsIsNull() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - - // When - Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), null); - - // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); - } - - @Test - public void shouldGetBadRequestWhenPatchNewsAndUpdatedNewsIsNull() throws Exception { - // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - - // When - Response response = newsRestResourcesV1.patchNews(request, "1", null); - - // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); - } - - @Test - public void shouldGetUnauthorizedWhenPatchNewsAndUSpaceIsNull() throws Exception { - // Given - News news = new News(); - news.setId("1"); - - HttpServletRequest request = mock(HttpServletRequest.class); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); - lenient().when(newsService.getNewsById("1", currentIdentity, false)).thenReturn(news); // When - Response response = newsRestResourcesV1.patchNews(request, "1", new News()); + ResponseEntity response = newsRestController.updateNews("1", false, null, CONTENT_AND_TITLE.name(), null); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } - + @Test public void shouldGetOKWhenSavingDraftsAndUserIsMemberOfTheSpaceAndSuperManager() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); news.setSpaceId("1"); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean())).thenReturn(news); + lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), anyString())).thenReturn(news); Space space1 = new Space(); space1.setId("1"); space1.setPrettyName("space1"); @@ -693,25 +465,23 @@ public void shouldGetOKWhenSavingDraftsAndUserIsMemberOfTheSpaceAndSuperManager( lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.createNews(request, news); + ResponseEntity response = newsRestController.createNews(news); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); - when(newsRestResourcesV1.createNews(request, news)).thenThrow(IllegalAccessException.class); + when(newsRestController.createNews(news)).thenThrow(IllegalAccessException.class); // When - response = newsRestResourcesV1.createNews(request, news); + response = newsRestController.createNews(news); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetOkWhenCreateNewsWithPublishedState() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -721,23 +491,21 @@ public void shouldGetOkWhenCreateNewsWithPublishedState() throws Exception { Space space1 = new Space(); space1.setId("1"); space1.setPrettyName("space1"); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean())).thenReturn(news); + lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), anyString())).thenReturn(news); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(space1); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.createNews(request, news); + ResponseEntity response = newsRestController.createNews(news); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetOkWhenScheduleNews() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -754,10 +522,10 @@ public void shouldGetOkWhenScheduleNews() throws Exception { lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.scheduleNews(request, ARTICLE.name().toLowerCase(), news); + ResponseEntity response = newsRestController.scheduleNews(ARTICLE.name().toLowerCase(), news); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test @@ -765,88 +533,77 @@ public void shouldGetBadRequestWhenCreatingNewsDraftAndNewsIsNull() throws Excep // Given News news = new News(); news.setId("1"); - - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean())).thenReturn(null); + lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), anyString())).thenReturn(null); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(false); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.createNews(request, new News()); + ResponseEntity response = newsRestController.createNews(new News()); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNewsDraftWhenNewsDraftExistsAndUserIsMemberOfTheSpaceAndSuperManager() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); news.setSpaceId("1"); - when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(news); + when(newsService.getNewsByIdAndLang(anyString(), any(), anyBoolean(), nullable(String.class), nullable(String.class))).thenReturn(news); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNotFoundWhenNewsDraftNotExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean())).thenReturn(null); + lenient().when(newsService.getNewsByIdAndLang(anyString(), any(), anyBoolean(), anyString(), nullable(String.class))).thenReturn(null); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetBadRequestWhenNewsDraftIsNull() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean())).thenReturn(null); + lenient().when(newsService.getNewsByIdAndLang(anyString(), any(), anyBoolean(), anyString(), nullable(String.class))).thenReturn(null); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.getNewsById(request, null, null, null, false); + ResponseEntity response = newsRestController.getNewsById(null, null, null, false, null); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNewsDraftListWhenNewsDraftsExistsAndUserIsMemberOfTheSpaceAndSuperManager() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + lenient().when(request.getRemoteUser()).thenReturn("john"); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -868,17 +625,16 @@ public void shouldGetNewsDraftListWhenNewsDraftsExistsAndUserIsMemberOfTheSpaceA lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, "1", "drafts", "", 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, "1", "drafts", "", 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNotAuthorizedWhenNewsDraftsExistsAndUserIsNotMemberOfTheSpaceNorSuperManager() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -896,9 +652,9 @@ public void shouldGetNotAuthorizedWhenNewsDraftsExistsAndUserIsNotMemberOfTheSpa lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(false); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, "1", "draft", null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, "1", "draft", null, 0, 10, false, request); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test @@ -922,17 +678,15 @@ public void shouldGetNotAuthorizedWhenNewsDraftsExistsAndUserNotExists() throws lenient().when(spaceService.isMember(any(Space.class), any())).thenReturn(true); // When - Response response = newsRestResourcesV1.getNews(request, "mike", "1", "draft", null, 0, 10, false); + ResponseEntity response = newsRestController.getNews("mike", "1", "draft", null, 0, 10, false, request); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldDeleteNewsWhenNewsExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -950,7 +704,7 @@ public void shouldDeleteNewsWhenNewsExists() throws Exception { lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.deleteNews(request, "1", ARTICLE.name().toLowerCase(), 0L); + Response response = newsRestController.deleteNews("1", ARTICLE.name().toLowerCase(), 0L); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); @@ -960,8 +714,6 @@ public void shouldDeleteNewsWhenNewsExists() throws Exception { @Test public void shouldNotDeleteNewsWhenUserIsNotDraftAuthor() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -979,7 +731,7 @@ public void shouldNotDeleteNewsWhenUserIsNotDraftAuthor() throws Exception { lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.deleteNews(request, "1", ARTICLE.name().toLowerCase(), 0L); + Response response = newsRestController.deleteNews("1", ARTICLE.name().toLowerCase(), 0L); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); @@ -989,18 +741,18 @@ public void shouldNotDeleteNewsWhenUserIsNotDraftAuthor() throws Exception { @Test public void shouldGetNotFoundWhenDeletingNewsDraftThatNotExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); + Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(null); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.deleteNews(request, "1", ARTICLE.name().toLowerCase(), 0L); + Response response = newsRestController.deleteNews("1", ARTICLE.name().toLowerCase(), 0L); // Then assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); @@ -1011,18 +763,18 @@ public void shouldGetNotFoundWhenDeletingNewsDraftThatNotExists() throws Excepti public void shouldGetBadRequestWhenDeletingNewsDraftWithIdNull() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); + Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + lenient().when(newsService.getNewsById(anyString(), any(), anyBoolean(), nullable(String.class))).thenReturn(null); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.deleteNews(request, null, ARTICLE.name().toLowerCase(), 0L); + Response response = newsRestController.deleteNews(null, ARTICLE.name().toLowerCase(), 0L); // Then assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -1032,8 +784,6 @@ public void shouldGetBadRequestWhenDeletingNewsDraftWithIdNull() throws Exceptio @Test public void shouldGetAllPublishedNewsWhenExist() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news1 = new News(); @@ -1048,11 +798,11 @@ public void shouldGetAllPublishedNewsWhenExist() throws Exception { lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, null, "", null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, null, "", null, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertEquals(3, newsList.size()); } @@ -1060,9 +810,6 @@ public void shouldGetAllPublishedNewsWhenExist() throws Exception { @Test public void shouldGetEmptyListWhenNoPublishedExists() throws Exception { // Given - - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); NewsFilter newsFilter = new NewsFilter(); @@ -1071,11 +818,11 @@ public void shouldGetEmptyListWhenNoPublishedExists() throws Exception { lenient().when(newsService.getNews(newsFilter, currentIdentity)).thenReturn(null); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, null, null, null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, null, null, null, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); assertNotNull(newsEntity); assertEquals(0, newsEntity.getNews().size()); } @@ -1083,8 +830,8 @@ public void shouldGetEmptyListWhenNoPublishedExists() throws Exception { @Test public void shouldGetOKWhenViewNewsAndNewsExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + + Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -1092,7 +839,7 @@ public void shouldGetOKWhenViewNewsAndNewsExists() throws Exception { news.setSpaceId("space1"); news.setViewsCount((long) 6); - lenient().when(newsService.getNewsById("1", currentIdentity, false, null)).thenReturn(news); + lenient().when(newsService.getNewsByIdAndLang("1", currentIdentity, false, null, null)).thenReturn(news); Space space1 = new Space(); space1.setPrettyName("space1"); lenient().when(spaceService.getSpaceById("space1")).thenReturn(space1); @@ -1100,18 +847,15 @@ public void shouldGetOKWhenViewNewsAndNewsExists() throws Exception { lenient().when(spaceService.isSuperManager(eq(JOHN))).thenReturn(false); // When - Response response = newsRestResourcesV1.getNewsById(request, "1", null, null, false); + ResponseEntity response = newsRestController.getNewsById("1", null, null, false, null); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetNotFoundWhenViewNewsAndNewsIsNull() throws Exception { // Given - - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -1120,18 +864,16 @@ public void shouldGetNotFoundWhenViewNewsAndNewsIsNull() throws Exception { lenient().when(newsService.getNewsById("1", currentIdentity, false, null)).thenReturn(news); // When - Response response = newsRestResourcesV1.getNewsById(request, "2", null, null, false); + ResponseEntity response = newsRestController.getNewsById("2", null, null, false, null); ; // Then - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetAllPinnedNewsWhenExist() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news1 = new News(); @@ -1156,11 +898,11 @@ public void shouldGetAllPinnedNewsWhenExist() throws Exception { lenient().when(newsService.getNewsCount(any())).thenReturn(allNews.size()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, null, "pinned", null, 0, 10, true); + ResponseEntity response = newsRestController.getNews(JOHN, null, "pinned", null, 0, 10, true, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1178,7 +920,6 @@ public void shouldGetAllPinnedNewsWhenExist() throws Exception { public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpaces() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1210,11 +951,11 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpaces() throws Excep lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spacesIds, "", text, 0, 5, false); + ResponseEntity response = newsRestController.getNews(JOHN, spacesIds, "", text, 0, 5, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1233,7 +974,6 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpaces() throws Excep public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpace() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1264,11 +1004,11 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpace() throws Except lenient().when(spaceService.isMember(any(Space.class), any())).thenReturn(true); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spaceId, "", text, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spaceId, "", text, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1284,7 +1024,6 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpace() throws Except public void shouldGetAllNewsWhenSearchingWithTagTextInTheGivenSpace() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1312,11 +1051,11 @@ public void shouldGetAllNewsWhenSearchingWithTagTextInTheGivenSpace() throws Exc lenient().when(spaceService.isMember(any(Space.class), any())).thenReturn(true); lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spaceId, "", tagText, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spaceId, "", tagText, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(2, newsList.size()); @@ -1329,7 +1068,6 @@ public void shouldGetAllNewsWhenSearchingWithTagTextInTheGivenSpace() throws Exc public void shouldGetPinnedNewsWhenSearchingWithTextInTheGivenSpaces() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1364,11 +1102,11 @@ public void shouldGetPinnedNewsWhenSearchingWithTextInTheGivenSpaces() throws Ex lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spacesIds, "pinned", text, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spacesIds, "pinned", text, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1385,7 +1123,6 @@ public void shouldGetPinnedNewsWhenSearchingWithTextInTheGivenSpaces() throws Ex public void shouldGetUnauthorizedWhenSearchingWithTextInNonMemberSpaces() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1406,18 +1143,16 @@ public void shouldGetUnauthorizedWhenSearchingWithTextInNonMemberSpaces() throws lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spacesIds, "pinned", text, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spacesIds, "pinned", text, 0, 10, false, request); // Then - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetMyPostedNewsWhenExists() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1447,11 +1182,11 @@ public void shouldGetMyPostedNewsWhenExists() throws Exception { lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, null, filter, null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, null, filter, null, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1465,7 +1200,6 @@ public void shouldGetMyPostedNewsWhenExists() throws Exception { public void shouldGetMyPostedNewsWhenFilteringWithTheGivenSpaces() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1496,11 +1230,11 @@ public void shouldGetMyPostedNewsWhenFilteringWithTheGivenSpaces() throws Except lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spacesIds, filter, null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spacesIds, filter, null, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1515,7 +1249,6 @@ public void shouldGetMyPostedNewsWhenFilteringWithTheGivenSpaces() throws Except public void shouldGetMyPostedNewsWhenSearchingWithTheGivenSpaces() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1548,11 +1281,11 @@ public void shouldGetMyPostedNewsWhenSearchingWithTheGivenSpaces() throws Except lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, spacesIds, filter, text, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, spacesIds, filter, text, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(3, newsList.size()); @@ -1568,7 +1301,6 @@ public void shouldGetMyPostedNewsWhenSearchingWithTheGivenSpaces() throws Except public void shouldGetStagedNewsWhenCurrentUserIsAuthor() throws Exception { // Given HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); lenient().when(request.getLocale()).thenReturn(new Locale("en")); @@ -1584,11 +1316,11 @@ public void shouldGetStagedNewsWhenCurrentUserIsAuthor() throws Exception { lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.getNews(request, JOHN, null, null, null, 0, 10, false); + ResponseEntity response = newsRestController.getNews(JOHN, null, null, null, 0, 10, false, request); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - NewsEntity newsEntity = (NewsEntity) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + NewsEntity newsEntity = (NewsEntity) response.getBody(); List newsList = newsEntity.getNews(); assertNotNull(newsList); assertEquals(1, newsList.size()); @@ -1599,8 +1331,6 @@ public void shouldGetStagedNewsWhenCurrentUserIsAuthor() throws Exception { @Test public void shouldDeleteNews() throws Exception { // Given - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); @@ -1611,59 +1341,15 @@ public void shouldDeleteNews() throws Exception { lenient().when(spaceService.isMember(any(Space.class), eq(JOHN))).thenReturn(true); // When - Response response = newsRestResourcesV1.deleteNews(request, news.getId(), ARTICLE.name().toLowerCase(), 0); - - // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - } - - @Test - public void getNewsIllustrationTest() throws Exception { - // Given - Request rsRequest = mock(Request.class); - Identity currentIdentity = new Identity(JOHN); - ConversationState.setCurrent(new ConversationState(currentIdentity)); - News news = new News(); - news.setSpaceId("1"); - news.setAuthor(JOHN); - news.setPublished(true); - news.setIllustrationUpdateDate(new Date()); - news.setIllustration("illustration".getBytes()); - news.setIllustrationMimeType("image"); - News news1 = new News(); - news1.setSpaceId("2"); - news1.setAuthor(JOHN); - news1.setPublished(true); - news1.setIllustrationUpdateDate(new Date()); - news1.setIllustration("illustration".getBytes()); - news1.setIllustrationMimeType("image/gif"); - - lenient().when(newsService.getNewsById("1", currentIdentity, false, null)).thenReturn(news); - lenient().when(newsService.getNewsById("2", currentIdentity, false, null)).thenReturn(news1); - - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); + Response response = newsRestController.deleteNews(news.getId(), ARTICLE.name().toLowerCase(), 0); - // When - Response response = newsRestResourcesV1.getNewsIllustration(rsRequest, request, "1", 2316465L, null, "300x300"); - Response response1 = newsRestResourcesV1.getNewsIllustration(rsRequest, request, "2", 2316465L, null, "300x300"); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - byte[] illustration = (byte[]) response.getEntity(); - assertNotNull(illustration); - assertEquals("illustration", new String(illustration)); - assertEquals(Response.Status.OK.getStatusCode(), response1.getStatus()); - byte[] illustration1 = (byte[]) response1.getEntity(); - assertNotNull(illustration1); - assertEquals("illustration", new String(illustration1)); - } @Test public void shouldGetBadRequestWhenSearchingWithoutQueryAndFavorites() throws Exception { // Given - UriInfo uriInfo = mock(UriInfo.class); - HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); String text = "text"; News news1 = new News(); news1.setSpaceId("4"); @@ -1689,17 +1375,15 @@ public void shouldGetBadRequestWhenSearchingWithoutQueryAndFavorites() throws Ex lenient().when(spaceService.getSpaceById(anyString())).thenReturn(new Space()); // When - Response response = newsRestResourcesV1.search(uriInfo, httpServletRequest, "", "", 0, null, 10, false); + ResponseEntity response = newsRestController.search("", "", 0, null, 10, false); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetBadRequestWhenSearchingWithNegativeOffset() throws Exception { // Given - UriInfo uriInfo = mock(UriInfo.class); - HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); String text = "text"; News news1 = new News(); news1.setSpaceId("4"); @@ -1726,17 +1410,15 @@ public void shouldGetBadRequestWhenSearchingWithNegativeOffset() throws Exceptio setCurrentUser(JOHN); // When - Response response = newsRestResourcesV1.search(uriInfo, httpServletRequest, "query", "", -1, null, 10, false); + ResponseEntity response = newsRestController.search("query", "", -1, null, 10, false); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetBadRequestWhenSearchingWithNegativeLimit() throws Exception { // Given - UriInfo uriInfo = mock(UriInfo.class); - HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); String text = "text"; News news1 = new News(); news1.setSpaceId("4"); @@ -1763,17 +1445,15 @@ public void shouldGetBadRequestWhenSearchingWithNegativeLimit() throws Exception setCurrentUser(JOHN); // When - Response response = newsRestResourcesV1.search(uriInfo, httpServletRequest, "query", "", 0, null, -1, false); + ResponseEntity response = newsRestController.search("query", "", 0, null, -1, false); // Then - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode().value()); } @Test public void shouldGetnewsListWhenSearchingWithQuery() throws Exception { // Given - UriInfo uriInfo = mock(UriInfo.class); - HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); String text = "text"; String spacesIds = "4,1"; News news1 = new News(); @@ -1801,11 +1481,11 @@ public void shouldGetnewsListWhenSearchingWithQuery() throws Exception { setCurrentUser(JOHN); // When - Response response = newsRestResourcesV1.search(uriInfo, httpServletRequest, text, "", 0, null, 10, false); + ResponseEntity response = newsRestController.search(text, "", 0, null, 10, false); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - List newsList = (List) response.getEntity(); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); + List newsList = (List) response.getBody(); assertNotNull(newsList); assertEquals(0, newsList.size()); } @@ -1816,16 +1496,49 @@ private void setCurrentUser(final String name) { @Test public void testMarkAsRead() throws Exception { - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn(JOHN); Identity currentIdentity = new Identity(JOHN); ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); when(newsService.getNewsById("1", currentIdentity, false, ARTICLE.name().toLowerCase())).thenReturn(news); doNothing().when(newsService).markAsRead(news, JOHN); - Response response = newsRestResourcesV1.markNewsAsRead(request, "1"); + Response response = newsRestController.markNewsAsRead( "1"); verify(newsService, times(1)).markAsRead(news, JOHN); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); } + + @Test + public void testDeleteArticleTranslation() throws Exception { + Identity currentIdentity = new Identity(JOHN); + ConversationState.setCurrent(new ConversationState(currentIdentity)); + News news = new News(); + news.setId("1"); + news.setCanDelete(false); + news.setLang("fr"); + when(newsService.getNewsById("1", currentIdentity, false, ARTICLE.name())).thenReturn(news); + // + Response response = newsRestController.deleteArticleTranslation(news.getId(), news.getLang()); + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); + + news.setCanDelete(true); + response = newsRestController.deleteArticleTranslation(news.getId(), news.getLang()); + assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + + } + + @Test + public void getArticleAvailableTranslationLanguages() throws Exception { + // + ResponseEntity responseEntity = newsRestController.getAvailableTranslationLanguages("", false); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), responseEntity.getStatusCode().value()); + // + when(newsService.getArticleLanguages(anyString(), anyBoolean())).thenReturn(Arrays.asList(new String[]{"fr"})); + responseEntity = newsRestController.getAvailableTranslationLanguages("1", false); + assertEquals(Response.Status.OK.getStatusCode(), responseEntity.getStatusCode().value()); + // + when(newsService.getArticleLanguages(anyString(), anyBoolean())).thenThrow(new Exception()); + responseEntity = newsRestController.getAvailableTranslationLanguages("1", false); + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), responseEntity.getStatusCode().value()); + + } } diff --git a/content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestResourcesV1Test.java b/content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestTest.java similarity index 65% rename from content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestResourcesV1Test.java rename to content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestTest.java index 9c6dc6481..6ea9111a3 100644 --- a/content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestResourcesV1Test.java +++ b/content-service/src/test/java/io/meeds/news/rest/NewsTargetingRestTest.java @@ -21,19 +21,22 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.when; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; + import javax.ws.rs.core.Response; import javax.ws.rs.ext.RuntimeDelegate; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -46,10 +49,11 @@ import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; -import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; @RunWith(MockitoJUnitRunner.class) -public class NewsTargetingRestResourcesV1Test { +public class NewsTargetingRestTest { @Mock NewsTargetingService newsTargetingService; @@ -60,53 +64,52 @@ public class NewsTargetingRestResourcesV1Test { @Mock IdentityManager identityManager; + @InjectMocks + private NewsTargetingRest newsTargetingRestController; + @Before public void setup() { + newsTargetingRestController.init(); RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); } @Test public void shouldReturnOkWhenGetTargets() { // Given - NewsTargetingRestResourcesV1 newsTargetingRestResourcesV1 = new NewsTargetingRestResourcesV1(newsTargetingService, container); - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn("john"); + when(newsTargetingService.getAllTargets()).thenReturn(new ArrayList<>()); // When - Response response = newsTargetingRestResourcesV1.getAllTargets(request); + ResponseEntity response = newsTargetingRestController.getAllTargets(); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(HttpStatus.OK.value(), response.getStatusCodeValue()); } @Test public void shouldReturnOkWhenGetAllowedTargets() { + Identity currentIdentity = new Identity("john"); + ConversationState.setCurrent(new ConversationState(currentIdentity)); // Given - NewsTargetingRestResourcesV1 newsTargetingRestResourcesV1 = new NewsTargetingRestResourcesV1(newsTargetingService, container); - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn("john"); - + lenient().when(newsTargetingService.getAllTargets()).thenReturn(new ArrayList<>()); // When - Response response = newsTargetingRestResourcesV1.getAllowedTargets(request); + ResponseEntity response = newsTargetingRestController.getAllowedTargets(); // Then - assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + assertEquals(org.springframework.http.HttpStatus.OK.value(), response.getStatusCodeValue()); - when(newsTargetingRestResourcesV1.getAllowedTargets(request)).thenThrow(RuntimeException.class); + when(newsTargetingRestController.getAllowedTargets()).thenThrow(RuntimeException.class); // When - response = newsTargetingRestResourcesV1.getAllowedTargets(request); + response = newsTargetingRestController.getAllowedTargets(); // Then - assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatusCodeValue()); + } @Test public void shouldReturnOkWhenDeleteNewsTarget() { // Given - NewsTargetingRestResourcesV1 newsTargetingRestResourcesV1 = new NewsTargetingRestResourcesV1(newsTargetingService, container); - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn("john"); Identity currentIdentity = new Identity("john"); ConversationState.setCurrent(new ConversationState(currentIdentity)); @@ -117,15 +120,15 @@ public void shouldReturnOkWhenDeleteNewsTarget() { lenient().when(newsTargetingService.getAllTargets()).thenReturn(targets); // When - Response response = newsTargetingRestResourcesV1.deleteTarget(request, targets.get(0).getName(), 0); + Response response = newsTargetingRestController.deleteTarget(targets.get(0).getName(), 0); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - when(newsTargetingRestResourcesV1.deleteTarget(request, targets.get(0).getName(), 0)).thenThrow(RuntimeException.class); + when(newsTargetingRestController.deleteTarget(targets.get(0).getName(), 0)).thenThrow(RuntimeException.class); // When - response = newsTargetingRestResourcesV1.deleteTarget(request, targets.get(0).getName(), 0); + response = newsTargetingRestController.deleteTarget(targets.get(0).getName(), 0); // Then assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); @@ -134,9 +137,7 @@ public void shouldReturnOkWhenDeleteNewsTarget() { @Test public void shouldReturnOkWhenCreateTargets() throws IllegalAccessException { // Given - NewsTargetingRestResourcesV1 newsTargetingRestResourcesV1 = new NewsTargetingRestResourcesV1(newsTargetingService, container); - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn("john"); + Identity currentIdentity = new Identity("john"); ConversationState.setCurrent(new ConversationState(currentIdentity)); Metadata sliderNews = new Metadata(); @@ -153,15 +154,15 @@ public void shouldReturnOkWhenCreateTargets() throws IllegalAccessException { lenient().when(newsTargetingService.createNewsTarget(newsTargetingEntity, currentIdentity)).thenReturn(sliderNews); // When - Response response = newsTargetingRestResourcesV1.createNewsTarget(request, newsTargetingEntity); + Response response = newsTargetingRestController.createNewsTarget(newsTargetingEntity); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - when(newsTargetingRestResourcesV1.createNewsTarget(request, newsTargetingEntity)).thenThrow(RuntimeException.class); + when(newsTargetingRestController.createNewsTarget(newsTargetingEntity)).thenThrow(RuntimeException.class); // When - response = newsTargetingRestResourcesV1.createNewsTarget(request, newsTargetingEntity); + response = newsTargetingRestController.createNewsTarget(newsTargetingEntity); // Then assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); @@ -171,9 +172,6 @@ public void shouldReturnOkWhenCreateTargets() throws IllegalAccessException { @Test public void shouldReturnOkWhenUpdateTargets() throws IllegalAccessException { // Given - NewsTargetingRestResourcesV1 newsTargetingRestResourcesV1 = new NewsTargetingRestResourcesV1(newsTargetingService, container); - HttpServletRequest request = mock(HttpServletRequest.class); - lenient().when(request.getRemoteUser()).thenReturn("john"); Identity currentIdentity = new Identity("john"); ConversationState.setCurrent(new ConversationState(currentIdentity)); Metadata sliderNews = new Metadata(); @@ -192,16 +190,16 @@ public void shouldReturnOkWhenUpdateTargets() throws IllegalAccessException { .thenReturn(sliderNews); // When - Response response = newsTargetingRestResourcesV1.updateNewsTarget(newsTargetingEntity, originalTargetName); + Response response = newsTargetingRestController.updateNewsTarget(newsTargetingEntity, originalTargetName); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); - when(newsTargetingRestResourcesV1.updateNewsTarget(newsTargetingEntity, + when(newsTargetingRestController.updateNewsTarget(newsTargetingEntity, originalTargetName)).thenThrow(RuntimeException.class); // When - response = newsTargetingRestResourcesV1.updateNewsTarget(newsTargetingEntity, originalTargetName); + response = newsTargetingRestController.updateNewsTarget(newsTargetingEntity, originalTargetName); // Then assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus()); diff --git a/content-service/src/test/java/io/meeds/news/search/NewsSearchConnectorTest.java b/content-service/src/test/java/io/meeds/news/search/NewsSearchConnectorTest.java index ade84a703..d470fd832 100644 --- a/content-service/src/test/java/io/meeds/news/search/NewsSearchConnectorTest.java +++ b/content-service/src/test/java/io/meeds/news/search/NewsSearchConnectorTest.java @@ -22,9 +22,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.MockitoAnnotations.openMocks; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -37,17 +39,14 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; import org.exoplatform.commons.search.es.client.ElasticSearchingClient; import org.exoplatform.commons.utils.IOUtil; import org.exoplatform.commons.utils.PropertyManager; import org.exoplatform.container.configuration.ConfigurationManager; -import org.exoplatform.container.xml.InitParams; -import org.exoplatform.container.xml.PropertiesParam; -import org.exoplatform.container.xml.ValueParam; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider; import org.exoplatform.social.core.jpa.search.ActivitySearchConnector; @@ -55,6 +54,8 @@ import org.exoplatform.social.core.storage.api.ActivityStorage; import io.meeds.news.filter.NewsFilter; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; @RunWith(MockitoJUnitRunner.class) public class NewsSearchConnectorTest { @@ -76,17 +77,25 @@ public class NewsSearchConnectorTest { @Mock ElasticSearchingClient client; + @InjectMocks + NewsSearchConnector newsSearchConnector; + String searchResult = null; boolean developingValue = false; @Before public void setUp() throws Exception {// NOSONAR + openMocks(this); + // set filed injected by the @Value annotation + ReflectionTestUtils.setField(newsSearchConnector, "index", "news_alias"); + ReflectionTestUtils.setField(newsSearchConnector, "searchType", "news"); + ReflectionTestUtils.setField(newsSearchConnector, "searchQueryFilePath", "jar:/news-search-query.json"); searchResult = IOUtil.getStreamContentAsString(getClass().getClassLoader().getResourceAsStream("news-search-result.json")); try { Mockito.reset(configurationManager); - lenient().when(configurationManager.getInputStream("FILE_PATH")) + lenient().when(configurationManager.getInputStream(anyString())) .thenReturn(new ByteArrayInputStream(FAKE_ES_QUERY.getBytes())); } catch (Exception e) { throw new IllegalStateException("Error retrieving ES Query content", e); @@ -94,6 +103,7 @@ public void setUp() throws Exception {// NOSONAR developingValue = PropertyManager.isDevelopping(); PropertyManager.setProperty(PropertyManager.DEVELOPING, "false"); PropertyManager.refresh(); + newsSearchConnector.init(); } @After @@ -104,11 +114,6 @@ public void tearDown() { @Test public void testSearchArguments() { - NewsSearchConnector newsSearchConnector = new NewsSearchConnector(configurationManager, - identityManager, - activityStorage, - client, - getParams()); NewsFilter filter = new NewsFilter(); filter.setSearchText("term"); filter.setLimit(0); @@ -145,12 +150,6 @@ public void testSearchArguments() { @Test public void testSearchNoResult() { - NewsSearchConnector newsSearchConnector = new NewsSearchConnector(configurationManager, - identityManager, - activityStorage, - client, - getParams()); - NewsFilter filter = new NewsFilter(); filter.setSearchText("term"); filter.setLimit(10); @@ -178,12 +177,6 @@ public void testSearchNoResult() { @Test public void testSearchWithResult() { - NewsSearchConnector newsSearchConnector = new NewsSearchConnector(configurationManager, - identityManager, - activityStorage, - client, - getParams()); - NewsFilter filter = new NewsFilter(); filter.setSearchText("term"); filter.setLimit(10); @@ -220,12 +213,6 @@ public void testSearchWithResult() { @Test public void testSearchWithIdentityResult() throws IOException {// NOSONAR - NewsSearchConnector newsSearchConnector = new NewsSearchConnector(configurationManager, - identityManager, - activityStorage, - client, - getParams()); - NewsFilter filter = new NewsFilter(); filter.setSearchText("john"); filter.setLimit(10); @@ -263,19 +250,5 @@ public void testSearchWithIdentityResult() throws IOException {// NOSONAR assertEquals(0, newsESSearchResult.getExcerpts().size()); } - private InitParams getParams() { - InitParams params = new InitParams(); - PropertiesParam propertiesParam = new PropertiesParam(); - propertiesParam.setName("constructor.params"); - propertiesParam.setProperty("index", ES_INDEX); - - ValueParam valueParam = new ValueParam(); - valueParam.setName("query.file.path"); - valueParam.setValue("FILE_PATH"); - - params.addParameter(propertiesParam); - params.addParameter(valueParam); - return params; - } } diff --git a/content-service/src/test/java/io/meeds/news/service/impl/NewsServiceImplTest.java b/content-service/src/test/java/io/meeds/news/service/impl/NewsServiceImplTest.java index 82789b942..dddf3da2b 100644 --- a/content-service/src/test/java/io/meeds/news/service/impl/NewsServiceImplTest.java +++ b/content-service/src/test/java/io/meeds/news/service/impl/NewsServiceImplTest.java @@ -22,7 +22,8 @@ import static io.meeds.news.service.impl.NewsServiceImpl.*; import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; import static io.meeds.news.utils.NewsUtils.NewsObjectType.LATEST_DRAFT; -import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT; +import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT_AND_TITLE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -33,12 +34,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Arrays; @@ -50,6 +46,8 @@ import io.meeds.news.search.NewsSearchConnector; import io.meeds.news.search.NewsESSearchResult; +import io.meeds.notes.model.NoteFeaturedImage; +import io.meeds.notes.model.NotePageProperties; import org.exoplatform.services.security.ConversationState; import org.exoplatform.social.core.utils.MentionUtils; import org.exoplatform.wiki.WikiException; @@ -57,8 +55,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; import org.exoplatform.commons.file.services.FileService; @@ -129,7 +129,8 @@ public class NewsServiceImplTest { @Mock private NewsSearchConnector newsSearchConnector; - private NewsService newsService; + @InjectMocks + private NewsServiceImpl newsService; private static final MockedStatic COMMONS_UTILS = mockStatic(CommonsUtils.class); @@ -143,18 +144,6 @@ public class NewsServiceImplTest { @Before public void setUp() { - this.newsService = new NewsServiceImpl(spaceService, - noteService, - metadataService, - fileService, - newsTargetingService, - indexingService, - identityManager, - activityManager, - wikiService, - uploadService, - newsSearchConnector); - when(johnIdentity.getUserId()).thenReturn("john"); ConversationState conversationState = mock(ConversationState.class); CONVERSATION_STATE.when(ConversationState::getCurrent).thenReturn(conversationState); @@ -176,7 +165,6 @@ public void testCreateDraftArticle() throws Exception { News draftArticle = new News(); draftArticle.setAuthor("john"); draftArticle.setTitle("draft article for new page"); - draftArticle.setSummary("draft article summary for new page"); draftArticle.setBody("draft body"); draftArticle.setPublicationState("draft"); @@ -211,7 +199,7 @@ public void testCreateDraftArticle() throws Exception { when(noteService.getNoteOfNoteBookByName("group", space.getGroupId(), NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME)).thenReturn(rootPage); - when(noteService.createDraftForNewPage(any(DraftPage.class), anyLong())).thenReturn(draftPage); + when(noteService.createDraftForNewPage(any(DraftPage.class), anyLong(), anyLong())).thenReturn(draftPage); when(rootPage.getId()).thenReturn("1"); org.exoplatform.social.core.identity.model.Identity identity1 = mock(org.exoplatform.social.core.identity.model.Identity.class); @@ -228,7 +216,8 @@ public void testCreateDraftArticle() throws Exception { verify(metadataService, times(1)).createMetadataItem(any(NewsDraftObject.class), any(MetadataKey.class), any(Map.class), - anyLong()); + anyLong(), + anyBoolean()); assertNotNull(savedDraftArticle.getId()); assertEquals(draftPage.getId(), savedDraftArticle.getId()); assertEquals(draftPage.getTitle(), savedDraftArticle.getTitle()); @@ -256,7 +245,6 @@ public void testGetDraftArticleById() throws Exception { when(metadataService.getMetadataItemsByMetadataAndObject(any(MetadataKey.class), any(MetadataObject.class))).thenReturn(metadataItems); Map properties = new HashMap<>(); - properties.put(NEWS_SUMMARY, draftPage.getContent()); when(metadataItem.getProperties()).thenReturn(properties); PORTAL_CONTAINER.when(PortalContainer::getCurrentPortalContainerName).thenReturn("portal"); COMMONS_UTILS.when(CommonsUtils::getCurrentPortalOwner).thenReturn("dw"); @@ -319,7 +307,6 @@ public void testUpdateDraftArticle() throws Exception { news.setId("1"); news.setPublicationState("draft"); news.setSpaceId(space.getId()); - news.setSummary("news summary"); DraftPage expecteddraftPage = new DraftPage(); expecteddraftPage.setTitle(news.getTitle()); @@ -329,7 +316,7 @@ public void testUpdateDraftArticle() throws Exception { expecteddraftPage.setWikiOwner("/space/groupId"); // When, Then - assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase())); + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name())); // Given when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); @@ -337,14 +324,13 @@ public void testUpdateDraftArticle() throws Exception { mock(org.exoplatform.social.core.identity.model.Identity.class); when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(identity1); when(identity1.getId()).thenReturn("1"); - when(noteService.updateDraftForNewPage(any(DraftPage.class), anyLong())).thenReturn(expecteddraftPage); + when(noteService.updateDraftForNewPage(any(DraftPage.class), anyLong(), anyLong())).thenReturn(expecteddraftPage); // When - newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); + newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name()); // Then - verify(noteService, times(1)).updateDraftForNewPage(eq(expecteddraftPage), anyLong()); - verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + verify(noteService, times(1)).updateDraftForNewPage(eq(expecteddraftPage), anyLong(), anyLong()); } @Test @@ -475,7 +461,6 @@ public void testGetDraftArticles() throws Exception { when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); Map properties = new HashMap<>(); - properties.put(NEWS_SUMMARY, draftPage.getContent()); MetadataItem metadataItem = mock(MetadataItem.class); List metadataItems = Arrays.asList(metadataItem); when(metadataItem.getObjectId()).thenReturn("1"); @@ -512,7 +497,6 @@ public void testPostNews() throws Exception { News newsArticle = new News(); newsArticle.setAuthor("john"); newsArticle.setTitle("news article for new page"); - newsArticle.setSummary("news article summary for new page"); newsArticle.setBody("news body"); newsArticle.setPublicationState(POSTED); newsArticle.setId("1"); @@ -557,7 +541,8 @@ public void testPostNews() throws Exception { verify(metadataService, atLeast(1)).createMetadataItem(any(MetadataObject.class), any(MetadataKey.class), any(Map.class), - anyLong()); + anyLong(), + anyBoolean()); } @Test @@ -603,11 +588,10 @@ public void testCreateDraftArticleForExistingPage() throws Exception { news.setId("1"); news.setPublicationState("draft"); news.setSpaceId("1"); - news.setSummary("news summary"); news.setOriginalBody("body"); // When, Then - assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase())); + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name())); // Given when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); @@ -629,7 +613,7 @@ public void testCreateDraftArticleForExistingPage() throws Exception { anyString())).thenReturn(draftPage); // When - newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); + newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name()); // Then verify(noteService, times(1)).createDraftForExistPage(any(DraftPage.class), @@ -640,7 +624,8 @@ public void testCreateDraftArticleForExistingPage() throws Exception { verify(metadataService, times(1)).createMetadataItem(any(NewsLatestDraftObject.class), any(MetadataKey.class), any(Map.class), - anyLong()); + anyLong(), + anyBoolean()); } @@ -686,11 +671,10 @@ public void testUpdateDraftArticleForExistingPage() throws Exception { news.setId("1"); news.setPublicationState("draft"); news.setSpaceId("1"); - news.setSummary("news summary"); news.setOriginalBody("body"); // When, Then - assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase())); + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name())); // Given when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); @@ -707,7 +691,7 @@ public void testUpdateDraftArticleForExistingPage() throws Exception { anyString())).thenReturn(draftPage); // When - newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); + newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name()); // Then verify(noteService, times(1)).updateDraftForExistPage(any(DraftPage.class), @@ -715,7 +699,7 @@ public void testUpdateDraftArticleForExistingPage() throws Exception { nullable(String.class), anyLong(), anyString()); - verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong(), anyBoolean()); } @Test @@ -763,11 +747,10 @@ public void testUpdateNewsArticle() throws Exception { news.setId("1"); news.setPublicationState(POSTED); news.setSpaceId("1"); - news.setSummary("news summary"); news.setOriginalBody("body"); // When, Then - assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase())); + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name())); // Given when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); @@ -777,16 +760,15 @@ public void testUpdateNewsArticle() throws Exception { when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(identity1); when(identity1.getId()).thenReturn("1"); - when(noteService.updateNote(any(Page.class))).thenReturn(existingPage); + when(noteService.updateNote(any(Page.class), any(), any())).thenReturn(existingPage); // When - newsService.updateNews(news, "john", false, false, ARTICLE.name().toLowerCase(), CONTENT.name().toLowerCase()); + newsService.updateNews(news, "john", false, false, ARTICLE.name().toLowerCase(), CONTENT_AND_TITLE.name()); // Then - verify(noteService, times(1)).updateNote(any(Page.class)); + verify(noteService, times(1)).updateNote(any(Page.class), any(), any()); verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId()); - verify(noteService, times(2)).getPublishedVersionByPageIdAndLang(1L, null); - verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + verify(noteService, times(1)).getPublishedVersionByPageIdAndLang(1L, null); } @Test @@ -827,9 +809,16 @@ public void testDeleteNewsArticle() throws Exception { when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); when(noteService.deleteNote(existingPage.getWikiType(), existingPage.getWikiOwner(), existingPage.getName())).thenReturn(true); DraftPage draftPage = mock(DraftPage.class); + NotePageProperties draftProperties = new NotePageProperties(); + NoteFeaturedImage noteFeaturedImage = new NoteFeaturedImage(); + noteFeaturedImage.setId(123L); + draftProperties.setFeaturedImage(noteFeaturedImage); when(draftPage.getId()).thenReturn("1"); + when(draftPage.getProperties()).thenReturn(draftProperties); when(noteService.getLatestDraftOfPage(existingPage, identity.getUserId())).thenReturn(draftPage); when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); + when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(new org.exoplatform.social.core.identity.model.Identity("1")); + doNothing().when(noteService).removeNoteFeaturedImage(anyLong(), anyLong(), anyString(), anyBoolean(), anyLong()); newsService.deleteNews(existingPage.getId(), identity, ARTICLE.name().toLowerCase()); @@ -837,7 +826,7 @@ public void testDeleteNewsArticle() throws Exception { verify(noteService, times(1)).deleteNote(existingPage.getWikiType(), existingPage.getWikiOwner(), existingPage.getName()); verify(noteService, times(1)).removeDraftById("1"); verify(activityManager, times(1)).deleteActivity("1"); - verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong(), anyBoolean()); } @Test @@ -865,7 +854,6 @@ public void testScheduleNews() throws Exception { News newsArticle = new News(); newsArticle.setAuthor("john"); newsArticle.setTitle("news article"); - newsArticle.setSummary("news article summary"); newsArticle.setBody("news body"); newsArticle.setPublicationState("staged"); newsArticle.setId("1"); @@ -951,7 +939,7 @@ public void testUnScheduleNews() throws Exception { when(draftPage.getCreatedDate()).thenReturn(new Date()); when(draftPage.getAuthor()).thenReturn("john"); when(draftPage.getId()).thenReturn("1"); - when(noteService.createDraftForNewPage(any(DraftPage.class), anyLong())).thenReturn(draftPage); + when(noteService.createDraftForNewPage(any(DraftPage.class), anyLong(), anyLong())).thenReturn(draftPage); org.exoplatform.social.core.identity.model.Identity identity1 = mock(org.exoplatform.social.core.identity.model.Identity.class); @@ -960,10 +948,81 @@ public void testUnScheduleNews() throws Exception { newsService.unScheduleNews(newsArticle, space.getGroupId(), "john"); - verify(noteService, times(1)).createDraftForNewPage(any(DraftPage.class), anyLong()); + verify(noteService, times(1)).createDraftForNewPage(any(DraftPage.class), anyLong(), anyLong()); verify(noteService, times(1)).deleteNote(anyString(), anyString(), anyString()); } + @Test + public void testAddNewsArticleTranslation() throws Exception { + // Given + Page existingPage = mock(Page.class); + when(noteService.getNoteById(anyString())).thenReturn(existingPage); + when(existingPage.getId()).thenReturn("1"); + when(existingPage.getWikiOwner()).thenReturn("/space/groupId"); + + MetadataItem metadataItem = mock(MetadataItem.class); + List metadataItems = new ArrayList<>(); + metadataItems.add(metadataItem); + when(metadataService.getMetadataItemsByMetadataAndObject(any(MetadataKey.class), + any(MetadataObject.class))).thenReturn(metadataItems); + Map properties = new HashMap<>(); + when(metadataItem.getProperties()).thenReturn(properties); + mockBuildArticle(metadataItems); + + Space space = mockSpace(); + + Identity identity = mockIdentity(); + NEWS_UTILS.when(() -> NewsUtils.canPublishNews(anyString(), any(Identity.class))).thenReturn(false); + NEWS_UTILS.when(() -> NewsUtils.processMentions(anyString(), any())).thenReturn(new HashSet<>()); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); + + DraftPage draftPage = mock(DraftPage.class); + + when(draftPage.getId()).thenReturn("1"); + + PageVersion pageVersion = mock(PageVersion.class); + when(noteService.getPublishedVersionByPageIdAndLang(1L, "fr")).thenReturn(pageVersion); + when(noteService.getLatestDraftPageByUserAndTargetPageAndLang(anyLong(), + anyString(), + anyString())).thenReturn(draftPage); + + when(existingPage.getAuthor()).thenReturn("john"); + when(pageVersion.getAuthor()).thenReturn("john"); + when(pageVersion.getUpdatedDate()).thenReturn(new Date()); + when(pageVersion.getAuthorFullName()).thenReturn("full name"); + + News news = new News(); + news.setAuthor("john"); + news.setTitle("new draft title"); + news.setBody("draft body"); + news.setId("1"); + news.setPublicationState(POSTED); + news.setSpaceId("1"); + news.setOriginalBody("body"); + news.setLang("fr"); + + // When, Then + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT_AND_TITLE.name())); + + // Given + when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + org.exoplatform.social.core.identity.model.Identity identity1 = + mock(org.exoplatform.social.core.identity.model.Identity.class); + when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(identity1); + when(identity1.getId()).thenReturn("1"); + + when(noteService.updateNote(any(Page.class), any(), any())).thenReturn(existingPage); + // When + newsService.updateNews(news, "john", false, false, ARTICLE.name().toLowerCase(), CONTENT_AND_TITLE.name()); + + // Then + verify(noteService, times(1)).updateNote(any(Page.class), any(), any()); + verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId()); + verify(noteService, times(2)).getPublishedVersionByPageIdAndLang(1L, null); + NEWS_UTILS.verify(() -> NewsUtils.broadcastEvent(eq(NewsUtils.ADD_ARTICLE_TRANSLATION), anyObject(), anyObject()), times(1)); + } + private void mockBuildArticle(List metadataItems) throws WikiException { when(metadataService.getMetadataItemsByFilter(any(), anyLong(), anyLong())).thenReturn(metadataItems); Page page = new Page(); diff --git a/content-service/src/test/java/io/meeds/news/service/impl/NewsTargetingImplTest.java b/content-service/src/test/java/io/meeds/news/service/impl/NewsTargetingImplTest.java index 9a78f7073..454c4918d 100644 --- a/content-service/src/test/java/io/meeds/news/service/impl/NewsTargetingImplTest.java +++ b/content-service/src/test/java/io/meeds/news/service/impl/NewsTargetingImplTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -38,11 +39,15 @@ import java.util.List; import java.util.Map; +import org.exoplatform.container.component.RequestLifeCycle; import org.junit.AfterClass; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; +import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; import org.exoplatform.commons.utils.CommonsUtils; @@ -106,6 +111,14 @@ public class NewsTargetingImplTest { @Mock private GroupHandler groupHandler; + @InjectMocks + NewsTargetingServiceImpl newsTargetingService; + + @Before + public void setUp() { + EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getCurrentContainer()).thenReturn(container); + } + @AfterClass public static void afterRunBare() throws Exception { // NOSONAR EXO_CONTAINER_CONTEXT.close(); @@ -116,11 +129,6 @@ public static void afterRunBare() throws Exception { // NOSONAR @Test public void testGetAllTargets() throws Exception { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); - IdentityRegistry identityRegistry = mock(IdentityRegistry.class); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); org.exoplatform.services.security.Identity identity = mock(org.exoplatform.services.security.Identity.class); REST_UTILS.when(() -> RestUtils.getCurrentUser()).thenReturn("root"); @@ -178,10 +186,6 @@ public void testGetAllTargets() throws Exception { @Test public void testGetAllowedTargets() throws Exception { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); org.exoplatform.services.security.Identity identity = mock(org.exoplatform.services.security.Identity.class); REST_UTILS.when(RestUtils::getCurrentUser).thenReturn("user"); @@ -312,10 +316,6 @@ public void testGetAllowedTargets() throws Exception { @Test public void testGetTargetsByNews() throws Exception { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); News news = new News(); news.setId("123456"); news.setSpaceId("1"); @@ -350,10 +350,6 @@ public void testGetTargetsByNews() throws Exception { @Test public void testSaveNewsTargets() throws Exception { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); org.exoplatform.services.security.Identity identity = new org.exoplatform.services.security.Identity("root"); Metadata sliderNews = new Metadata(); sliderNews.setName("sliderNews"); @@ -381,7 +377,6 @@ public void testSaveNewsTargets() throws Exception { MetadataKey metadataKey = new MetadataKey(NewsTargetingService.METADATA_TYPE.getName(), "sliderNews", 0); Identity userIdentity = new Identity("1"); when(identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, "root")).thenReturn(userIdentity); - IdentityRegistry identityRegistry = mock(IdentityRegistry.class); Authenticator authenticator = mock(Authenticator.class); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getCurrentContainer()).thenReturn(container); @@ -402,17 +397,12 @@ public void testSaveNewsTargets() throws Exception { // Then verify(identityManager, times(1)).getOrCreateIdentity(OrganizationIdentityProvider.NAME, "root"); - verify(metadataService, times(1)).createMetadataItem(newsTargetObject, metadataKey, properties, 1); + verify(metadataService, times(1)).createMetadataItem(newsTargetObject, metadataKey, properties, 1, false); } @Test public void testGetNewsTargetItemsByTargetName() throws Exception { - // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); Metadata sliderNews = new Metadata(); sliderNews.setName("newsTargets"); @@ -446,15 +436,10 @@ public void testGetNewsTargetItemsByTargetName() throws Exception { @Test public void testDeleteTargetByName() throws IllegalAccessException { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); String username = "user"; Identity userIdentity = new Identity(); userIdentity.setRemoteId(username); - IdentityRegistry identityRegistry = mock(IdentityRegistry.class); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); org.exoplatform.services.security.Identity identity = mock(org.exoplatform.services.security.Identity.class); when(identity.isMemberOf("/platform/web-contributors", "manager")).thenReturn(true); @@ -484,10 +469,6 @@ public void testDeleteTargetByName() throws IllegalAccessException { @Test public void testCreateTarget() throws IllegalAccessException { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); org.exoplatform.services.security.Identity currentIdentity = new org.exoplatform.services.security.Identity("root"); MembershipEntry membershipentry = new MembershipEntry("/platform/web-contributors", "manager"); List memberships = new ArrayList(); @@ -495,7 +476,7 @@ public void testCreateTarget() throws IllegalAccessException { currentIdentity.setMemberships(memberships); Identity userIdentity = new Identity("organization", "root"); userIdentity.setId("1"); - when(identityManager.getOrCreateIdentity(any(), any())).thenReturn(userIdentity); + when(identityManager.getOrCreateIdentity(anyString(), anyString())).thenReturn(userIdentity); List newsTargets = new LinkedList<>(); Metadata sliderNews = new Metadata(); @@ -537,8 +518,7 @@ public void testCreateTarget() throws IllegalAccessException { userIdentity1.setId(id1); userIdentity1.setRemoteId(username1); - IdentityRegistry identityRegistry1 = mock(IdentityRegistry.class); - EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry1); + EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); org.exoplatform.services.security.Identity identity1 = mock(org.exoplatform.services.security.Identity.class); try { newsTargetingService.createNewsTarget(newsTargetingEntity, identity1); @@ -551,10 +531,6 @@ public void testCreateTarget() throws IllegalAccessException { @Test public void testUpdateTarget() throws IllegalAccessException { // Given - NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, - identityManager, - spaceService, - organizationService); org.exoplatform.services.security.Identity currentIdentity = new org.exoplatform.services.security.Identity("root"); MembershipEntry membershipentry = new MembershipEntry("/platform/web-contributors", "manager"); List memberships = new ArrayList(); diff --git a/content-service/src/test/resources/conf/portal/configuration.xml b/content-service/src/test/resources/conf/portal/configuration.xml deleted file mode 100644 index 2eeadc4a0..000000000 --- a/content-service/src/test/resources/conf/portal/configuration.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - io.meeds.news.search.NewsSearchConnector - - - query.file.path - ${exo.news.es.query.path:jar:/news-search-query.json} - - - constructor.params - - - - - - - diff --git a/content-webapp/pom.xml b/content-webapp/pom.xml index e74a9f44d..d1b92ed1a 100644 --- a/content-webapp/pom.xml +++ b/content-webapp/pom.xml @@ -44,6 +44,11 @@ commons-api provided + + io.meeds.social + social-component-service + provided + ${project.groupId} content-service @@ -55,6 +60,11 @@ sources provided + + io.meeds.social + social-component-web + provided + diff --git a/content-webapp/src/main/java/ContentApplication.java b/content-webapp/src/main/java/io/meeds/news/ContentApplication.java similarity index 96% rename from content-webapp/src/main/java/ContentApplication.java rename to content-webapp/src/main/java/io/meeds/news/ContentApplication.java index db70c5e76..ddcb20b06 100644 --- a/content-webapp/src/main/java/ContentApplication.java +++ b/content-webapp/src/main/java/io/meeds/news/ContentApplication.java @@ -17,6 +17,7 @@ * 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.news; import io.meeds.spring.AvailableIntegration; import io.meeds.spring.kernel.PortalApplicationContextInitializer; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -27,7 +28,7 @@ ContentApplication.MODULE_NAME, AvailableIntegration.KERNEL_MODULE, AvailableIntegration.JPA_MODULE, - AvailableIntegration.WEB_SECURITY_MODULE, + AvailableIntegration.WEB_MODULE, }, exclude = { LiquibaseAutoConfiguration.class, }) diff --git a/content-webapp/src/main/java/io/meeds/news/portlet/NewsListViewPortlet.java b/content-webapp/src/main/java/io/meeds/news/portlet/NewsListViewPortlet.java index 0db0c8001..ecf559516 100644 --- a/content-webapp/src/main/java/io/meeds/news/portlet/NewsListViewPortlet.java +++ b/content-webapp/src/main/java/io/meeds/news/portlet/NewsListViewPortlet.java @@ -21,17 +21,31 @@ import java.io.IOException; import java.util.Enumeration; +import java.util.Random; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; +import javax.portlet.PortletConfig; import javax.portlet.PortletException; import javax.portlet.PortletPreferences; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; import org.apache.commons.lang3.StringUtils; -import org.exoplatform.commons.api.portlet.GenericDispatchedViewPortlet; +import io.meeds.social.portlet.CMSPortlet; -public class NewsListViewPortlet extends GenericDispatchedViewPortlet { +public class NewsListViewPortlet extends CMSPortlet { + + private static final String OBJECT_TYPE = "newsListViewPortlet"; + + private static final String APPLICATION_ID = "applicationId"; + + @Override + public void init(PortletConfig config) throws PortletException { + super.init(config); + this.contentType = OBJECT_TYPE; + } @Override public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { @@ -47,4 +61,20 @@ public void processAction(ActionRequest request, ActionResponse response) throws } preferences.store(); } + + @Override + public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { + request.setAttribute(APPLICATION_ID, getOrCreateApplicationId(request.getPreferences())); + super.doView(request, response); + } + + private String getOrCreateApplicationId(PortletPreferences preferences) { + String applicationId = preferences.getValue(APPLICATION_ID, null); + if (applicationId == null) { + Random random = new Random(); + applicationId = String.valueOf(Math.abs(random.nextLong())); + savePreference(APPLICATION_ID, applicationId); + } + return applicationId; + } } diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/configuration.xml index c7a9ee487..fb4a4bcd6 100644 --- a/content-webapp/src/main/webapp/WEB-INF/conf/configuration.xml +++ b/content-webapp/src/main/webapp/WEB-INF/conf/configuration.xml @@ -31,7 +31,6 @@ war:/conf/news/search-configuration.xml war:/conf/news/metadata-plugins-configuration.xml war:/conf/news/gamification-configuration.xml - war:/conf/news/activity-listener-configuration.xml war:/conf/news/ckeditor-configuration.xml diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/news/activity-listener-configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/news/activity-listener-configuration.xml deleted file mode 100644 index 37bdd8f8e..000000000 --- a/content-webapp/src/main/webapp/WEB-INF/conf/news/activity-listener-configuration.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - org.exoplatform.social.core.manager.ActivityManager - - NewsActivityListener - addActivityEventListener - io.meeds.news.listener.NewsActivityListener - - - ActivityNewsProcessor - addProcessorPlugin - io.meeds.news.activity.processor.ActivityNewsProcessor - - - priority - priority of this processor (lower are executed first) - 30 - - - - - - - org.exoplatform.services.listener.ListenerService - - exo.news.postArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.updateArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.deleteArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.viewArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.shareArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.commentArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - exo.news.likeArticle - addListener - io.meeds.news.listener.AnalyticsNewsListener - - - - - org.exoplatform.services.listener.ListenerService - - exo.news.postArticle - addListener - io.meeds.news.listener.AttachedActivityCacheUpdater - - - exo.news.updateArticle - addListener - io.meeds.news.listener.AttachedActivityCacheUpdater - - - exo.news.shareArticle - addListener - io.meeds.news.listener.AttachedActivityCacheUpdater - - - exo.news.scheduleArticle - addListener - io.meeds.news.listener.AttachedActivityCacheUpdater - - - exo.news.unscheduleArticle - addListener - io.meeds.news.listener.AttachedActivityCacheUpdater - - - \ No newline at end of file diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/news/gamification-configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/news/gamification-configuration.xml index 64fa83815..fc4fded08 100644 --- a/content-webapp/src/main/webapp/WEB-INF/conf/news/gamification-configuration.xml +++ b/content-webapp/src/main/webapp/WEB-INF/conf/news/gamification-configuration.xml @@ -22,20 +22,6 @@ - - - org.exoplatform.services.listener.ListenerService - - exo.news.gamification.postArticle - addListener - io.meeds.news.listener.NewsGamificationIntegrationListener - - - exo.news.gamification.PublishArticle - addListener - io.meeds.news.listener.NewsGamificationIntegrationListener - - io.meeds.gamification.service.EventRegistry diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/news/metadata-plugins-configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/news/metadata-plugins-configuration.xml index 23920c425..5ce1971e0 100644 --- a/content-webapp/src/main/webapp/WEB-INF/conf/news/metadata-plugins-configuration.xml +++ b/content-webapp/src/main/webapp/WEB-INF/conf/news/metadata-plugins-configuration.xml @@ -106,38 +106,4 @@ - - - org.exoplatform.services.listener.ListenerService - - exo.news.postArticle - addListener - io.meeds.news.listener.NewsMetadataListener - - - exo.news.updateArticle - addListener - io.meeds.news.listener.NewsMetadataListener - - - exo.news.shareArticle - addListener - io.meeds.news.listener.NewsMetadataListener - - - social.metadataItem.deleted - addListener - io.meeds.news.listener.MetadataItemModified - - - social.metadataItem.updated - addListener - io.meeds.news.listener.MetadataItemModified - - - social.metadataItem.created - addListener - io.meeds.news.listener.MetadataItemModified - - \ No newline at end of file diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/news/news-configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/news/news-configuration.xml index cfabec70f..e16eb920f 100644 --- a/content-webapp/src/main/webapp/WEB-INF/conf/news/news-configuration.xml +++ b/content-webapp/src/main/webapp/WEB-INF/conf/news/news-configuration.xml @@ -23,24 +23,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"> - - - io.meeds.news.service.NewsService - io.meeds.news.service.impl.NewsServiceImpl - - - - io.meeds.news.service.NewsTargetingService - io.meeds.news.service.impl.NewsTargetingServiceImpl - - - io.meeds.news.rest.NewsRestResourcesV1 - - - - io.meeds.news.rest.NewsTargetingRestResourcesV1 - org.exoplatform.services.resources.ResourceBundleService diff --git a/content-webapp/src/main/webapp/WEB-INF/conf/news/search-configuration.xml b/content-webapp/src/main/webapp/WEB-INF/conf/news/search-configuration.xml index fec6756ac..df7260a4f 100644 --- a/content-webapp/src/main/webapp/WEB-INF/conf/news/search-configuration.xml +++ b/content-webapp/src/main/webapp/WEB-INF/conf/news/search-configuration.xml @@ -23,21 +23,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"> - - - io.meeds.news.search.NewsSearchConnector - - - query.file.path - ${exo.news.es.query.path:jar:/news-search-query.json} - - - constructor.params - - - - - org.exoplatform.social.core.search.SearchService @@ -55,7 +40,7 @@ news - + ${exo.search.activity.enabled:true} diff --git a/content-webapp/src/main/webapp/WEB-INF/gatein-resources.xml b/content-webapp/src/main/webapp/WEB-INF/gatein-resources.xml index c531efd4e..a6103bc05 100644 --- a/content-webapp/src/main/webapp/WEB-INF/gatein-resources.xml +++ b/content-webapp/src/main/webapp/WEB-INF/gatein-resources.xml @@ -49,6 +49,7 @@ NewsComposer Enterprise /skin/css/newsComposer.css + Notes @@ -88,6 +89,9 @@ false /js/newsActivityComposer.bundle.js + + NotesRichEditor + vue @@ -187,6 +191,9 @@ newsDetails + + NewsActivityStreamExtensions + @@ -313,6 +320,9 @@ suggester + + contentTranslationMenu + @@ -548,4 +558,28 @@ extensionRegistry + + + contentTranslationMenu + + + vue + + + vuetify + + + eXoVueI18n + + + extensionRegistry + + + jquery + $ + + diff --git a/content-webapp/src/main/webapp/WEB-INF/jsp/newsListView.jsp b/content-webapp/src/main/webapp/WEB-INF/jsp/newsListView.jsp index 281c9b3f3..db0106607 100644 --- a/content-webapp/src/main/webapp/WEB-INF/jsp/newsListView.jsp +++ b/content-webapp/src/main/webapp/WEB-INF/jsp/newsListView.jsp @@ -1,9 +1,10 @@ -<%@page import="org.exoplatform.container.ExoContainerContext"%> <%@page import="org.exoplatform.services.security.ConversationState"%> <%@page import="org.exoplatform.services.security.Identity"%> <%@ page import="io.meeds.news.utils.NewsUtils" %> <%@ page import="org.exoplatform.web.PortalHttpServletResponseWrapper" %> <%@ page import="org.exoplatform.portal.application.PortalRequestContext" %> +<%@ page import="org.exoplatform.commons.api.settings.ExoFeatureService" %> +<%@ page import="org.exoplatform.commons.utils.CommonsUtils" %> <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> @@ -11,6 +12,13 @@
<% + String applicationId; + Object applicationIdParam = request.getAttribute("applicationId"); + if (applicationIdParam instanceof String[]) { + applicationId = ((String[]) applicationIdParam)[0]; + } else { + applicationId = (String) applicationIdParam; + } int generatedId = (int) (Math.random() * 1000000l); String appId = "news-list-view-" + generatedId; String[] viewTemplateParams = (String[]) request.getAttribute("viewTemplate"); @@ -29,7 +37,7 @@ String[] seeAllUrlParams = (String[]) request.getAttribute("seeAllUrl"); String viewTemplate = viewTemplateParams == null || viewTemplateParams.length == 0 ? "": viewTemplateParams[0]; String newsTarget = newsTargetParams == null || newsTargetParams.length == 0 ? "": newsTargetParams[0]; - String header = headerParams == null || headerParams.length == 0 ? "": headerParams[0]; + String headerTitle = headerParams == null || headerParams.length == 0 ? "": headerParams[0]; String limit = limitParams == null || limitParams.length == 0 ? "4": limitParams[0]; String showHeader = showHeaderParams == null || showHeaderParams.length == 0 ? "true": showHeaderParams[0]; String showSeeAll = showSeeAllParams == null || showSeeAllParams.length == 0 ? "true": showSeeAllParams[0]; @@ -50,7 +58,7 @@ PortalRequestContext rcontext = PortalRequestContext.getCurrentInstance(); PortalHttpServletResponseWrapper responseWrapper = ( PortalHttpServletResponseWrapper ) rcontext.getResponse(); - String newsListUrl = "/portal/rest/v1/news/byTarget/" + newsTarget + "?offset=0&limit=" + limit + "&returnSize=true"; + String newsListUrl = "/content/rest/contents/byTarget/" + newsTarget + "?offset=0&limit=" + limit + "&returnSize=true"; responseWrapper.addHeader("Link", "<" + newsListUrl + ">; rel=prefetch; as=fetch; crossorigin=use-credentials", false); boolean canManageNewsPublishTargets = NewsUtils.canManageNewsPublishTargets(currentIdentity); %> @@ -58,11 +66,12 @@ diff --git a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ExoNewsActivityComposer.vue b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ExoNewsActivityComposer.vue index 700425603..7eb6e5922 100644 --- a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ExoNewsActivityComposer.vue +++ b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ExoNewsActivityComposer.vue @@ -279,6 +279,7 @@ export default { desktopToolbar: null, oembedMinWidth: 300, spaceUrl: null, + autoSaveDone: false, }; }, computed: { @@ -328,8 +329,7 @@ export default { && this.news.publicationState !== 'draft') { return true; } - - return false; + return !this.autoSaveDone; }, draftWarningText() { return this.$t('news.drafts.warning.youAreEditingDraft').replace('{0}', this.news.draftUpdaterDisplayName).replace('{1}', this.formatDate(this.news.draftUpdateDate.time)); @@ -341,22 +341,26 @@ export default { watch: { 'news.title': function() { if (this.news.title !== this.originalNews.title) { + this.autoSaveDone = false; this.autoSave(); } }, 'news.summary': function() { if (this.news.summary !== this.originalNews.summary) { + this.autoSaveDone = false; this.autoSave(); } }, 'news.body': function() { if (this.getContent(this.news.body) !== this.getContent(this.originalNews.body)) { + this.autoSaveDone = false; this.autoSave(); } }, 'news.illustration': function() { if (this.initIllustrationDone) { this.illustrationChanged = true; + this.autoSaveDone = false; this.autoSave(); } } @@ -601,6 +605,7 @@ export default { this.saveNewsDraft(); } }); + this.autoSaveDone = true; }, this.autoSaveDelay); }, newsActions() { diff --git a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/initComponents.js b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/initComponents.js index cacb0da8e..4d5ee61bd 100644 --- a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/initComponents.js +++ b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/initComponents.js @@ -20,12 +20,15 @@ import ExoNewsActivityComposer from './components/ExoNewsActivityComposer.vue'; import ExoNewsFileDrop from './components/ExoNewsFileDrop.vue'; +import ContentRichEditor from './components/ContentRichEditor.vue'; + import * as newsServices from '../services/newsServices.js'; import * as newsConstants from '../services/newsConstants.js'; const components = { 'exo-news-activity-composer': ExoNewsActivityComposer, 'exo-news-file-drop': ExoNewsFileDrop, + 'content-rich-editor': ContentRichEditor }; for (const key in components) { diff --git a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/main.js b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/main.js index 41852074c..6aec381eb 100644 --- a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/main.js +++ b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/main.js @@ -29,6 +29,7 @@ const lang = typeof eXo !== 'undefined' ? eXo.env.portal.language : 'en'; // should expose the locale resources as REST API const urls = [ + `/content/i18n/locale.portlet.notes.notesPortlet?lang=${lang}`, `/content/i18n/locale.portlet.news.News?lang=${lang}`, ]; @@ -49,20 +50,26 @@ export function init(maxToUpload, maxFileSize) { // init Vue app when locale resources are ready newsActivityComposerApp = new Vue({ el: '#NewsComposerApp', + computed: { + }, data: function() { return { - newsId: getURLQueryParam('newsId'), + articleId: getURLQueryParam('newsId'), spaceId: getURLQueryParam('spaceId'), activityId: getURLQueryParam('activityId'), - newsType: getURLQueryParam('type'), + articleType: getURLQueryParam('type'), + selectedLanguage: getURLQueryParam('lang'), maxToUpload: maxToUpload, maxFileSize: maxFileSize }; }, - template: '', + template: '', i18n, vuetify }); + }).finally(() => { + Vue.prototype.$utils.includeExtensions('WYSIWYGPluginsExtensions'); + Vue.prototype.$utils.includeExtensions('AutomaticTranslationNotesEditorExtension'); }); } @@ -77,4 +84,4 @@ function getURLQueryParam(paramName) { if (urlParams.has(paramName)) { return urlParams.get(paramName); } -} \ No newline at end of file +} diff --git a/content-webapp/src/main/webapp/vue-app/news-details-app/components/ExoNewsDetailsApp.vue b/content-webapp/src/main/webapp/vue-app/news-details-app/components/ExoNewsDetailsApp.vue index 1056c43ce..4d9f14196 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details-app/components/ExoNewsDetailsApp.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details-app/components/ExoNewsDetailsApp.vue @@ -5,15 +5,19 @@

{{ $t('news.details.restricted') }}

+ :show-delete-button="showDeleteButton" + :translations="translations" + :selected-translation="selectedTranslation" + /> @@ -36,16 +40,55 @@ export default { showEditButton: false, showPublishButton: false, showDeleteButton: false, + selectedTranslation: {value: eXo.env.portal.language}, + translations: [], + languages: [], + originalVersion: null, + previousSelectedTranslation: null }), created() { - this.$newsServices.getNewsById(this.newsId, false, this.newsType) - .then(news => { - if (news !== null && news !== UNAUTHORIZED_CODE) { - this.news = news; + this.getAvailableLanguages(); + const url = new URL(window.location.href); + const params = new URLSearchParams(url.search); + if (params.has('lang')) { + this.selectedTranslation.value = params.get('lang'); + } + this.originalVersion = { value: '', text: this.$root.$t('article.label.translation.originalVersion') }; + this.getArticleVersionWithLang(this.newsId, this.selectedTranslation.value); + this.fetchTranslation(this.newsId); + this.$root.$on('change-article-translation', (translation) => { + this.previousSelectedTranslation = this.selectedTranslation.value; + this.changeTranslation(translation); + }); + this.$root.$on('update-content-selected-translation', (translation) => { + this.updateSelectedTranslation(translation); + this.previousSelectedTranslation = translation.value; + }); + }, + methods: { + getAvailableLanguages() { + return this.$notesService.getAvailableLanguages().then(data => { + this.languages = data || []; + }); + }, + getArticleVersionWithLang(id, lang) { + if (this.previousSelectedTranslation === 'autoTranslation') { + // reset the news model after the automatic translation + this.news = null; + } + return this.$newsServices.getNewsById(id, false, 'article', lang).then((resp) => { + if (resp !== null && resp !== UNAUTHORIZED_CODE) { + this.news = resp; this.showEditButton = this.news.canEdit; this.showPublishButton = this.news.canPublish; this.showDeleteButton = this.news.canDelete; - if (!this.news.spaceMember) { + if (this.news.lang) { + this.addParamToUrl('lang', this.news.lang); + } else { + this.removeParamFromUrl('lang'); + this.selectedTranslation = this.originalVersion; + } + if (this.news.spaceMember) { this.$root.$emit('restricted-space', this.news.spaceDisplayName, this.news.hiddenSpace); const message = this.news.hiddenSpace ? this.$t('news.activity.notAuthorizedUserForSpaceHidden'): this.$t('news.activity.notAuthorizedUser').replace('{0}', this.news.spaceDisplayName); this.$root.$emit('alert-message', message, 'warning'); @@ -54,6 +97,34 @@ export default { this.notFound = true; } }); - }, + }, + addParamToUrl(paramName, paramValue) { + const url = new URL(window.location.href); + url.searchParams.set(paramName, paramValue); + history.pushState({}, null, url.toString()); + }, + removeParamFromUrl(paramName) { + const url = new URL(window.location.href); + url.searchParams.delete(paramName); + history.pushState({}, null, url.toString()); + }, + changeTranslation(translation) { + this.selectedTranslation = translation; + this.getArticleVersionWithLang(this.news.id, this.selectedTranslation.value); + }, + fetchTranslation(articleId) { + this.$newsServices.getArticleLanguages(articleId, false).then((resp) => { + this.translations = resp || []; + if (this.translations.length>0) { + this.translations = this.languages.filter(item1 => this.translations.some(item2 => item2 === item1.value)); + this.translations.sort((a, b) => a.text.localeCompare(b.text)); + } + this.translations.unshift(this.originalVersion); + }); + }, + updateSelectedTranslation(translation) { + this.selectedTranslation = translation; + }, + } }; - \ No newline at end of file + diff --git a/content-webapp/src/main/webapp/vue-app/news-details-app/main.js b/content-webapp/src/main/webapp/vue-app/news-details-app/main.js index 923da278d..55daac92a 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details-app/main.js +++ b/content-webapp/src/main/webapp/vue-app/news-details-app/main.js @@ -62,6 +62,8 @@ export function init() { i18n, vuetify }).$mount(appElement); + }).finally(() => { + Vue.prototype.$utils.includeExtensions('AutomaticTranslationNewsActivityStreamExtension'); }); } export function destroy() { diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetails.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetails.vue index 3f00eb65e..8269f9107 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetails.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetails.vue @@ -42,7 +42,9 @@ :show-publish-button="showPublishButton" /> + :news="news" + :translations="translations" + :selected-translation="selectedTranslation" /> { + return []; + } + }, + selectedTranslation: { + type: Object, + default: () => { + return {}; + } + } }, data() { return { @@ -173,7 +187,10 @@ export default { }, editLink() { const newsType = this.activityId && this.activityId !== '' ? this.$newsConstants.newsObjectType.LATEST_DRAFT : this.newsType; - const editUrl = `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/editor?spaceId=${this.spaceId}&newsId=${this.newsId}&activityId=${this.activityId}&type=${newsType}`; + let editUrl = `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/editor?spaceId=${this.spaceId}&newsId=${this.newsId}&activityId=${this.activityId}&spaceName=${this.currentSpace.prettyName}&type=${newsType}`; + if (this.news.lang) { + editUrl = `${editUrl}&lang=${this.news.lang}`; + } window.open(editUrl, '_target'); }, deleteConfirmDialog() { @@ -245,7 +262,7 @@ export default { } }, getNewsById(newsId) { - this.$newsServices.getNewsById(newsId, false, this.processedNewsType) + this.$newsServices.getNewsById(newsId, false, this.processedNewsType, this.selectedTranslation.value) .then(news => { this.spaceId = news.spaceId; this.getSpaceById(this.spaceId); diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsActivity.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsActivity.vue index 79a91d9dd..238fb4c0a 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsActivity.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsActivity.vue @@ -22,14 +22,18 @@ + :show-delete-button="showDeleteButton" + :translations="translations" + :selected-translation="selectedTranslation" /> \ No newline at end of file diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsBody.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsBody.vue index 5160a4bad..c00e6c9cf 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsBody.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsBody.vue @@ -24,9 +24,9 @@
@@ -69,12 +69,12 @@ :format="dateFormat" class="newsInformationValue newsPostedDate news-details-information ms-1" /> - - - {{ postedDate }} +
+ +
@@ -155,6 +155,18 @@ export default { required: false, default: null }, + translations: { + type: Array, + default: () => { + return []; + } + }, + selectedTranslation: { + type: Object, + default: () => { + return {}; + } + } }, data: () => ({ dateFormat: { @@ -166,19 +178,14 @@ export default { hour: '2-digit', minute: '2-digit', }, - translateExtension: null, newsTitleContent: null, newsSummaryContent: null, newsBodyContent: null }), created() { this.setNewsTitle(this.news?.title); - this.setNewsSummary(this.news?.summary); + this.setNewsSummary(this.news?.properties?.summary); this.setNewsContent(this.news?.body); - this.refreshTranslationExtensions(); - document.addEventListener('automatic-translation-extensions-updated', () => { - this.refreshTranslationExtensions(); - }); this.$root.$on('update-news-title', this.setNewsTitle); this.$root.$on('update-news-summary', this.setNewsSummary); this.$root.$on('update-news-body', this.setNewsContent); @@ -190,13 +197,16 @@ export default { }; }, illustrationURL() { - return this.news && this.news.illustrationURL; + return this?.news.illustrationURL; + }, + featuredImageAltText() { + return this.news?.properties?.featuredImage?.altText || this.newsTitle; }, newsTitle() { return this.news && this.newsTitleContent; }, showUpdateInfo() { - return this.news && this.news.updateDate && this.news.updater !=='__system' && this.news.updateDate !== 'null' && this.news.publicationDate && this.news.publicationDate !== 'null' && this.news.updateDate.time > this.news.publicationDate.time; + return this.news && this.news.updateDate && this.news.updater !=='__system' && this.news.updateDate !== 'null' && this.news.publicationDate && this.news.publicationDate !== 'null' && new Date(this.news.updateDate).getTime() > new Date(this.news.publicationDate).getTime(); }, authorProfile() { return this.news && this.news.author; @@ -217,10 +227,10 @@ export default { return this.news && this.news.updater; }, publicationDate() { - return this.news && this.news.publicationDate && this.news.publicationDate.time && new Date(this.news.publicationDate.time); + return this.news && this.news.publicationDate && new Date(this.news.publicationDate); }, updatedDate() { - return this.news && this.news.updateDate && this.news.updateDate.time && new Date(this.news.updateDate.time); + return this.news && this.news.updateDate && new Date(this.news.updateDate); }, newsSummary() { return this.news && this.newsSummaryContent; @@ -232,7 +242,7 @@ export default { return this.news && this.news.postedDate; }, summary() { - return this.news && this.news.summary; + return this.news?.properties?.summary; }, attachmentsIds() { return this.news?.attachmentsIds; @@ -257,9 +267,6 @@ export default { setNewsContent(translation) { this.newsBodyContent = translation; }, - refreshTranslationExtensions() { - this.translateExtension = extensionRegistry.loadExtensions('news', 'translation-menu-extension')[0]; - } } }; diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsTime.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsTime.vue index b5b6c7df4..8c2c5e11d 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsTime.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsDetailsTime.vue @@ -73,10 +73,10 @@ export default { }), computed: { publicationDate() { - return this.news && this.news.publicationDate && this.news.publicationDate.time && new Date(this.news.publicationDate.time); + return this.news && this.news.publicationDate && this.news.publicationDate && new Date(this.news.publicationDate); }, updatedDate() { - return this.news && this.news.updateDate && this.news.updateDate.time && new Date(this.news.updateDate.time); + return this.news && this.news.updateDate && new Date(this.news.updateDate); }, postedDate() { return this.news && this.news.postedDate; diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsFavoriteAction.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsFavoriteAction.vue index 6b52c7465..d345aff73 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsFavoriteAction.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/ExoNewsFavoriteAction.vue @@ -64,7 +64,7 @@ export default { }), computed: { newsId() { - return this.news?.id; + return this.news.lang && `${this.news.id}-${this.news.lang}` || this.news.id; }, spaceId() { return this.news?.spaceId; diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsBodyMobile.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsBodyMobile.vue index 68274237e..00d6342a6 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsBodyMobile.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsBodyMobile.vue @@ -112,7 +112,7 @@ export default { return this.news && this.news.publicationState; }, newsSummary() { - return this.news?.summary; + return this.news?.properties?.summary; }, newsBody() { return this.news?.body; diff --git a/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue b/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue index 3f1fca2c6..b0f84e515 100644 --- a/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue +++ b/content-webapp/src/main/webapp/vue-app/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue @@ -23,6 +23,7 @@ absolute flat :src="illustrationUrl" + :alt="featuredImageAltText" prominent class="news-details-toolbar application-border-radius-top"> @@ -88,14 +89,17 @@ export default { backURL() { return this.news && this.news.spaceMember ? this.news.spaceUrl : `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}`; }, + featuredImageAltText() { + return this.news?.properties?.featuredImage?.altText; + }, illustrationUrl() { - return this.news && this.news.illustrationURL ? this.news.illustrationURL.concat('&size=315x128').toString() : '/content/images/news.png'; + return this?.news.illustrationURL ? this.news.illustrationURL.concat('&size=315x128').toString() : '/content/images/news.png'; }, publicationState() { - return this.news && this.news.publicationState; + return this.news?.publicationState; }, newsPublished() { - return this.news && this.news.published; + return this.news?.published; } }, }; diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivitySwitchToNews.vue b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivitySwitchToNews.vue index 7fe53f6c7..f373c5a10 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivitySwitchToNews.vue +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivitySwitchToNews.vue @@ -68,8 +68,9 @@ export default { link() { const baseUrl = `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/editor`; if (eXo.env.portal.spaceId) { - return `${baseUrl}?spaceId=${eXo.env.portal.spaceId}&type=draft`; - } else { + return `${baseUrl}?spaceId=${eXo.env.portal.spaceId}&spaceName=${eXo.env.portal.spaceName}&type=draft`; + } + else { return baseUrl; } }, diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsComposer.vue b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsComposer.vue index 8566ba9ce..cd8ab89e1 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsComposer.vue +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsComposer.vue @@ -92,7 +92,7 @@ export default { if (!this.disableComposerButton) { let url = `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/editor`; if (eXo.env.portal.spaceId) { - url += `?spaceId=${eXo.env.portal.spaceId}&type=draft`; + url += `?spaceId=${eXo.env.portal.spaceId}&spaceName=${eXo.env.portal.spaceName}&type=draft`; } localStorage.setItem('exo-activity-composer-message', this.message || ''); window.open(url, '_blank'); diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsToolbarAction.vue b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsToolbarAction.vue index b2ba196cf..7a3d565a9 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsToolbarAction.vue +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/components/activity/ActivityWriteNewsToolbarAction.vue @@ -63,7 +63,7 @@ export default { switchToNews() { let url = `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/editor`; if (eXo.env.portal.spaceId) { - url += `?spaceId=${eXo.env.portal.spaceId}&type=draft`; + url += `?spaceId=${eXo.env.portal.spaceId}&spaceName=${eXo.env.portal.spaceName}&type=draft`; } window.open(url, '_blank'); }, diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/extensions.js b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/extensions.js index eb3a68d20..421c8a73e 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/extensions.js +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/activity-stream-extensions/extensions.js @@ -41,10 +41,19 @@ const newsActivityTypeExtensionOptions = { if (activity.parentActivity) { activityId = activity.parentActivity.id; } + if (activity.newsTranslations) { + const newsTranslationsMap = activity.newsTranslations; + const newsTranslationKey = `news_${lang}`; + activity.news = newsTranslationsMap[newsTranslationKey] || activity.news; + } if (!activity.news || isActivityDetail) { - return Vue.prototype.$newsServices.getNewsByActivityId(activityId) + return Vue.prototype.$newsServices.getNewsByActivityId(activityId, lang) .then(news => activity.news = news); } + // metadata object id for translation is a concatenation of the news id and the lang + if (activity.news.lang) { + activity.templateParams.metadataObjectId = `${activity.news.id}-${activity.news.lang}`; + } }, canEdit: () => false, canShare: () => true, @@ -70,8 +79,8 @@ const newsActivityTypeExtensionOptions = { getSourceLink: (activity) => `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/activity?id=${!activity.parentActivity ? activity.id : activity.parentActivity.id}`, getSummary: (activity) => { const news = activity?.news; - if (news?.summary) { - return news.summary; + if (news?.properties?.summary) { + return news?.properties?.summary; } else if (news?.body) { return Vue.prototype.$utils.htmlToText(news.body); } diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue b/content-webapp/src/main/webapp/vue-app/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue index 1274cb333..b7661f48c 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue @@ -25,8 +25,8 @@ tile size="25"> ({ + news: null, activityTitle: '', url: '', isFavorite: true, newsObjectType: 'article', }), + computed: { + featuredImageAltText() { + return this.news?.properties?.featuredImage?.altText || this.activityTitle; + } + }, created() { - this.$newsServices.getNewsById(this.id, false, this.newsObjectType) + let newsId = this.id; + let lang = null; + if (this.id.includes('-')) { + const parts = this.id.split('-'); + newsId = parts[0]; + lang = parts[1]; + } + this.$newsServices.getNewsById(newsId, false, this.newsObjectType, lang) .then(news => { this.activityTitle = news.title; this.url = news.url; diff --git a/content-webapp/src/main/webapp/vue-app/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue b/content-webapp/src/main/webapp/vue-app/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue index 0dca816d6..8552c997d 100644 --- a/content-webapp/src/main/webapp/vue-app/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue +++ b/content-webapp/src/main/webapp/vue-app/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue @@ -45,7 +45,7 @@ export default { computed: { url() { return this.notification?.space?.isMember ? this.notification?.parameters?.ACTIVITY_LINK - : `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news/detail?newsId=${this.notification?.parameters?.NEWS_ID}&type=article`; + : `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}/news-detail?newsId=${this.notification?.parameters?.NEWS_ID}&type=article`; }, eventTitle() { return this.notification?.parameters?.CONTENT_TITLE; diff --git a/content-webapp/src/main/webapp/vue-app/news-list-view/components/NewsListView.vue b/content-webapp/src/main/webapp/vue-app/news-list-view/components/NewsListView.vue index 8b2e44b6a..4a946f5e9 100644 --- a/content-webapp/src/main/webapp/vue-app/news-list-view/components/NewsListView.vue +++ b/content-webapp/src/main/webapp/vue-app/news-list-view/components/NewsListView.vue @@ -35,7 +35,11 @@ :params="viewComponentParams" /> - + @@ -44,6 +48,14 @@ \ No newline at end of file + diff --git a/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettings.vue b/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettings.vue index 859794eac..0e9ab37a8 100644 --- a/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettings.vue +++ b/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettings.vue @@ -24,9 +24,9 @@ {{ newsHeader }} + :title="headerTitle">{{ headerTitle }}
-
+
({ - newsHeader: '', seeAllUrl: '', showHeader: false, showSeeAll: false, canPublishNews: false, + language: eXo?.env?.portal?.language, }), computed: { + headerTitle() { + return this.$root.headerTitle || ''; + }, showSettingsContainer(){ return this.showHeader || this.showSeeAll || this.canPublishNews ; }, @@ -91,12 +94,10 @@ export default { this.canPublishNews = canPublishNews; }); this.$root.$on('saved-news-settings', (newsTarget, selectedOptions) => { - this.newsHeader = selectedOptions.header; this.seeAllUrl = selectedOptions.seeAllUrl; this.showSeeAll = selectedOptions.showSeeAll; this.showHeader = selectedOptions.showHeader; }); - this.newsHeader = this.$root.header; this.seeAllUrl = this.$root.seeAllUrl; this.showSeeAll = this.$root.showSeeAll; this.showHeader = this.$root.showHeader; @@ -111,4 +112,4 @@ export default { } }, }; - \ No newline at end of file + diff --git a/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettingsDrawer.vue b/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettingsDrawer.vue index f4aec9d71..061f26b05 100644 --- a/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettingsDrawer.vue +++ b/content-webapp/src/main/webapp/vue-app/news-list-view/components/settings/NewsSettingsDrawer.vue @@ -68,17 +68,18 @@
- + class="flex" + no-expand-icon + back-icon + autofocus + required />
- {{ $t('news.list.settings.drawer.advancedSettings') }} + + {{ $t('news.list.settings.drawer.advancedSettings') }} +