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 cb1327b75..f1a96104f 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 @@ -33,6 +33,8 @@ import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; + public class ActivityNewsProcessor extends BaseActivityProcessorPlugin { private static final Log LOG = ExoLogger.getLogger(ActivityNewsProcessor.class); @@ -58,7 +60,7 @@ public void processActivity(ExoSocialActivity activity) { News news = (News) activity.getLinkedProcessedEntities().get("news"); if (news == null) { try { - news = newsService.getNewsById(activity.getTemplateParams().get("newsId"), false); + news = newsService.getNewsArticleById(activity.getTemplateParams().get("newsId")); RealtimeListAccess listAccess = activityManager.getCommentsWithListAccess(activity, true); news.setCommentsCount(listAccess.getSize()); 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 63238b440..af2666dba 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 @@ -35,6 +35,8 @@ import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; + /** * A triggered listener class about activity lifecyles. This class is used to * propagate sharing activity in News elements to let targeted space members to @@ -76,8 +78,8 @@ public void shareActivity(ActivityLifeCycleEvent event) { String newsId = originalActivity.getTemplateParams().get(NEWS_ID); org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); try { - News news = newsService.getNewsById(newsId, currentIdentity, false); - if (news != null) { + News news = newsService.getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase()); + if (news != null && !news.isDeleted()) { Identity posterIdentity = getIdentity(sharedActivity); Space space = getSpace(sharedActivity); newsService.shareNews(news, space, posterIdentity, sharedActivity.getId()); 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 c7d9c8c3f..2d7c19dbd 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 @@ -139,4 +139,6 @@ public class News { private List targets; private boolean favorite; + + private boolean deleted; } diff --git a/content-service/src/main/java/io/meeds/news/model/NewsLatestDraftObject.java b/content-service/src/main/java/io/meeds/news/model/NewsLatestDraftObject.java new file mode 100644 index 000000000..46e4c9111 --- /dev/null +++ b/content-service/src/main/java/io/meeds/news/model/NewsLatestDraftObject.java @@ -0,0 +1,32 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.news.model; + +import org.exoplatform.social.metadata.model.MetadataObject; + +public class NewsLatestDraftObject extends MetadataObject { + + public NewsLatestDraftObject() { + } + + public NewsLatestDraftObject(String objectType, String objectId, String parentObjectId, long spaceId) { + super(objectType, objectId, parentObjectId, spaceId); + } +} diff --git a/content-service/src/main/java/io/meeds/news/model/NewsPageObject.java b/content-service/src/main/java/io/meeds/news/model/NewsPageObject.java new file mode 100644 index 000000000..25628acc0 --- /dev/null +++ b/content-service/src/main/java/io/meeds/news/model/NewsPageObject.java @@ -0,0 +1,32 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.news.model; + +import org.exoplatform.social.metadata.model.MetadataObject; + +public class NewsPageObject extends MetadataObject { + + public NewsPageObject() { + } + + public NewsPageObject(String objectType, String objectId, String parentObjectId, long spaceId) { + super(objectType, objectId, parentObjectId, spaceId); + } +} diff --git a/content-service/src/main/java/io/meeds/news/model/NewsPageVersionObject.java b/content-service/src/main/java/io/meeds/news/model/NewsPageVersionObject.java new file mode 100644 index 000000000..8214913e9 --- /dev/null +++ b/content-service/src/main/java/io/meeds/news/model/NewsPageVersionObject.java @@ -0,0 +1,32 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2024 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.news.model; + +import org.exoplatform.social.metadata.model.MetadataObject; + +public class NewsPageVersionObject extends MetadataObject { + + public NewsPageVersionObject() { + } + + public NewsPageVersionObject(String objectType, String objectId, String parentObjectId, Long spaceId) { + super(objectType, objectId, parentObjectId, spaceId); + } +} diff --git a/content-service/src/main/java/io/meeds/news/model/NewsTargetObject.java b/content-service/src/main/java/io/meeds/news/model/NewsTargetObject.java index b6515eeed..7711effa7 100644 --- a/content-service/src/main/java/io/meeds/news/model/NewsTargetObject.java +++ b/content-service/src/main/java/io/meeds/news/model/NewsTargetObject.java @@ -26,8 +26,8 @@ public class NewsTargetObject extends MetadataObject { public NewsTargetObject() { } - public NewsTargetObject(String objectType, String objectId, String parentObjectId) { - super(objectType, objectId, parentObjectId); + public NewsTargetObject(String objectType, String objectId, String parentObjectId, Long spaceId) { + super(objectType, objectId, parentObjectId, spaceId); } } diff --git a/content-service/src/main/java/io/meeds/news/notification/provider/MailTemplateProvider.java b/content-service/src/main/java/io/meeds/news/notification/provider/MailTemplateProvider.java index 75754ca2f..3ab029007 100644 --- a/content-service/src/main/java/io/meeds/news/notification/provider/MailTemplateProvider.java +++ b/content-service/src/main/java/io/meeds/news/notification/provider/MailTemplateProvider.java @@ -98,7 +98,7 @@ protected MessageInfo makeMessage(NotificationContext ctx) { String contentSpaceName = notification.getValueOwnerParameter(NotificationConstants.CONTENT_SPACE); String authorAvatarUrl = notification.getValueOwnerParameter(NotificationConstants.AUTHOR_AVATAR_URL); String baseUrl = PropertyManager.getProperty("gatein.email.domain.url"); - String illustrationUrl = baseUrl.concat("/news/images/newsImageDefault.png"); + String illustrationUrl = baseUrl.concat("/content/images/newsImageDefault.png"); String activityLink = notification.getValueOwnerParameter(NotificationConstants.ACTIVITY_LINK); String context = notification.getValueOwnerParameter(NotificationConstants.CONTEXT); @@ -150,6 +150,7 @@ protected MessageInfo makeMessage(NotificationContext ctx) { templateContext.put("FIRST_NAME", encoder.encode(receiver.getProfile().getProperty(Profile.FIRST_NAME).toString())); // Footer templateContext.put("FOOTER_LINK", LinkProviderUtils.getRedirectUrl("notification_settings", receiver.getRemoteId())); + templateContext.put("COMPANY_LINK", LinkProviderUtils.getBaseUrl()); String subject = TemplateUtils.processSubject(templateContext); String body = TemplateUtils.processGroovy(templateContext); // binding the exception throws by processing template diff --git a/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java b/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java index 9f376c273..1b63d9455 100644 --- a/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java +++ b/content-service/src/main/java/io/meeds/news/rest/NewsRestResourcesV1.java @@ -91,6 +91,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; +import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; + @Path("v1/news") @Tag(name = "v1/news", description = "Managing news") public class NewsRestResourcesV1 implements ResourceContainer, Startable { @@ -158,7 +160,7 @@ public void stop() { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("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 'published'.") + @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"), @@ -238,6 +240,10 @@ public Response updateNews(@Parameter(description = "News id", required = true) @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) { @@ -261,11 +267,11 @@ public Response updateNews(@Parameter(description = "News id", required = true) news.setTargets(updatedNews.getTargets()); news.setAudience(updatedNews.getAudience()); - news = newsService.updateNews(news, currentIdentity.getUserId(), post, updatedNews.isPublished(), newsObjectType); + news = newsService.updateNews(news, currentIdentity.getUserId(), post, updatedNews.isPublished(), newsObjectType, newsUpdateType); return Response.ok(news).build(); } catch (IllegalAccessException e) { - LOG.warn("User '{}' is not autorized to update news", currentIdentity.getUserId(), e); + LOG.warn("User '{}' is not authorized to update news", currentIdentity.getUserId(), e); return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); } catch (Exception e) { LOG.error("Error when updating the news " + id, e); @@ -303,7 +309,7 @@ public Response deleteNews(@Context currentIdentity, false, isDraft ? NewsObjectType.DRAFT.name().toLowerCase() - : NewsObjectType.ARTICLE.name().toLowerCase()); + : ARTICLE.name().toLowerCase()); if (news == null) { return Response.status(Response.Status.NOT_FOUND).build(); } @@ -403,7 +409,7 @@ public Response getNewsById(@Context } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); News news = newsService.getNewsById(id, currentIdentity, editMode, newsObjectType); - if (news == null) { + if (news == null || news.isDeleted()) { return Response.status(Response.Status.NOT_FOUND).build(); } Locale userLocale = LocalizationFilter.getCurrentLocale(); @@ -464,7 +470,7 @@ public Response markNewsAsRead(@Context return Response.status(Response.Status.BAD_REQUEST).build(); } org.exoplatform.services.security.Identity currentIdentity = ConversationState.getCurrent().getIdentity(); - News news = newsService.getNewsById(id, currentIdentity, false); + News news = newsService.getNewsById(id, currentIdentity, false, ARTICLE.name().toLowerCase()); if (news == null) { return Response.status(Response.Status.NOT_FOUND).build(); } @@ -679,7 +685,7 @@ public Response getNewsByActivityId(@Parameter(description = "Activity id", requ @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("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 'published'.") + @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"), 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 82d020d3a..651155a63 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 @@ -101,7 +101,7 @@ private Document getDocument(String id) { LOG.debug("Index document for news id={}", id); News news = null; try { - news = newsService.getNewsById(id, false); + news = newsService.getNewsArticleById(id); } catch (Exception e) { LOG.error("Error when getting the news " + id, e); } 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 421cfffdc..91663f163 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 @@ -93,7 +93,7 @@ public interface NewsService { * @return updated News * @throws Exception */ - News updateNews(News news, String updater, Boolean post, boolean publish, String newsObjectType) throws Exception; + News updateNews(News news, String updater, Boolean post, boolean publish, String newsObjectType, String newsUpdateType) throws Exception; /** * Delete news @@ -163,6 +163,14 @@ News getNewsById(String newsId, boolean editMode, String newsObjectType) throws IllegalAccessException; + /** + * Retrives a news identified by its technical identifier + * + * @param newsId {@link News} identifier + * @return {@link News} if found else null + */ + News getNewsArticleById(String newsId); + /** * Get all news * 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 f0766bde7..c6939bbd6 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 @@ -59,13 +59,13 @@ void deleteTargetByName(String targetName, /** * Gets the {@link List} of {@link News} targets linked to a given - * {@link News} id + * {@link News} * - * @param newsId {@link News} identifier of {@link News} targets to be + * @param news {@link News} for which targets to be * retrieved - * @return {@link List} of {@link News} targets by {@link News} id + * @return {@link List} of {@link News} targets by {@link News} news object */ - List getTargetsByNewsId(String newsId); + List getTargetsByNews(News news); /** * Gets the {@link List} of {@link News} target items by a given target name. @@ -105,9 +105,9 @@ void deleteTargetByName(String targetName, * Delete the {@link List} of {@link News} targets linked to a given * {@link News} id * - * @param newsId {@link News} identifier of {@link News} to delete targets + * @param news {@link News} for which targets to be deleted */ - void deleteNewsTargets(String newsId); + void deleteNewsTargets(News news); /** * Create news target 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 8bd68590d..d9bb25fdb 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,47 +21,61 @@ 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 java.io.FileInputStream; import java.io.InputStream; +import java.text.SimpleDateFormat; 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.Set; +import java.util.regex.Matcher; +import java.util.stream.Stream; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; +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; import org.exoplatform.container.PortalContainer; -import org.exoplatform.portal.config.UserACL; import org.exoplatform.services.log.ExoLogger; 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; import org.exoplatform.social.core.manager.ActivityManager; import org.exoplatform.social.core.manager.IdentityManager; import org.exoplatform.social.core.space.model.Space; import org.exoplatform.social.core.space.spi.SpaceService; +import org.exoplatform.social.core.utils.MentionUtils; import org.exoplatform.social.metadata.MetadataService; import org.exoplatform.social.metadata.model.MetadataItem; import org.exoplatform.social.metadata.model.MetadataKey; import org.exoplatform.social.metadata.model.MetadataObject; import org.exoplatform.social.metadata.model.MetadataType; +import org.exoplatform.social.metadata.MetadataFilter; +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; +import org.exoplatform.wiki.model.PageVersion; import org.exoplatform.wiki.model.Wiki; import org.exoplatform.wiki.model.WikiType; import org.exoplatform.wiki.service.NoteService; @@ -70,42 +84,96 @@ import io.meeds.news.filter.NewsFilter; import io.meeds.news.model.News; import io.meeds.news.model.NewsDraftObject; +import io.meeds.news.model.NewsLatestDraftObject; +import io.meeds.news.model.NewsPageObject; +import io.meeds.news.model.NewsPageVersionObject; +import io.meeds.news.notification.plugin.MentionInNewsNotificationPlugin; +import io.meeds.news.notification.plugin.PostNewsNotificationPlugin; +import io.meeds.news.notification.plugin.PublishNewsNotificationPlugin; import io.meeds.news.notification.utils.NotificationConstants; +import io.meeds.news.notification.utils.NotificationUtils; import io.meeds.news.search.NewsESSearchResult; import io.meeds.news.search.NewsIndexingServiceConnector; import io.meeds.news.service.NewsService; import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; import io.meeds.news.utils.NewsUtils.NewsObjectType; +import org.exoplatform.commons.utils.HTMLSanitizer; public class NewsServiceImpl implements NewsService { - public static final String NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME = "Articles"; + public static final String NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME = "Articles"; - public static final MetadataType NEWS_METADATA_TYPE = new MetadataType(1000, "news"); + private static final String HTML_AT_SYMBOL_PATTERN = "@"; - public static final String NEWS_METADATA_NAME = "news"; + private static final String HTML_AT_SYMBOL_ESCAPED_PATTERN = "@"; - public static final String NEWS_METADATA_DRAFT_OBJECT_TYPE = "newsDraftPage"; + public static final MetadataType NEWS_METADATA_TYPE = new MetadataType(1000, "news"); - public static final String NEWS_FILE_API_NAME_SPACE = "news"; + public static final String NEWS_METADATA_NAME = "news"; - public static final String NEWS_SUMMARY = "summary"; + public static final String NEWS_METADATA_DRAFT_OBJECT_TYPE = "newsDraftPage"; - public static final String NEWS_ILLUSTRATION_ID = "illustrationId"; + public static final String NEWS_FILE_API_NAME_SPACE = "news"; - public static final String NEWS_UPLOAD_ID = "uploadId"; + 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"; + public final static String PUBLISHED = "published"; + + /** The Constant POSTED. */ + public final static String POSTED = "posted"; /** The Constant DRAFT. */ - public final static String DRAFT = "draft"; + public final static String DRAFT = "draft"; /** The Constant STAGED. */ - public final static String STAGED = "staged"; + public final static String STAGED = "staged"; + + /** The Constant AUDIENCE. */ + public static final String NEWS_AUDIENCE = "audience"; + + /** The Constant NEWS_ID. */ + public static final String NEWS_ID = "newsId"; + + /** The Constant SCHEDULE_POST_DATE. */ + public static final String SCHEDULE_POST_DATE = "schedulePostDate"; + + /** The Constant NEWS_ACTIVITIES. */ + public static final String NEWS_ACTIVITIES = "activities"; + + /** The Constant NEWS_PUBLICATION_STATE. */ + public static final String NEWS_PUBLICATION_STATE = "publicationState"; + + /** The Constant NEWS_ACTIVITY_POSTED. */ + public static final String NEWS_ACTIVITY_POSTED = "activityPosted"; - private static final Log LOG = ExoLogger.getLogger(NewsServiceImpl.class); + /** The Constant NEWS_PUBLICATION_DATE. */ + public static final String NEWS_PUBLICATION_DATE = "publicationDate"; + + /** The Constant NEWS_METADATA_PAGE_OBJECT_TYPE. */ + public static final String NEWS_METADATA_PAGE_OBJECT_TYPE = "newsPage"; + + /** The Constant NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE. */ + public static final String NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE = "newsPageVersion"; + + /** The Constant NEWS_VIEWERS. */ + public static final String NEWS_VIEWERS = "viewers"; + + /** The Constant NEWS_VIEWS. */ + public static final String NEWS_VIEWS = "viewsCount"; + + /** The Constant NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE. */ + public static final String NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE = "newsLatestDraftPage"; + + public static final MetadataKey NEWS_METADATA_KEY = + new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); + + private static final Log LOG = ExoLogger.getLogger(NewsServiceImpl.class); private final SpaceService spaceService; @@ -123,8 +191,6 @@ public class NewsServiceImpl implements NewsService { private final IdentityManager identityManager; - private final UserACL userACL; - private final ActivityManager activityManager; private final WikiService wikiService; @@ -136,7 +202,6 @@ public NewsServiceImpl(SpaceService spaceService, NewsTargetingService newsTargetingService, IndexingService indexingService, IdentityManager identityManager, - UserACL userACL, ActivityManager activityManager, WikiService wikiService, UploadService uploadService) { @@ -148,7 +213,6 @@ public NewsServiceImpl(SpaceService spaceService, this.newsTargetingService = newsTargetingService; this.indexingService = indexingService; this.identityManager = identityManager; - this.userACL = userACL; this.activityManager = activityManager; this.wikiService = wikiService; } @@ -161,10 +225,10 @@ public News createNews(News news, Identity currentIdentity) throws Exception { Space space = spaceService.getSpaceById(news.getSpaceId()); try { if (!canCreateNews(space, currentIdentity)) { - throw new IllegalArgumentException("User " + currentIdentity.getUserId() + " not authorized to create news"); + throw new IllegalAccessException("User " + currentIdentity.getUserId() + " not authorized to create news"); } News createdNews; - if (PUBLISHED.equals(news.getPublicationState()) && recreateIfDraftDeleted(news) != null) { + if (POSTED.equals(news.getPublicationState())) { createdNews = postNews(news, currentIdentity.getUserId()); } else if (news.getSchedulePostDate() != null) { createdNews = unScheduleNews(news, currentIdentity); @@ -180,14 +244,22 @@ public News createNews(News news, Identity currentIdentity) throws Exception { @Override public News postNews(News news, String poster) throws Exception { - return null; + news = createNewsArticlePage(news, poster); + postNewsActivity(news); + sendNotification(poster, news, NotificationConstants.NOTIFICATION_CONTEXT.POST_NEWS); + if (news.isPublished()) { + publishNews(news, poster); + } + NewsUtils.broadcastEvent(NewsUtils.POST_NEWS_ARTICLE, news.getId(), news);// Gamification + NewsUtils.broadcastEvent(NewsUtils.POST_NEWS, news.getAuthor(), news);// Analytics + return news; } /** * {@inheritDoc} */ @Override - public boolean canCreateNews(Space space, org.exoplatform.services.security.Identity currentIdentity) throws Exception { + public boolean canCreateNews(Space space, Identity currentIdentity) throws Exception { return space != null && (NewsUtils.canPublishNews(space.getId(), currentIdentity) || spaceService.canRedactOnSpace(space, currentIdentity)); } @@ -204,17 +276,22 @@ public News updateNews(News news, String updater, Boolean post, boolean publish) * {@inheritDoc} */ @Override - public News updateNews(News news, String updater, Boolean post, boolean publish, String newsObjectType) throws Exception { + public News updateNews(News news, String updater, Boolean post, boolean publish, String newsObjectType, String newsUpdateType) throws Exception { if (!canEditNews(news, updater)) { - throw new IllegalArgumentException("User " + updater + " is not authorized to update news"); + throw new IllegalAccessException("User " + updater + " is not authorized to update news"); } - org.exoplatform.services.security.Identity updaterIdentity = NewsUtils.getUserIdentity(updater); + Identity updaterIdentity = NewsUtils.getUserIdentity(updater); News originalNews = getNewsById(news.getId(), updaterIdentity, false, newsObjectType); - List oldTargets = newsTargetingService.getTargetsByNewsId(news.getId()); + List oldTargets = newsTargetingService.getTargetsByNews(news); boolean canPublish = NewsUtils.canPublishNews(news.getSpaceId(), updaterIdentity); Set previousMentions = NewsUtils.processMentions(originalNews.getOriginalBody(), spaceService.getSpaceById(news.getSpaceId())); + if (NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { + return updateDraftArticleForNewPage(news, updater); + } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { + return createOrUpdateDraftForExistingPage(news, updater); + } if (publish != news.isPublished() && news.isCanPublish()) { news.setPublished(publish); if (news.isPublished()) { @@ -234,16 +311,13 @@ public News updateNews(News news, String updater, Boolean post, boolean publish, sendNotification(updater, news, NotificationConstants.NOTIFICATION_CONTEXT.PUBLISH_NEWS); } } - - if (io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { - news = updateDraftArticleForNewPage(news, updater); - } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { - // TODO - } else if (ARTICLE.name().toLowerCase().equals(newsObjectType)) { - // TODO + // update the news article after executing publish and send notification methods + // They need the original news to treat the news audience and exclude space members from notification. + if (ARTICLE.name().toLowerCase().equals(newsObjectType)) { + news = updateNewsArticle(news, updaterIdentity, newsUpdateType); } - if (PUBLISHED.equals(news.getPublicationState())) { + if (POSTED.equals(news.getPublicationState())) { // Send mention notifs if (StringUtils.isNotEmpty(news.getId()) && news.getCreationDate() != null) { News newMentionedNews = news; @@ -276,15 +350,15 @@ public void deleteNews(String newsId, Identity currentIdentity, boolean isDraft) false, isDraft ? NewsObjectType.DRAFT.name().toLowerCase() : NewsObjectType.ARTICLE.name().toLowerCase()); if (!news.isCanDelete()) { - throw new IllegalArgumentException("User " + currentIdentity.getUserId() + " is not authorized to delete news"); + throw new IllegalAccessException("User " + currentIdentity.getUserId() + " is not authorized to delete news"); } if (isDraft) { - deleteDraftArticle(newsId, currentIdentity.getUserId()); + deleteDraftArticle(newsId, currentIdentity.getUserId(), true); } else { - // TODO delete article - indexingService.unindex(NewsIndexingServiceConnector.TYPE, String.valueOf(news.getId())); + deleteArticle(news, currentIdentity); MetadataObject newsMetadataObject = new MetadataObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, newsId); metadataService.deleteMetadataItemsByObject(newsMetadataObject); + indexingService.unindex(NewsIndexingServiceConnector.TYPE, String.valueOf(news.getId())); NewsUtils.broadcastEvent(NewsUtils.DELETE_NEWS, currentIdentity.getUserId(), news); } } @@ -293,8 +367,38 @@ public void deleteNews(String newsId, Identity currentIdentity, boolean isDraft) * {@inheritDoc} */ @Override - public void publishNews(News news, String publisher) throws Exception { + public void publishNews(News newsToPublish, String publisher) throws Exception { + Identity publisherIdentity = NewsUtils.getUserIdentity(publisher); + News news = getNewsArticleById(newsToPublish.getId()); + boolean displayed = !(StringUtils.equals(news.getPublicationState(), STAGED) || news.isArchived()); + // update page metadata + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); + MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject).get(0); + if (metadataItem != null) { + Map properties = metadataItem.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + } + properties.put(PUBLISHED, String.valueOf(true)); + Calendar updateCalendar = Calendar.getInstance(); + Date newsPublicationDate = updateCalendar.getTime(); + properties.put(NEWS_PUBLICATION_DATE, String.valueOf(newsPublicationDate)); + metadataItem.setProperties(properties); + String publisherId = identityManager.getOrCreateUserIdentity(publisherIdentity.getUserId()).getId(); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(publisherId)); + } + if (newsToPublish.getTargets() != null) { + newsTargetingService.deleteNewsTargets(news, publisher); + newsTargetingService.saveNewsTarget(news, displayed, newsToPublish.getTargets(), publisher); + } + NewsUtils.broadcastEvent(NewsUtils.PUBLISH_NEWS, news.getId(), news); + 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); + } } /** @@ -302,7 +406,26 @@ public void publishNews(News news, String publisher) throws Exception { */ @Override public void unpublishNews(String newsId, String publisher) throws Exception { - + News news = getNewsArticleById(newsId); + newsTargetingService.deleteNewsTargets(news, publisher); + + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); + MetadataItem newsMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject) + .stream() + .findFirst() + .orElse(null); + + if (newsMetadataItem != null) { + Map properties = newsMetadataItem.getProperties(); + if (properties != null) { + properties.put(PUBLISHED, String.valueOf(false)); + properties.remove(NEWS_PUBLICATION_DATE); + properties.remove(NEWS_AUDIENCE); + } + newsMetadataItem.setProperties(properties); + String publisherId = identityManager.getOrCreateUserIdentity(publisher).getId(); + metadataService.updateMetadataItem(newsMetadataItem, Long.parseLong(publisherId)); + } } /** @@ -334,12 +457,12 @@ public News getNewsById(String newsId, if (newsObjectType == null) { throw new IllegalArgumentException("Required argument news object type could not be null"); } - if (io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { + if (NewsObjectType.DRAFT.name().toLowerCase().equals(newsObjectType)) { news = buildDraftArticle(newsId, currentIdentity.getUserId()); } else if (LATEST_DRAFT.name().toLowerCase().equals(newsObjectType)) { - // TODO + news = buildLatestDraftArticle(newsId, currentIdentity.getUserId()); } else if (ARTICLE.name().toLowerCase().equals(newsObjectType)) { - // TODO + news = buildArticle(newsId); } } catch (Exception exception) { LOG.error("An error occurred while retrieving news with id {}", newsId, exception); @@ -356,7 +479,7 @@ public News getNewsById(String newsId, news.setCanDelete(canDeleteNews(currentIdentity, news.getAuthor(), news.getSpaceId())); news.setCanPublish(NewsUtils.canPublishNews(news.getSpaceId(), currentIdentity)); news.setCanArchive(canArchiveNews(currentIdentity, news.getAuthor())); - news.setTargets(newsTargetingService.getTargetsByNewsId(newsId)); + news.setTargets(newsTargetingService.getTargetsByNews(news)); ExoSocialActivity activity = null; try { activity = activityManager.getActivity(news.getActivityId()); @@ -372,6 +495,18 @@ public News getNewsById(String newsId, return news; } + @Override + public News getNewsArticleById(String newsId) { + News news = null; + try { + news = buildArticle(newsId); + news.setTargets(newsTargetingService.getTargetsByNews(news)); + } catch (Exception exception) { + LOG.error("An error occurred while retrieving news with id {}", newsId, exception); + } + return news; + } + /** * {@inheritDoc} */ @@ -418,8 +553,27 @@ public List getNews(NewsFilter filter, Identity currentIdentity) throws Ex * {@inheritDoc} */ @Override - public List getNewsByTargetName(NewsFilter filter, String targetName, Identity currentIdentity) throws Exception { - return new ArrayList<>(); + public List getNewsByTargetName(NewsFilter newsFilter, String targetName, Identity currentIdentity) throws Exception { + List newsTargetItems = + newsTargetingService.getNewsTargetItemsByTargetName(targetName, newsFilter.getOffset(), 0); + return newsTargetItems.stream().filter(target -> { + try { + News news = getNewsById(target.getObjectId(), currentIdentity, false, ARTICLE.name().toLowerCase()); + return news != null + && (news.getAudience().equals("") || news.getAudience().equals(NewsUtils.ALL_NEWS_AUDIENCE) || news.isSpaceMember()); + } catch (Exception e) { + return false; + } + }).map(target -> { + try { + News news = getNewsById(target.getObjectId(), currentIdentity, false, ARTICLE.name().toLowerCase()); + news.setPublishDate(new Date(target.getCreatedDate())); + news.setIllustration(null); + return news; + } catch (Exception e) { + return null; + } + }).limit(newsFilter.getLimit()).toList(); } /** @@ -435,7 +589,47 @@ public int getNewsCount(NewsFilter filter) throws Exception { */ @Override public void markAsRead(News news, String userId) throws Exception { - + try { + MetadataItem metadataItem = + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, + new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, + news.getId(), + null, + Long.parseLong(news.getSpaceId()))) + .get(0); + if (metadataItem != null) { + Map properties = metadataItem.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + } + if (properties.containsKey(NEWS_VIEWERS) && StringUtils.isNotEmpty(properties.get(NEWS_VIEWERS))) { + String newsViewers = properties.get(NEWS_VIEWERS); + String[] newsViewersArray = newsViewers.split(","); + boolean isUserInNewsViewers = Arrays.stream(newsViewersArray).anyMatch(userId::equals); + if (isUserInNewsViewers) { + return; + } + newsViewers.concat("," + userId); + properties.put(NEWS_VIEWERS, newsViewers); + if (properties.containsKey(NEWS_VIEWS) && StringUtils.isNotEmpty(properties.get(NEWS_VIEWS))) { + Long newsViewsCount = Long.parseLong(properties.get(NEWS_VIEWS)) + 1L; + properties.put(NEWS_VIEWS, String.valueOf(newsViewsCount)); + } else { + properties.put(NEWS_VIEWS, "1"); + } + } else { + properties.put(NEWS_VIEWERS, userId); + properties.put(NEWS_VIEWS, "1"); + } + metadataItem.setProperties(properties); + String userIdentityId = identityManager.getOrCreateUserIdentity(userId).getId(); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentityId)); + } + } catch (Exception exception) { + LOG.error("Failed to mark news article " + news.getId() + " as read for current user", exception); + return; + } + NewsUtils.broadcastEvent(NewsUtils.VIEW_NEWS, userId, news); } /** @@ -452,7 +646,34 @@ public List searchNews(NewsFilter filter, String lang) throws Exception { @Override public News getNewsByActivityId(String activityId, Identity currentIdentity) throws IllegalAccessException, ObjectNotFoundException { - return null; + ExoSocialActivity activity = activityManager.getActivity(activityId); + if (activity == null) { + throw new ObjectNotFoundException("Activity with id " + activityId + " wasn't found"); + } + Identity viewerIdentity = NewsUtils.getUserIdentity(currentIdentity.getUserId()); + if (!activityManager.isActivityViewable(activity, viewerIdentity)) { + throw new IllegalAccessException("User " + currentIdentity.getUserId() + " isn't allowed to access activity with id " + + activityId); + } + Map templateParams = activity.getTemplateParams(); + if (templateParams == null) { + throw new ObjectNotFoundException("Activity with id " + activityId + " isn't of type news nor a shared news"); + } + String newsId = templateParams.get(NEWS_ID); + if (StringUtils.isBlank(newsId)) { + String originalActivityId = templateParams.get("originalActivityId"); + if (StringUtils.isNotBlank(originalActivityId)) { + org.exoplatform.social.core.identity.model.Identity sharedActivityPosterIdentity = + identityManager.getIdentity(activity.getPosterId()); + if (sharedActivityPosterIdentity == null) { + throw new IllegalAccessException("Shared Activity '" + activityId + "' Poster " + activity.getPosterId() + + " isn't found"); + } + return getNewsByActivityId(originalActivityId, NewsUtils.getUserIdentity(sharedActivityPosterIdentity.getRemoteId())); + } + throw new ObjectNotFoundException("Activity with id " + activityId + " isn't of type news nor a shared news"); + } + return getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase()); } /** @@ -484,7 +705,9 @@ public List search(org.exoplatform.social.core.identity.mode */ @Override public boolean canScheduleNews(Space space, Identity currentIdentity) { - return false; + return spaceService.isManager(space, currentIdentity.getUserId()) + || spaceService.isRedactor(space, currentIdentity.getUserId()) + || NewsUtils.canPublishNews(space.getId(), currentIdentity); } /** @@ -499,13 +722,13 @@ public boolean canViewNews(News news, String authenticatedUser) { LOG.warn("Can't find space with id {} when checking access on news with id {}", spaceId, news.getId()); return false; } - if (!news.isPublished() && StringUtils.equals(news.getPublicationState(), PUBLISHED) + if (!news.isPublished() && StringUtils.equals(news.getPublicationState(), POSTED) && !(spaceService.isSuperManager(authenticatedUser) || spaceService.isMember(space, authenticatedUser) || isMemberOfsharedInSpaces(news, authenticatedUser))) { return false; } - if (news.isPublished() && news.getAudience().equals(NewsUtils.SPACE_NEWS_AUDIENCE) - && !spaceService.isMember(space, authenticatedUser)) { + if (news.isPublished() && StringUtils.equals(news.getPublicationState(), POSTED) && news.getAudience().equals(NewsUtils.SPACE_NEWS_AUDIENCE) + && !(spaceService.isMember(space, authenticatedUser) || isMemberOfsharedInSpaces(news, authenticatedUser))) { return false; } if (StringUtils.equals(news.getPublicationState(), STAGED) @@ -528,6 +751,35 @@ public void shareNews(News news, org.exoplatform.social.core.identity.model.Identity userIdentity, String sharedActivityId) throws Exception { + if (!canViewNews(news, userIdentity.getRemoteId())) { + throw new IllegalAccessException("User with id " + userIdentity.getRemoteId() + "doesn't have access to news"); + } + if (sharedActivityId != null) { + // update article metadata activities + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); + MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject).stream().findFirst().orElse(null); + if (metadataItem == null) { + throw new ObjectNotFoundException("News metadata object with id " + news.getId() + " wasn't found"); + } + + Map properties = metadataItem.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + } + if (properties.containsKey(NEWS_ACTIVITIES)) { + String newsActivities = properties.get(NEWS_ACTIVITIES); + newsActivities = newsActivities.concat(";").concat(space.getId()).concat(":").concat(sharedActivityId); + properties.put(NEWS_ACTIVITIES, newsActivities); + } else { + properties.put(NEWS_ACTIVITIES, space.getId().concat(":").concat(sharedActivityId)); + } + + metadataItem.setProperties(properties); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(userIdentity.getId())); + + NewsUtils.broadcastEvent(NewsUtils.SHARE_NEWS, userIdentity.getRemoteId(), news); + } + } /** @@ -590,15 +842,12 @@ private News createDraftArticleForNewPage(News draftArticle, String pageOwnerId, draftArticlePage.getId(), null, Long.parseLong(draftArticleSpace.getId())); - MetadataKey draftArticleMetadataKey = new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); 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, - io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name()); + setArticleIllustration(draftArticle, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, draftArticle.getUploadId()); } @@ -606,7 +855,7 @@ private News createDraftArticleForNewPage(News draftArticle, String pageOwnerId, draftArticleMetadataItemProperties.put(NEWS_SUMMARY, draftArticle.getSummary()); } metadataService.createMetadataItem(draftArticleMetaDataObject, - draftArticleMetadataKey, + NEWS_METADATA_KEY, draftArticleMetadataItemProperties, Long.parseLong(draftArticleMetadataItemCreatorIdentityId)); @@ -615,10 +864,6 @@ private News createDraftArticleForNewPage(News draftArticle, String pageOwnerId, return null; } - private News recreateIfDraftDeleted(News news) throws Exception { - return null; - } - private News updateDraftArticleForNewPage(News draftArticle, String draftArticleUpdater) throws WikiException, IllegalAccessException, FileStorageException { @@ -634,9 +879,8 @@ private News updateDraftArticleForNewPage(News draftArticle, String draftArticle draftArticlePage.getId(), null, Long.parseLong(draftArticleSpace.getId())); - MetadataKey draftArticleMetadataKey = new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); List draftArticleMetadataItems = - metadataService.getMetadataItemsByMetadataAndObject(draftArticleMetadataKey, + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, draftArticleMetaDataObject); if (draftArticleMetadataItems != null && !draftArticleMetadataItems.isEmpty()) { MetadataItem draftArticleMetadataItem = draftArticleMetadataItems.get(0); @@ -656,23 +900,20 @@ private News updateDraftArticleForNewPage(News draftArticle, String draftArticle Long draftArticleIllustrationId = saveArticleIllustration(draftArticle.getUploadId(), draftArticleIllustrationFileItem.getFileInfo().getId()); draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - setArticleIllustration(draftArticle, - draftArticleIllustrationId, - io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name()); + setArticleIllustration(draftArticle, draftArticleIllustrationId, NewsObjectType.DRAFT.name()); } } else { Long draftArticleIllustrationId = saveArticleIllustration(draftArticle.getUploadId(), null); draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(draftArticleIllustrationId)); - setArticleIllustration(draftArticle, - draftArticleIllustrationId, - io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name()); + 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) { + && 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))); @@ -693,8 +934,8 @@ private News updateDraftArticleForNewPage(News draftArticle, String draftArticle return null; } - private News buildDraftArticle(String draftArticleId, String draftArticleCreator) throws WikiException, IllegalAccessException { - DraftPage draftArticlePage = noteService.getDraftNoteById(draftArticleId, draftArticleCreator); + private News buildDraftArticle(String draftArticleId, String currentUserId) throws Exception { + DraftPage draftArticlePage = noteService.getDraftNoteById(draftArticleId, currentUserId); if (draftArticlePage != null) { News draftArticle = new News(); draftArticle.setId(draftArticlePage.getId()); @@ -702,59 +943,91 @@ private News buildDraftArticle(String draftArticleId, String draftArticleCreator draftArticle.setAuthor(draftArticlePage.getAuthor()); draftArticle.setCreationDate(draftArticlePage.getCreatedDate()); draftArticle.setUpdateDate(draftArticlePage.getUpdatedDate()); - draftArticle.setBody(draftArticlePage.getContent()); + draftArticle.setDraftUpdateDate(draftArticlePage.getUpdatedDate()); + draftArticle.setDraftUpdaterUserName(draftArticlePage.getAuthor()); + org.exoplatform.social.core.identity.model.Identity draftUpdaterIdentity = + identityManager.getOrCreateUserIdentity(currentUserId); + if (draftUpdaterIdentity != null && draftUpdaterIdentity.getProfile() != null) { + draftArticle.setDraftUpdaterDisplayName(draftUpdaterIdentity.getProfile().getFullName()); + } + processPageContent(draftArticlePage, draftArticle); draftArticle.setPublicationState(DRAFT); Space draftArticleSpace = spaceService.getSpaceByGroupId(draftArticlePage.getWikiOwner()); draftArticle.setSpaceId(draftArticleSpace.getId()); draftArticle.setSpaceAvatarUrl(draftArticleSpace.getAvatarUrl()); draftArticle.setSpaceDisplayName(draftArticleSpace.getDisplayName()); boolean hiddenSpace = draftArticleSpace.getVisibility().equals(Space.HIDDEN) - && !spaceService.isMember(draftArticleSpace, draftArticleCreator) && !spaceService.isSuperManager(draftArticleCreator); + && !spaceService.isMember(draftArticleSpace, currentUserId) && !spaceService.isSuperManager(currentUserId); draftArticle.setHiddenSpace(hiddenSpace); - boolean isSpaceMember = spaceService.isSuperManager(draftArticleCreator) - || spaceService.isMember(draftArticleSpace, draftArticleCreator); + boolean isSpaceMember = + spaceService.isSuperManager(currentUserId) || spaceService.isMember(draftArticleSpace, currentUserId); draftArticle.setSpaceMember(isSpaceMember); if (StringUtils.isNotEmpty(draftArticleSpace.getGroupId())) { String spaceGroupId = draftArticleSpace.getGroupId().split("/")[2]; String spaceUrl = "/portal/g/:spaces:" + spaceGroupId + "/" + draftArticleSpace.getPrettyName(); draftArticle.setSpaceUrl(spaceUrl); } - StringBuilder draftArticleUrl = new StringBuilder(""); - draftArticleUrl.append("/") - .append(PortalContainer.getCurrentPortalContainerName()) - .append("/") - .append(CommonsUtils.getCurrentPortalOwner()) - .append("/news/detail?newsId=") - .append(draftArticle.getId()) - .append("&type=draft"); - draftArticle.setUrl(draftArticleUrl.toString()); - NewsDraftObject draftArticleMetaDataObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, - draftArticle.getId(), - null, - Long.parseLong(draftArticleSpace.getId())); - MetadataKey draftArticleMetadataKey = new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); - List draftArticleMetadataItems = - metadataService.getMetadataItemsByMetadataAndObject(draftArticleMetadataKey, - draftArticleMetaDataObject); - if (draftArticleMetadataItems != null && !draftArticleMetadataItems.isEmpty()) { - Map draftArticleMetadataItemProperties = draftArticleMetadataItems.get(0).getProperties(); - if (draftArticleMetadataItemProperties != null && !draftArticleMetadataItemProperties.isEmpty()) { - if (draftArticleMetadataItemProperties.containsKey(NEWS_SUMMARY)) { - draftArticle.setSummary(draftArticleMetadataItemProperties.get(NEWS_SUMMARY)); - } - if (draftArticleMetadataItemProperties.containsKey(NEWS_ILLUSTRATION_ID) - && draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID) != null) { - setArticleIllustration(draftArticle, - Long.valueOf(draftArticleMetadataItemProperties.get(NEWS_ILLUSTRATION_ID)), - io.meeds.news.utils.NewsUtils.NewsObjectType.DRAFT.name().toLowerCase()); - } - } + draftArticle.setUrl(NewsUtils.buildDraftUrl(draftArticlePage)); + MetadataObject draftArticleMetaDataObject; + if (draftArticlePage.getTargetPageId() == null) { + draftArticleMetaDataObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, + draftArticle.getId(), + null, + Long.parseLong(draftArticleSpace.getId())); + } else { + draftArticleMetaDataObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, + draftArticle.getId(), + draftArticlePage.getTargetPageId(), + Long.parseLong(draftArticleSpace.getId())); } + MetadataItem draftArticleMetadataItem = metadataService + .getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, + draftArticleMetaDataObject) + .stream() + .findFirst() + .orElse(null); + buildDraftArticleProperties(draftArticle, draftArticleMetadataItem); return draftArticle; } return null; } + + private void buildDraftArticleProperties(News draftArticle, MetadataItem metadataItem) { + 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, + metadataItem.getParentObjectId(), + null, + metadataItem.getSpaceId()); + MetadataItem parentMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject) + .get(0); + Map properties = parentMetadataItem.getProperties(); + if (properties.containsKey(NEWS_ACTIVITIES) && properties.get(NEWS_ACTIVITIES) != null) { + String[] activities = properties.get(NEWS_ACTIVITIES).split(";"); + String newsActivityId = activities[0].split(":")[1]; + draftArticle.setActivityId(newsActivityId); + } + } + } + } private List buildDraftArticles(NewsFilter filter, Identity currentIdentity) throws Exception { List allowedDraftNewsSpacesIds = NewsUtils.getAllowedDraftNewsSpaces(currentIdentity) @@ -762,48 +1035,54 @@ private List buildDraftArticles(NewsFilter filter, Identity currentIdentit .map(Space::getId) .map(spaceId -> Long.parseLong(spaceId)) .toList(); - List draftArticles = - metadataService.getMetadataItemsByMetadataNameAndTypeAndObjectAndSpaceIds(NEWS_METADATA_NAME, - NEWS_METADATA_TYPE.getName(), - NEWS_METADATA_DRAFT_OBJECT_TYPE, - allowedDraftNewsSpacesIds, - filter.getOffset(), - filter.getLimit()) - .stream() - .map(draftArticle -> { - try { - return buildDraftArticle(draftArticle.getObjectId(), currentIdentity.getUserId()); - } catch (IllegalAccessException | WikiException e) { - // TODO Auto-generated catch - // block - e.printStackTrace(); - return null; - } - }) - .toList(); - return draftArticles; - } - - private void deleteDraftArticle(String draftArticleId, String draftArticleCreator) throws Exception { + MetadataFilter metadataFilter = new MetadataFilter(); + metadataFilter.setMetadataName(NEWS_METADATA_NAME); + metadataFilter.setMetadataTypeName(NEWS_METADATA_TYPE.getName()); + metadataFilter.setMetadataObjectTypes(List.of(NEWS_METADATA_DRAFT_OBJECT_TYPE, NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE)); + metadataFilter.setMetadataSpaceIds(allowedDraftNewsSpacesIds); + return metadataService.getMetadataItemsByFilter(metadataFilter, filter.getOffset(), filter.getLimit()) + .stream() + .map(draftArticle -> { + try { + News draft = buildDraftArticle(draftArticle.getObjectId(), currentIdentity.getUserId()); + if (draft != null && draftArticle.getParentObjectId() != null) { + draft.setId(draftArticle.getParentObjectId()); + } + return draft; + } catch (IllegalAccessException e) { + LOG.error("User with id " + currentIdentity.getUserId() + " not authorized to view news", e); + return null; + } catch (Exception e) { + LOG.error("Error while building new draft article", e); + return null; + } + }) + .toList(); + } + + private void deleteDraftArticle(String draftArticleId, + String draftArticleCreator, + boolean deleteIllustration) throws Exception { DraftPage draftArticlePage = noteService.getDraftNoteById(draftArticleId, draftArticleCreator); if (draftArticlePage != null) { noteService.removeDraftById(draftArticlePage.getId()); Space draftArticleSpace = spaceService.getSpaceByGroupId(draftArticlePage.getWikiOwner()); - NewsDraftObject draftArticleMetaDataObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, - draftArticlePage.getId(), - null, - Long.parseLong(draftArticleSpace.getId())); - MetadataKey draftArticleMetadataKey = new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); + MetadataObject draftArticleMetaDataObject = new MetadataObject(draftArticlePage.getTargetPageId() != null ? NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE : NEWS_METADATA_DRAFT_OBJECT_TYPE, + draftArticlePage.getId(), + draftArticlePage.getTargetPageId(), + Long.parseLong(draftArticleSpace.getId())); List draftArticleMetadataItems = - metadataService.getMetadataItemsByMetadataAndObject(draftArticleMetadataKey, + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, draftArticleMetaDataObject); if (draftArticleMetadataItems != null && !draftArticleMetadataItems.isEmpty()) { Map draftArticleMetadataItemProperties = draftArticleMetadataItems.get(0).getProperties(); - 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()); + 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); } @@ -816,7 +1095,7 @@ private boolean canEditNews(News news, String authenticatedUser) { if (space == null) { return false; } - org.exoplatform.services.security.Identity authenticatedUserIdentity = NewsUtils.getUserIdentity(authenticatedUser); + Identity authenticatedUserIdentity = NewsUtils.getUserIdentity(authenticatedUser); if (authenticatedUserIdentity == null) { LOG.warn("Can't find user with id {} when checking access on news with id {}", authenticatedUser, news.getId()); return false; @@ -873,14 +1152,12 @@ private Long saveArticleIllustration(String articleUploadId, Long oldArticleIllu } } - private boolean canDeleteNews(org.exoplatform.services.security.Identity currentIdentity, String posterId, String spaceId) { - if (currentIdentity == null) { + private boolean canDeleteNews(Identity currentIdentity, String posterId, String spaceId) { + Space space = spaceId == null ? null : spaceService.getSpaceById(spaceId); + if (space == null) { return false; } - String authenticatedUser = currentIdentity.getUserId(); - Space currentSpace = spaceService.getSpaceById(spaceId); - return authenticatedUser.equals(posterId) || userACL.isSuperUser() || spaceService.isSuperManager(authenticatedUser) - || spaceService.isManager(currentSpace, authenticatedUser); + return spaceService.canRedactOnSpace(space, currentIdentity); } private boolean isMemberOfsharedInSpaces(News news, String username) { @@ -927,10 +1204,752 @@ private String formatWikiOwnerToGroupId(String wikiOwner) { private void sendNotification(String currentUserId, News news, NotificationConstants.NOTIFICATION_CONTEXT context) throws Exception { - return; + String newsId = news.getId(); + String contentAuthor = news.getAuthor(); + String currentUser = currentUserId != null ? currentUserId : contentAuthor; + String activities = news.getActivities(); + String contentTitle = news.getTitle(); + String contentBody = news.getBody(); + String lastSpaceIdActivityId = activities.split(";")[activities.split(";").length - 1]; + String contentSpaceId = lastSpaceIdActivityId.split(":")[0]; + String contentActivityId = lastSpaceIdActivityId.split(":")[1]; + Space contentSpace = spaceService.getSpaceById(contentSpaceId); + boolean isMember = spaceService.isMember(contentSpace, contentAuthor); + if (contentSpace == null) { + throw new NullPointerException("Cannot find a space with id " + contentSpaceId + ", it may not exist"); + } + org.exoplatform.social.core.identity.model.Identity identity = identityManager.getOrCreateUserIdentity(contentAuthor); + String authorAvatarUrl = LinkProviderUtils.getUserAvatarUrl(identity.getProfile()); + String activityLink = NotificationUtils.getNotificationActivityLink(contentSpace, contentActivityId, isMember); + String contentSpaceName = contentSpace.getDisplayName(); + + // Send Notification + NotificationContext ctx = NotificationContextImpl.cloneInstance() + .append(PostNewsNotificationPlugin.CONTEXT, context) + .append(PostNewsNotificationPlugin.CONTENT_TITLE, contentTitle) + .append(PostNewsNotificationPlugin.CONTENT_AUTHOR, contentAuthor) + .append(PostNewsNotificationPlugin.CURRENT_USER, currentUser) + .append(PostNewsNotificationPlugin.CONTENT_SPACE_ID, contentSpaceId) + .append(PostNewsNotificationPlugin.CONTENT_SPACE, contentSpaceName) + .append(PostNewsNotificationPlugin.AUTHOR_AVATAR_URL, authorAvatarUrl) + .append(PostNewsNotificationPlugin.ACTIVITY_LINK, activityLink) + .append(PostNewsNotificationPlugin.NEWS_ID, newsId); + + if (context.equals(NotificationConstants.NOTIFICATION_CONTEXT.POST_NEWS)) { + ctx.getNotificationExecutor().with(ctx.makeCommand(PluginKey.key(PostNewsNotificationPlugin.ID))).execute(ctx); + Matcher matcher = MentionInNewsNotificationPlugin.MENTION_PATTERN.matcher(contentBody); + if (matcher.find()) { + sendMentionInNewsNotification(newsId, + contentAuthor, + currentUser, + contentTitle, + contentBody, + contentSpaceId, + authorAvatarUrl, + activityLink, + contentSpaceName); + } + } else if (context.equals(NotificationConstants.NOTIFICATION_CONTEXT.MENTION_IN_NEWS)) { + sendMentionInNewsNotification(newsId, + contentAuthor, + currentUser, + contentTitle, + contentBody, + contentSpaceId, + authorAvatarUrl, + activityLink, + contentSpaceName); + } else if (context.equals(NotificationConstants.NOTIFICATION_CONTEXT.PUBLISH_NEWS)) { + if (news.getAudience() != null) { + News originalNews = getNewsArticleById(news.getId()); + if (news.getAudience().equals(NewsUtils.ALL_NEWS_AUDIENCE) && originalNews.getAudience() != null + && originalNews.getAudience().equals(NewsUtils.SPACE_NEWS_AUDIENCE)) { + ctx.append(PostNewsNotificationPlugin.AUDIENCE, "excludeSpaceMembers"); // Notification + // will + // not + // be + // sent + // to + // news + // space + // members + // when + // news + // audience + // is + // changed + // from + // "space" + // to + // "all" + } else { + ctx.append(PostNewsNotificationPlugin.AUDIENCE, news.getAudience()); + } + } + ctx.getNotificationExecutor().with(ctx.makeCommand(PluginKey.key(PublishNewsNotificationPlugin.ID))).execute(ctx); + } } private void updateNewsActivity(News news, boolean post) { - // TODO + ExoSocialActivity activity = activityManager.getActivity(news.getActivityId()); + if (activity != null) { + if (post) { + activity.setUpdated(System.currentTimeMillis()); + } + activity.isHidden(!news.isActivityPosted()); + Map templateParams = activity.getTemplateParams() == null ? new HashMap<>() : activity.getTemplateParams(); + templateParams.put(NEWS_ID, news.getId()); + activity.setTemplateParams(templateParams); + activity.setMetadataObjectId(news.getId()); + activity.setMetadataObjectType(NewsUtils.NEWS_METADATA_OBJECT_TYPE); + activityManager.updateActivity(activity, true); + } + } + + private void sendMentionInNewsNotification(String newsId, + String contentAuthor, + String currentUser, + String contentTitle, + String contentBody, + String contentSpaceId, + String authorAvatarUrl, + String activityLink, + String contentSpaceName) { + Space space = spaceService.getSpaceById(contentSpaceId); + Set mentionedIds = NewsUtils.processMentions(contentBody, space); + NotificationContext mentionNotificationCtx = + NotificationContextImpl.cloneInstance() + .append(MentionInNewsNotificationPlugin.CONTEXT, + NotificationConstants.NOTIFICATION_CONTEXT.MENTION_IN_NEWS) + .append(PostNewsNotificationPlugin.CURRENT_USER, + currentUser) + .append(PostNewsNotificationPlugin.CONTENT_AUTHOR, + contentAuthor) + .append(PostNewsNotificationPlugin.CONTENT_SPACE_ID, + contentSpaceId) + .append(PostNewsNotificationPlugin.CONTENT_TITLE, + contentTitle) + .append(PostNewsNotificationPlugin.CONTENT_SPACE, + contentSpaceName) + .append(PostNewsNotificationPlugin.AUTHOR_AVATAR_URL, + authorAvatarUrl) + .append(PostNewsNotificationPlugin.ACTIVITY_LINK, + activityLink) + .append(MentionInNewsNotificationPlugin.MENTIONED_IDS, + mentionedIds) + .append(PostNewsNotificationPlugin.NEWS_ID, newsId); + mentionNotificationCtx.getNotificationExecutor() + .with(mentionNotificationCtx.makeCommand(PluginKey.key(MentionInNewsNotificationPlugin.ID))) + .execute(mentionNotificationCtx); + } + + private Identity getCurrentIdentity() { + ConversationState conversationState = ConversationState.getCurrent(); + return conversationState == null ? null : conversationState.getIdentity(); + } + + private void updateNewsActivities(String activityId, News news) throws Exception { + if (activityId != null && !StringUtils.isEmpty(news.getId())) { + Page newsPage = noteService.getNoteById(news.getId()); + if (newsPage != null) { + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, newsPage.getId(), null, Long.parseLong(news.getSpaceId())); + MetadataItem metadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject).get(0); + if (metadataItem != null) { + Map properties = metadataItem.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + } + String newsActivity = news.getSpaceId().concat(":").concat(activityId); + if (properties.containsKey(NEWS_ACTIVITIES)) { + properties.put(NEWS_ACTIVITIES, properties.get(NEWS_ACTIVITIES).concat("; ").concat(newsActivity)); + } else { + properties.put(NEWS_ACTIVITIES, newsActivity); + } + metadataItem.setProperties(properties); + String updaterId = identityManager.getOrCreateUserIdentity(news.getAuthor()).getId(); + metadataService.updateMetadataItem(metadataItem, Long.parseLong(updaterId)); + news.setActivities(properties.get(NEWS_ACTIVITIES)); + news.setActivityId(activityId); + } + } else { + throw new ObjectNotFoundException("No metadata item found for the news article page " + news.getId()); + } + } + } + + private void postNewsActivity(News news) throws Exception { + org.exoplatform.social.core.identity.model.Identity poster = identityManager.getOrCreateUserIdentity(news.getAuthor()); + + Space space = spaceService.getSpaceById(news.getSpaceId()); + org.exoplatform.social.core.identity.model.Identity spaceIdentity = + identityManager.getOrCreateSpaceIdentity(space.getPrettyName()); + + ExoSocialActivity activity = new ExoSocialActivityImpl(); + activity.setTitle(news.getTitle()); + activity.setType("news"); + activity.setUserId(poster.getId()); + activity.isHidden(!news.isActivityPosted()); + Map templateParams = new HashMap<>(); + templateParams.put(NEWS_ID, news.getId()); + activity.setTemplateParams(templateParams); + activity.setMetadataObjectId(news.getId()); + activity.setMetadataObjectType(NewsUtils.NEWS_METADATA_OBJECT_TYPE); + + activityManager.saveActivityNoReturn(spaceIdentity, activity); + updateNewsActivities(activity.getId(), news); + } + + private News createNewsArticlePage(News newsArticle, String newsArticleCreator) throws Exception { + // get the news draft article from the news model before setting the news + // article id to the news model + String draftNewsId = newsArticle.getId(); + + Identity poster = NewsUtils.getUserIdentity(newsArticleCreator); + Space space = spaceService.getSpaceById(newsArticle.getSpaceId()); + Wiki wiki = wikiService.getWikiByTypeAndOwner(WikiType.GROUP.name().toLowerCase(), space.getGroupId()); + Page newsArticlesRootNotePage = noteService.getNoteOfNoteBookByName(WikiType.GROUP.name().toLowerCase(), + space.getGroupId(), + NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME); + + if (newsArticlesRootNotePage != null) { + Page newsArticlePage = new Page(); + newsArticlePage.setTitle(newsArticle.getTitle()); + newsArticlePage.setContent(newsArticle.getBody()); + newsArticlePage.setParentPageId(newsArticlesRootNotePage.getId()); + newsArticlePage.setAuthor(newsArticle.getAuthor()); + newsArticlePage.setLang(null); + newsArticlePage = noteService.createNote(wiki, newsArticlesRootNotePage.getName(), newsArticlePage, poster); + // create the version + noteService.createVersionOfNote(newsArticlePage, poster.getUserId()); + + if (newsArticlePage != null) { + PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(newsArticlePage.getId()), null); + // set properties + newsArticle.setId(newsArticlePage.getId()); + newsArticle.setCreationDate(pageVersion.getCreatedDate()); + + NewsPageVersionObject newsArticleVersionMetaDataObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, + pageVersion.getId(), + null, + Long.parseLong(space.getId())); + String newsArticleMetadataItemCreatorIdentityId = identityManager.getOrCreateUserIdentity(newsArticleCreator).getId(); + Map newsArticleVersionMetadataItemProperties = new HashMap<>(); + + // save illustration + boolean hasIllustration = false; + Long oldIllustrationId = null; + String oldUploadId = null; + + NewsDraftObject newsDraftObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, + draftNewsId, + null, + Long.parseLong(space.getId())); + List metadataItems = + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsDraftObject); + MetadataItem metadataItem = metadataItems.isEmpty() ? null : metadataItems.get(0); + if (metadataItem != null && metadataItem.getProperties() != null && !metadataItem.getProperties().isEmpty()) { + hasIllustration = metadataItem.getProperties().containsKey(NEWS_ILLUSTRATION_ID) + && StringUtils.isNotEmpty(metadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); + if (hasIllustration) { + oldIllustrationId = Long.parseLong(metadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); + oldUploadId = metadataItem.getProperties().get(NEWS_UPLOAD_ID); + } + } + if (StringUtils.isNotEmpty(newsArticle.getUploadId())) { + if (hasIllustration && oldUploadId.equals(newsArticle.getUploadId())) { + newsArticleVersionMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(oldIllustrationId)); + newsArticleVersionMetadataItemProperties.put(NEWS_UPLOAD_ID, oldUploadId); + setArticleIllustration(newsArticle, oldIllustrationId, ARTICLE.name().toLowerCase()); + } else { + Long newIllustrationId = saveArticleIllustration(newsArticle.getUploadId(), oldIllustrationId); + if (newIllustrationId != null) { + newsArticleVersionMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(newIllustrationId)); + newsArticleVersionMetadataItemProperties.put(NEWS_UPLOAD_ID, newsArticle.getUploadId()); + setArticleIllustration(newsArticle, newIllustrationId, ARTICLE.name().toLowerCase()); + } + } + } else if (newsArticle.getUploadId() == null && hasIllustration) { + // link the illustration to the newly created version + newsArticleVersionMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(oldIllustrationId)); + newsArticleVersionMetadataItemProperties.put(NEWS_UPLOAD_ID, oldUploadId); + setArticleIllustration(newsArticle, oldIllustrationId, 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)); + + // create metadata item page + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, newsArticlePage.getId(), null, Long.parseLong(space.getId())); + Map newsPageProperties = new HashMap<>(); + if (StringUtils.isNotEmpty(newsArticle.getAudience())) { + newsPageProperties.put(NEWS_AUDIENCE, newsArticle.getAudience()); + } + if (StringUtils.isNotEmpty(newsArticle.getSchedulePostDate())) { + newsPageProperties.put(SCHEDULE_POST_DATE, newsArticle.getSchedulePostDate()); + } + if (StringUtils.isNotEmpty(newsArticle.getPublicationState())) { + newsPageProperties.put(NEWS_PUBLICATION_STATE, newsArticle.getPublicationState()); + } + newsPageProperties.put(NEWS_ACTIVITY_POSTED, String.valueOf(newsArticle.isActivityPosted())); + metadataService.createMetadataItem(newsPageObject, NEWS_METADATA_KEY, newsPageProperties, Long.parseLong(newsArticleMetadataItemCreatorIdentityId)); + + // delete the draft + deleteDraftArticle(draftNewsId, poster.getUserId(), false); + return newsArticle; + } + } + return null; + } + + private News updateNewsArticle(News news, Identity updater, String newsUpdateType) throws Exception { + Page existingPage = noteService.getNoteById(news.getId()); + if (existingPage != null) { + if (newsUpdateType.equals(CONTENT.name().toLowerCase())) { + existingPage.setTitle(news.getTitle()); + existingPage.setContent(news.getBody()); + } + existingPage.setUpdatedDate(Calendar.getInstance().getTime()); + existingPage = noteService.updateNote(existingPage); + news.setUpdateDate(existingPage.getUpdatedDate()); + news.setUpdater(existingPage.getAuthor()); + news.setUpdaterFullName(existingPage.getAuthorFullName()); + + String newsArticleUpdaterIdentityId = identityManager.getOrCreateUserIdentity(updater.getUserId()).getId(); + + // update the metadata item page + NewsPageObject newsPageObject = new NewsPageObject(NEWS_METADATA_PAGE_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); + MetadataItem existingPageMetadataItem = + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsPageObject) + .stream() + .findFirst() + .orElse(null); + if (existingPageMetadataItem != null) { + Map newsPageProperties = existingPageMetadataItem.getProperties(); + if (StringUtils.isNotEmpty(news.getAudience())) { + newsPageProperties.put(NEWS_AUDIENCE, news.getAudience()); + } + if (StringUtils.isNotEmpty(news.getSchedulePostDate())) { + newsPageProperties.put(SCHEDULE_POST_DATE, news.getSchedulePostDate()); + } + if (StringUtils.isNotEmpty(news.getPublicationState())) { + newsPageProperties.put(NEWS_PUBLICATION_STATE, news.getPublicationState()); + } + newsPageProperties.put(NEWS_ACTIVITY_POSTED, String.valueOf(news.isActivityPosted())); + existingPageMetadataItem.setProperties(newsPageProperties); + metadataService.updateMetadataItem(existingPageMetadataItem, Long.parseLong(newsArticleUpdaterIdentityId)); + } else { + throw new ObjectNotFoundException("No such news article metadata item exists with id " + news.getId()); + } + + // create the version + if (newsUpdateType.equals(CONTENT.name().toLowerCase())) { + 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())) { + DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(existingPage.getId()), updater.getUserId(), null); + deleteDraftArticle(draftPage.getId(), updater.getUserId(), news.getIllustration() == null); + } + return news; + } + return null; + } + + private News buildArticle(String newsId) throws Exception { + Page articlePage = noteService.getNoteById(newsId); + Identity userIdentity = getCurrentIdentity(); + String currentUsername = userIdentity == null ? null : userIdentity.getUserId(); + if (articlePage != null) { + Space space = spaceService.getSpaceByGroupId(articlePage.getWikiOwner()); + News news = new News(); + news.setId(articlePage.getId()); + news.setCreationDate(articlePage.getCreatedDate()); + news.setAuthor(articlePage.getAuthor()); + news.setUpdateDate(articlePage.getUpdatedDate()); + 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); + if (metadataItem != null && metadataItem.getProperties() != null && !metadataItem.getProperties().isEmpty()) { + Map properties = metadataItem.getProperties(); + if (properties.containsKey(NEWS_ACTIVITIES) && properties.get(NEWS_ACTIVITIES) != null) { + String[] activities = properties.get(NEWS_ACTIVITIES).split(";"); + StringBuilder memberSpaceActivities = new StringBuilder(); + String newsActivityId = activities[0].split(":")[1]; + news.setActivityId(newsActivityId); + StringBuilder newsUrl = new StringBuilder(); + Space newsPostedInSpace = spaceService.getSpaceById(activities[0].split(":")[0]); + if (currentUsername != null && spaceService.isMember(newsPostedInSpace, currentUsername)) { + newsUrl.append("/") + .append(PortalContainer.getCurrentPortalContainerName()) + .append("/") + .append(CommonsUtils.getCurrentPortalOwner()) + .append("/activity?id=") + .append(newsActivityId); + news.setUrl(newsUrl.toString()); + } else { + newsUrl.append("/") + .append(PortalContainer.getCurrentPortalContainerName()) + .append("/") + .append(CommonsUtils.getCurrentPortalOwner()) + .append("/news/detail?newsId=") + .append(newsId) + .append("&type=article"); + news.setUrl(newsUrl.toString()); + } + memberSpaceActivities.append(activities[0]).append(";"); + List sharedInSpacesList = new ArrayList<>(); + for (int i = 1; i < activities.length; i++) { + String sharedInSpaceId = activities[i].split(":")[0]; + sharedInSpacesList.add(sharedInSpaceId); + Space sharedInSpace = spaceService.getSpaceById(sharedInSpaceId); + String activityId = activities[i].split(":")[1]; + if (sharedInSpace != null && currentUsername != null && spaceService.isMember(sharedInSpace, currentUsername) + && activityManager.isActivityExists(activityId)) { + memberSpaceActivities.append(activities[i]).append(";"); + } + } + news.setActivities(memberSpaceActivities.toString()); + news.setSharedInSpacesList(sharedInSpacesList); + } + if (properties.containsKey(NEWS_AUDIENCE) && StringUtils.isNotEmpty(properties.get(NEWS_AUDIENCE))) { + news.setAudience(properties.get(NEWS_AUDIENCE)); + } + if (properties.containsKey(SCHEDULE_POST_DATE) && StringUtils.isNotEmpty(properties.get(SCHEDULE_POST_DATE))) { + news.setSchedulePostDate(properties.get(SCHEDULE_POST_DATE)); + } + if (properties.containsKey(NEWS_PUBLICATION_STATE) && StringUtils.isNotEmpty(properties.get(NEWS_PUBLICATION_STATE))) { + news.setPublicationState(properties.get(NEWS_PUBLICATION_STATE)); + } + if (properties.containsKey(PUBLISHED) && StringUtils.isNotEmpty(properties.get(PUBLISHED))) { + news.setPublished(Boolean.valueOf(properties.get(PUBLISHED))); + } + if (properties.containsKey(NEWS_PUBLICATION_DATE) && StringUtils.isNotEmpty(properties.get(NEWS_PUBLICATION_DATE))) { + try { + SimpleDateFormat format = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy"); + Date date = format.parse(properties.get(NEWS_PUBLICATION_DATE)); + news.setPublicationDate(date); + } catch (Exception exception) { + LOG.warn("failed to parse news published date for article with id " + news.getId()); + } + } else { + news.setPublicationDate(articlePage.getCreatedDate()); + } + if (properties.containsKey(NEWS_VIEWS) && StringUtils.isNotEmpty(properties.get(NEWS_VIEWS))) { + news.setViewsCount(Long.parseLong(properties.get(NEWS_VIEWS))); + } + if (properties.containsKey(NEWS_ACTIVITY_POSTED)) { + news.setActivityPosted(Boolean.valueOf(properties.get(NEWS_ACTIVITY_POSTED))); + } else { + news.setActivityPosted(false); + } + news.setDeleted(articlePage.isDeleted()); + } + + // 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()); + if (space != null) { + news.setSpaceId(space.getId()); + news.setSpaceAvatarUrl(space.getAvatarUrl()); + news.setSpaceDisplayName(space.getDisplayName()); + boolean hiddenSpace = space.getVisibility().equals(Space.HIDDEN) && !spaceService.isMember(space, currentUsername) + && !spaceService.isSuperManager(currentUsername); + news.setHiddenSpace(hiddenSpace); + boolean isSpaceMember = spaceService.isSuperManager(currentUsername) || spaceService.isMember(space, currentUsername); + news.setSpaceMember(isSpaceMember); + if (StringUtils.isNotEmpty(space.getGroupId())) { + String spaceGroupId = space.getGroupId().split("/")[2]; + String spaceUrl = "/portal/g/:spaces:" + spaceGroupId + "/" + space.getPrettyName(); + news.setSpaceUrl(spaceUrl); + } + } + NewsPageVersionObject newsArticleObject = new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, + pageVersion.getId(), + null, + Long.parseLong(space.getId())); + List metadataItems = + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, newsArticleObject); + if (metadataItems != null && !metadataItems.isEmpty()) { + Map properties = metadataItems.get(0).getProperties(); + if (properties != null && !properties.isEmpty()) { + if (properties.containsKey(NEWS_SUMMARY)) { + news.setSummary(properties.get(NEWS_SUMMARY)); + } + if (properties.containsKey(NEWS_ILLUSTRATION_ID) && properties.get(NEWS_ILLUSTRATION_ID) != null) { + setArticleIllustration(news, Long.valueOf(properties.get(NEWS_ILLUSTRATION_ID)), ARTICLE.name().toLowerCase()); + } + if (properties.containsKey(NEWS_UPLOAD_ID) && properties.get(NEWS_UPLOAD_ID) != null) { + news.setUploadId(properties.get(NEWS_UPLOAD_ID)); + } + } + } + return news; + } + return null; + } + + private News createOrUpdateDraftForExistingPage(News news, String updater) throws Exception { + String pageId = news.getId(); + Page existingPage = noteService.getNoteById(pageId); + if (existingPage == null) { + return null; + } + DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(pageId), updater, null); + if (draftPage == null) { + news = createDraftForExistingPage(news, updater, existingPage); + } else { + news = updateDraftForExistingPage(news, updater, existingPage, draftPage); + } + return news; + } + + private News createDraftForExistingPage(News news, String updater, Page page) throws Exception { + DraftPage draftArticlePage = new DraftPage(); + draftArticlePage.setNewPage(false); + draftArticlePage.setTargetPageId(page.getId()); + draftArticlePage.setTitle(news.getTitle()); + draftArticlePage.setContent(news.getBody()); + draftArticlePage.setParentPageId(page.getParentPageId()); + draftArticlePage.setAuthor(news.getAuthor()); + draftArticlePage.setLang(null); + + draftArticlePage = noteService.createDraftForExistPage(draftArticlePage, page, null, System.currentTimeMillis(), updater); + + news.setDraftUpdateDate(draftArticlePage.getCreatedDate()); + news.setDraftUpdater(draftArticlePage.getAuthor()); + + NewsLatestDraftObject latestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, + draftArticlePage.getId(), + page.getId(), + Long.parseLong(news.getSpaceId())); + + Map draftArticleMetadataItemProperties = new HashMap<>(); + if (StringUtils.isNotEmpty(news.getSummary())) { + draftArticleMetadataItemProperties.put(NEWS_SUMMARY, news.getSummary()); + } + draftArticleMetadataItemProperties.put(NEWS_ACTIVITY_POSTED, String.valueOf(news.isActivityPosted())); + // check if the article has an illustration to lik it to the created draft + PageVersion latestPageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(page.getId()), null); + if (latestPageVersion != null) { + // fetch the version related metadata item + MetadataItem metadataItem = + metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, + new NewsPageVersionObject(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, + latestPageVersion.getId(), + null, + Long.parseLong(news.getSpaceId()))) + .get(0); + boolean hasIllustration = false; + Long oldIllustrationId = null; + String oldIllustrationUploadId = null; + if (metadataItem != null && metadataItem.getProperties() != null && !metadataItem.getProperties().isEmpty()) { + hasIllustration = metadataItem.getProperties().containsKey(NEWS_ILLUSTRATION_ID) + && StringUtils.isNotEmpty(metadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); + if (hasIllustration) { + oldIllustrationId = Long.parseLong(metadataItem.getProperties().get(NEWS_ILLUSTRATION_ID)); + oldIllustrationUploadId = metadataItem.getProperties().get(NEWS_UPLOAD_ID); + } + } + if (StringUtils.isNotEmpty(news.getUploadId())) { + // save the illustration + Long newIllustrationId = saveArticleIllustration(news.getUploadId(), null); + if (newIllustrationId != null) { + draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(newIllustrationId)); + draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, news.getUploadId()); + setArticleIllustration(news, newIllustrationId, NewsObjectType.DRAFT.name().toLowerCase()); + } + } else if (news.getUploadId() == null && hasIllustration) { + // link the illustration to the newly created draft + draftArticleMetadataItemProperties.put(NEWS_ILLUSTRATION_ID, String.valueOf(oldIllustrationId)); + draftArticleMetadataItemProperties.put(NEWS_UPLOAD_ID, oldIllustrationUploadId); + setArticleIllustration(news, oldIllustrationId, NewsObjectType.DRAFT.name().toLowerCase()); + } + } + String draftArticleMetadataItemCreatorIdentityId = identityManager.getOrCreateUserIdentity(updater).getId(); + metadataService.createMetadataItem(latestDraftObject, NEWS_METADATA_KEY, draftArticleMetadataItemProperties, Long.parseLong(draftArticleMetadataItemCreatorIdentityId)); + return news; + } + + private News updateDraftForExistingPage(News news, String updater, Page page, DraftPage draftPage) { + try { + draftPage.setTitle(news.getTitle()); + draftPage.setContent(news.getBody()); + draftPage.setAuthor(news.getAuthor()); + draftPage.setTargetPageId(page.getId()); + draftPage.setLang(null); + + draftPage = noteService.updateDraftForExistPage(draftPage, page, null, System.currentTimeMillis(), updater); + + news.setDraftUpdateDate(draftPage.getUpdatedDate()); + news.setDraftUpdater(draftPage.getAuthor()); + + 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); + 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())); + latestDraftArticleMetadataItem.setProperties(latestDraftArticleMetadataItemProperties); + String draftArticleMetadataItemUpdaterIdentityId = identityManager.getOrCreateUserIdentity(updater).getId(); + metadataService.updateMetadataItem(latestDraftArticleMetadataItem, + Long.parseLong(draftArticleMetadataItemUpdaterIdentityId)); + } else { + throw new ObjectNotFoundException("No metadata item found for the draft " + news.getId()); + } + } catch (Exception exception) { + return null; + } + return news; + } + + private News buildLatestDraftArticle(String parentPageId, String currentIdentityId) throws Exception { + Page parentPage = noteService.getNoteById(parentPageId); + if (parentPage == null) { + return null; + } + // if the latest draft exist return it , else return the article + DraftPage latestDraft = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(parentPageId), + currentIdentityId, + null); + if (latestDraft == null) { + return buildArticle(parentPageId); + } + 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); + return draftArticle; + } + + private void processPageContent(Page page, News news) throws Exception { + String portalOwner = CommonsUtils.getCurrentPortalOwner(); + String body = page.getContent(); + String sanitizedBody = HTMLSanitizer.sanitize(body); + sanitizedBody = sanitizedBody.replaceAll(HTML_AT_SYMBOL_ESCAPED_PATTERN, HTML_AT_SYMBOL_PATTERN); + news.setBody(MentionUtils.substituteUsernames(portalOwner, sanitizedBody)); + news.setOriginalBody(sanitizedBody); + } + + private void deleteArticle(News news, Identity currentIdentity) throws Exception { + Page articlePage = noteService.getNoteById(news.getId()); + if (articlePage != null && !articlePage.isDeleted()) { + boolean hasDraft = true; + while (hasDraft) { + try { + DraftPage latestDraftPage = noteService.getLatestDraftOfPage(articlePage, currentIdentity.getUserId()); + if (latestDraftPage != null) { + deleteDraftArticle(latestDraftPage.getId(), currentIdentity.getUserId(), true); + } else { + hasDraft = false; + } + } catch (Exception exception) { + hasDraft = false; + } + } + boolean isDeleted = noteService.deleteNote(articlePage.getWikiType(), articlePage.getWikiOwner(), articlePage.getName()); + if (isDeleted) { + if (news.getActivities() != null) { + String newsActivities = news.getActivities(); + Stream.of(newsActivities.split(";")).map(activity -> activity.split(":")[1]).forEach(activityManager::deleteActivity); + } + } + } } } 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 dd91243e0..dbfd9d538 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 @@ -129,8 +129,8 @@ public void deleteTargetByName(String targetName, } @Override - public List getTargetsByNewsId(String newsId) { - NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, newsId, null); + public List getTargetsByNews(News news) { + NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); List newsTargets = metadataService.getMetadataItemsByMetadataTypeAndObject(METADATA_TYPE.getName(), newsTargetObject); return newsTargets.stream().map(MetadataItem::getMetadata).map(Metadata::getName).toList(); @@ -145,7 +145,7 @@ public void saveNewsTarget(News news, if (!NewsUtils.canPublishNews(news.getSpaceId(), currentIdentity)) { throw new IllegalAccessException("User " + currentUserId + " not authorized to save news targets"); } - NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, news.getId(), null); + NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); Identity currentSocIdentity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, currentUserId); Map properties = new LinkedHashMap<>(); properties.put(NewsUtils.DISPLAYED_STATUS, String.valueOf(displayed)); @@ -174,8 +174,8 @@ public List getNewsTargetItemsByTargetName(String targetName, long } @Override - public void deleteNewsTargets(String newsId) { - NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, newsId, null); + public void deleteNewsTargets(News news) { + NewsTargetObject newsTargetObject = new NewsTargetObject(NewsUtils.NEWS_METADATA_OBJECT_TYPE, news.getId(), null, Long.parseLong(news.getSpaceId())); metadataService.deleteMetadataItemsByMetadataTypeAndObject(METADATA_TYPE.getName(), newsTargetObject); } @@ -185,7 +185,7 @@ public void deleteNewsTargets(News news, String currentUserId) throws IllegalAcc if (!NewsUtils.canPublishNews(news.getSpaceId(), currentIdentity)) { throw new IllegalAccessException("User " + currentIdentity.getUserId() + " not authorized to delete news targets"); } - deleteNewsTargets(news.getId()); + deleteNewsTargets(news); } @Override 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 82f561edb..2946240dc 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 @@ -31,6 +31,7 @@ import org.exoplatform.commons.utils.CommonsUtils; import org.exoplatform.commons.utils.ListAccess; import org.exoplatform.container.ExoContainerContext; +import org.exoplatform.container.PortalContainer; import org.exoplatform.services.listener.ListenerService; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; @@ -43,6 +44,7 @@ import org.exoplatform.social.core.space.spi.SpaceService; import org.exoplatform.social.core.storage.api.IdentityStorage; import org.exoplatform.social.core.utils.MentionUtils; +import org.exoplatform.wiki.model.DraftPage; public class NewsUtils { @@ -94,6 +96,10 @@ public enum NewsObjectType { DRAFT, LATEST_DRAFT, ARTICLE; } + public enum NewsUpdateType { + CONTENT, SCHEDULE, POSTING_AND_PUBLISHING + } + public static void broadcastEvent(String eventName, Object source, Object data) { try { ListenerService listenerService = CommonsUtils.getService(ListenerService.class); @@ -193,4 +199,16 @@ public static org.exoplatform.services.security.Identity getUserIdentity(String } return identity; } + + public static String buildDraftUrl(DraftPage draftPage) { + StringBuilder draftArticleUrl = new StringBuilder(); + draftArticleUrl.append("/") + .append(PortalContainer.getCurrentPortalContainerName()) + .append("/") + .append(CommonsUtils.getCurrentPortalOwner()) + .append("/news/detail?newsId=") + .append(draftPage.getId()) + .append(draftPage.getTargetPageId() != null ? "&type=latest_draft" : "&type=draft"); + return draftArticleUrl.toString(); + } } 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 33cd77f98..09dd30fb7 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 @@ -19,6 +19,7 @@ */ package io.meeds.news.listener; +import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.mock; @@ -188,7 +189,7 @@ public void testNotShareWhenSharedActivityWhenNewsNotFound() throws Exception { newsActivityListener.shareActivity(event); - verify(newsService, times(1)).getNewsById(newsId, currentIdentity, false); + verify(newsService, times(1)).getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase()); verify(newsService, never()).shareNews(nullable(News.class), nullable(Space.class), nullable(Identity.class), @@ -232,11 +233,11 @@ public void testShareWhenNewsFound() throws Exception { ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); - when(newsService.getNewsById(newsId, currentIdentity, false)).thenReturn(news); + when(newsService.getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase())).thenReturn(news); newsActivityListener.shareActivity(event); - verify(newsService, times(1)).getNewsById(newsId, currentIdentity, false); + verify(newsService, times(1)).getNewsById(newsId, currentIdentity, false, ARTICLE.name().toLowerCase()); verify(newsService, times(1)).shareNews(eq(news), nullable(Space.class), nullable(Identity.class), nullable(String.class)); } } diff --git a/content-service/src/test/java/io/meeds/news/notification/provider/MailTemplateProviderTest.java b/content-service/src/test/java/io/meeds/news/notification/provider/MailTemplateProviderTest.java index 781dc7317..62edf4edf 100644 --- a/content-service/src/test/java/io/meeds/news/notification/provider/MailTemplateProviderTest.java +++ b/content-service/src/test/java/io/meeds/news/notification/provider/MailTemplateProviderTest.java @@ -151,7 +151,7 @@ public void shouldInstantiateMailTemplate() { when(encoder.encode("title")).thenReturn("title"); when(encoder.encode("space1")).thenReturn("space1"); when(encoder.encode("jean")).thenReturn("jean"); - when(encoder.encode("http://localhost:8080/news/images/newsImageDefault.png")).thenReturn("http://localhost:8080/news/images/newsImageDefault.png"); + when(encoder.encode("http://localhost:8080/content/images/newsImageDefault.png")).thenReturn("http://localhost:8080/content/images/newsImageDefault.png"); when(encoder.encode("COMMENT MY NEWS")).thenReturn("COMMENT MY NEWS"); when(encoder.encode("http://localhost:8080/portal/intranet/activity?id=39")).thenReturn("http://localhost:8080/portal/intranet/activity?id=39"); when(notification.getValueOwnerParameter("read")).thenReturn("true"); diff --git a/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java b/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java index d0f98860c..2ddc13dd8 100644 --- a/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java +++ b/content-service/src/test/java/io/meeds/news/rest/NewsRestResourcesV1Test.java @@ -19,6 +19,9 @@ */ package io.meeds.news.rest; +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 org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -363,11 +366,11 @@ public void shouldGetOKWhenUpdatingNewsAndNewsExistsAndUserIsAuthorized() throws updatedNews.setTitle("Updated Title"); updatedNews.setSummary("Updated Summary"); updatedNews.setBody("Updated Body"); - updatedNews.setPublicationState("published"); - lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null)).then(returnsFirstArg()); + updatedNews.setPublicationState(POSTED); + lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT.name().toLowerCase())).then(returnsFirstArg()); // When - Response response = newsRestResourcesV1.updateNews("1", false, null, updatedNews); + Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); @@ -376,12 +379,12 @@ public void shouldGetOKWhenUpdatingNewsAndNewsExistsAndUserIsAuthorized() throws assertEquals("Updated Title", returnedNews.getTitle()); assertEquals("Updated Summary", returnedNews.getSummary()); assertEquals("Updated Body", returnedNews.getBody()); - assertEquals("published", returnedNews.getPublicationState()); + assertEquals(POSTED, returnedNews.getPublicationState()); - when(newsRestResourcesV1.updateNews("1", false, null, updatedNews)).thenThrow(IllegalAccessException.class); + when(newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews)).thenThrow(IllegalAccessException.class); // When - response = newsRestResourcesV1.updateNews("1", false, null, updatedNews); + response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), updatedNews); // Then assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); @@ -395,7 +398,7 @@ 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, new News()); + Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), new News()); // Then assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); @@ -596,10 +599,10 @@ 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)).then(returnsFirstArg()); + lenient().when(newsService.updateNews(existingNews, JOHN, false, updatedNews.isPublished(), null, CONTENT.name().toLowerCase())).then(returnsFirstArg()); // When - Response response = newsRestResourcesV1.updateNews("id123", false, null, updatedNews); + Response response = newsRestResourcesV1.updateNews("id123", false, null, CONTENT.name().toLowerCase(), updatedNews); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); @@ -642,7 +645,7 @@ public void shouldGetOKWhenUpdatingAndUnpinNewsAndNewsExistsAndAndUserIsAuthoriz lenient().when(newsService.getNewsById("id123", currentIdentity, false, null)).thenReturn(oldnews); // When - Response response = newsRestResourcesV1.updateNews("id123", false, null, updatedNews); + Response response = newsRestResourcesV1.updateNews("id123", false, null, CONTENT.name().toLowerCase(), updatedNews); // Then assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); @@ -757,7 +760,7 @@ public void shouldGetBadRequestWhenUpdatingNewsAndUpdatedNewsIsNull() throws Exc ConversationState.setCurrent(new ConversationState(currentIdentity)); // When - Response response = newsRestResourcesV1.updateNews("1", false, null, null); + Response response = newsRestResourcesV1.updateNews("1", false, null, CONTENT.name().toLowerCase(), null); // Then assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); @@ -840,7 +843,7 @@ public void shouldGetOkWhenCreateNewsWithPublishedState() throws Exception { ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); - news.setPublicationState("published"); + news.setPublicationState(POSTED); news.setSpaceId("1"); Space space1 = new Space(); space1.setId("1"); @@ -1261,15 +1264,15 @@ public void shouldGetAllPinnedNewsWhenExist() throws Exception { News news1 = new News(); news1.setPublished(true); news1.setAuthor(JOHN); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setPublished(true); news2.setAuthor(JOHN); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setPublished(true); news3.setAuthor(JOHN); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1290,7 +1293,7 @@ public void shouldGetAllPinnedNewsWhenExist() throws Exception { assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { assertEquals(true, newsList.get(i).isPublished()); - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); } assertEquals(0, newsEntity.getOffset().intValue()); @@ -1312,17 +1315,17 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpaces() throws Excep news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1343,7 +1346,7 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpaces() throws Excep assertNotNull(newsList); assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); assertEquals(text, newsList.get(i).getTitle()); assertEquals(true, spacesIds.contains(newsList.get(i).getSpaceId())); @@ -1367,17 +1370,17 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpace() throws Except news1.setSpaceId(spaceId); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId(spaceId); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId(spaceId); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1397,7 +1400,7 @@ public void shouldGetAllNewsWhenSearchingWithTextInTheGivenSpace() throws Except assertNotNull(newsList); assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); assertEquals(text, newsList.get(i).getTitle()); assertEquals("4", newsList.get(i).getSpaceId()); @@ -1420,13 +1423,13 @@ public void shouldGetAllNewsWhenSearchingWithTagTextInTheGivenSpace() throws Exc news1.setAuthor(JOHN); news1.setTitle("newsTitle"); news1.setBody(newsBody); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId(spaceId); news2.setAuthor(JOHN); news2.setTitle("newsTitle"); news2.setBody(newsBody); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1464,19 +1467,19 @@ public void shouldGetPinnedNewsWhenSearchingWithTextInTheGivenSpaces() throws Ex news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setPublished(true); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setPublished(true); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1498,7 +1501,7 @@ public void shouldGetPinnedNewsWhenSearchingWithTextInTheGivenSpaces() throws Ex assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { assertEquals(true, newsList.get(i).isPublished()); - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); assertEquals(text, newsList.get(i).getTitle()); assertEquals(true, spacesIds.contains(newsList.get(i).getSpaceId())); @@ -1551,17 +1554,17 @@ public void shouldGetMyPostedNewsWhenExists() throws Exception { news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1580,7 +1583,7 @@ public void shouldGetMyPostedNewsWhenExists() throws Exception { assertNotNull(newsList); assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); } } @@ -1600,17 +1603,17 @@ public void shouldGetMyPostedNewsWhenFilteringWithTheGivenSpaces() throws Except news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1629,7 +1632,7 @@ public void shouldGetMyPostedNewsWhenFilteringWithTheGivenSpaces() throws Except assertNotNull(newsList); assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); assertEquals(true, spacesIds.contains(newsList.get(i).getSpaceId())); } @@ -1650,17 +1653,17 @@ public void shouldGetMyPostedNewsWhenSearchingWithTheGivenSpaces() throws Except news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1681,7 +1684,7 @@ public void shouldGetMyPostedNewsWhenSearchingWithTheGivenSpaces() throws Except assertNotNull(newsList); assertEquals(3, newsList.size()); for (int i = 0; i < newsList.size(); i++) { - assertEquals("published", newsList.get(i).getPublicationState()); + assertEquals(POSTED, newsList.get(i).getPublicationState()); assertEquals(JOHN, newsList.get(i).getAuthor()); assertEquals(text, newsList.get(i).getTitle()); assertEquals(true, spacesIds.contains(newsList.get(i).getSpaceId())); @@ -1793,17 +1796,17 @@ public void shouldGetBadRequestWhenSearchingWithoutQueryAndFavorites() throws Ex news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1829,17 +1832,17 @@ public void shouldGetBadRequestWhenSearchingWithNegativeOffset() throws Exceptio news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1866,17 +1869,17 @@ public void shouldGetBadRequestWhenSearchingWithNegativeLimit() throws Exception news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1904,17 +1907,17 @@ public void shouldGetnewsListWhenSearchingWithQuery() throws Exception { news1.setSpaceId("4"); news1.setAuthor(JOHN); news1.setTitle(text); - news1.setPublicationState("published"); + news1.setPublicationState(POSTED); News news2 = new News(); news2.setSpaceId("1"); news2.setAuthor(JOHN); news2.setTitle(text); - news2.setPublicationState("published"); + news2.setPublicationState(POSTED); News news3 = new News(); news3.setSpaceId("4"); news3.setAuthor(JOHN); news3.setTitle(text); - news3.setPublicationState("published"); + news3.setPublicationState(POSTED); List allNews = new ArrayList<>(); allNews.add(news1); allNews.add(news2); @@ -1946,7 +1949,7 @@ public void testMarkAsRead() throws Exception { ConversationState.setCurrent(new ConversationState(currentIdentity)); News news = new News(); news.setId("1"); - when(newsService.getNewsById("1", currentIdentity, false)).thenReturn(news); + when(newsService.getNewsById("1", currentIdentity, false, ARTICLE.name().toLowerCase())).thenReturn(news); doNothing().when(newsService).markAsRead(news, JOHN); Response response = newsRestResourcesV1.markNewsAsRead(request, "1"); verify(newsService, times(1)).markAsRead(news, JOHN); diff --git a/content-service/src/test/java/io/meeds/news/search/NewsIndexingServiceConnectorTest.java b/content-service/src/test/java/io/meeds/news/search/NewsIndexingServiceConnectorTest.java index aa65da81a..15b3e71eb 100644 --- a/content-service/src/test/java/io/meeds/news/search/NewsIndexingServiceConnectorTest.java +++ b/content-service/src/test/java/io/meeds/news/search/NewsIndexingServiceConnectorTest.java @@ -129,7 +129,7 @@ public void testCreate() { posterProfile.setProperty("fullName", "Root Root"); posterIdentity.setProfile(posterProfile); try { - when(newsService.getNewsById("1", false)).thenReturn(news); + when(newsService.getNewsArticleById("1")).thenReturn(news); } catch (Exception e) { e.printStackTrace(); } 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 7c7d2942c..355171268 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 @@ -19,8 +19,14 @@ */ package io.meeds.news.service.impl; +import static io.meeds.news.service.impl.NewsServiceImpl.DRAFT; +import static io.meeds.news.service.impl.NewsServiceImpl.NEWS_ACTIVITIES; import static io.meeds.news.service.impl.NewsServiceImpl.NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME; import static io.meeds.news.service.impl.NewsServiceImpl.NEWS_SUMMARY; +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.NewsObjectType.LATEST_DRAFT; +import static io.meeds.news.utils.NewsUtils.NewsUpdateType.CONTENT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -32,6 +38,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; @@ -40,7 +47,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -56,7 +65,6 @@ import org.exoplatform.commons.search.index.IndexingService; import org.exoplatform.commons.utils.CommonsUtils; import org.exoplatform.container.PortalContainer; -import org.exoplatform.portal.config.UserACL; import org.exoplatform.services.security.Identity; import org.exoplatform.social.core.manager.ActivityManager; import org.exoplatform.social.core.manager.IdentityManager; @@ -68,6 +76,8 @@ import org.exoplatform.social.metadata.model.MetadataObject; import org.exoplatform.upload.UploadService; import org.exoplatform.wiki.model.DraftPage; +import org.exoplatform.wiki.model.Page; +import org.exoplatform.wiki.model.PageVersion; import org.exoplatform.wiki.model.Wiki; import org.exoplatform.wiki.service.NoteService; import org.exoplatform.wiki.service.WikiService; @@ -75,6 +85,7 @@ import io.meeds.news.filter.NewsFilter; import io.meeds.news.model.News; import io.meeds.news.model.NewsDraftObject; +import io.meeds.news.model.NewsLatestDraftObject; import io.meeds.news.service.NewsService; import io.meeds.news.service.NewsTargetingService; import io.meeds.news.utils.NewsUtils; @@ -114,8 +125,6 @@ public class NewsServiceImplTest { private NewsService newsService; - private UserACL userACL; - private static final MockedStatic COMMONS_UTILS = mockStatic(CommonsUtils.class); private static final MockedStatic PORTAL_CONTAINER = mockStatic(PortalContainer.class); @@ -124,7 +133,6 @@ public class NewsServiceImplTest { @Before public void setUp() { - userACL = CommonsUtils.getService(UserACL.class); this.newsService = new NewsServiceImpl(spaceService, noteService, metadataService, @@ -132,7 +140,6 @@ public void setUp() { newsTargetingService, indexingService, identityManager, - userACL, activityManager, wikiService, uploadService); @@ -242,13 +249,13 @@ public void testGetDraftArticleById() throws Exception { 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"); + PORTAL_CONTAINER.when(PortalContainer::getCurrentPortalContainerName).thenReturn("portal"); + COMMONS_UTILS.when(CommonsUtils::getCurrentPortalOwner).thenReturn("dw"); Identity identity = mock(Identity.class); when(identity.getUserId()).thenReturn("john"); when(activityManager.getActivity(nullable(String.class))).thenReturn(null); - when(newsTargetingService.getTargetsByNewsId(anyString())).thenReturn(null); - + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); + NEWS_UTILS.when(() -> NewsUtils.buildDraftUrl(any())).thenReturn("url"); // When News news = newsService.getNewsById("1", identity, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase()); @@ -260,7 +267,7 @@ public void testGetDraftArticleById() throws Exception { assertEquals("draft", news.getPublicationState()); assertEquals(space.getDisplayName(), news.getSpaceDisplayName()); assertEquals(space.getAvatarUrl(), news.getSpaceAvatarUrl()); - assertEquals("/portal/dw/news/detail?newsId=1&type=draft", news.getUrl()); + assertEquals("url", news.getUrl()); } @Test @@ -297,7 +304,7 @@ public void testUpdateDraftArticle() throws Exception { Identity identity = mock(Identity.class); when(identity.getUserId()).thenReturn("john"); when(activityManager.getActivity(nullable(String.class))).thenReturn(null); - when(newsTargetingService.getTargetsByNewsId(anyString())).thenReturn(null); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); org.exoplatform.wiki.model.Page rootPage = mock(org.exoplatform.wiki.model.Page.class); when(rootPage.getName()).thenReturn(NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME); when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); @@ -319,7 +326,7 @@ public void testUpdateDraftArticle() throws Exception { expecteddraftPage.setWikiOwner("/space/groupId"); // When, Then - assertThrows(IllegalArgumentException.class, () -> newsService.updateNews(news, "john", false, false, "draft")); + assertThrows(IllegalAccessException.class, () -> newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase())); // Given when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); @@ -330,7 +337,7 @@ public void testUpdateDraftArticle() throws Exception { when(noteService.updateDraftForNewPage(any(DraftPage.class), anyLong())).thenReturn(expecteddraftPage); // When - newsService.updateNews(news, "john", false, false, "draft"); + newsService.updateNews(news, "john", false, false, NewsUtils.NewsObjectType.DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); // Then verify(noteService, times(1)).updateDraftForNewPage(eq(expecteddraftPage), anyLong()); @@ -371,7 +378,7 @@ public void testDeleteDraftArticle() throws Exception { Identity identity = mock(Identity.class); when(identity.getUserId()).thenReturn("john"); when(activityManager.getActivity(nullable(String.class))).thenReturn(null); - when(newsTargetingService.getTargetsByNewsId(anyString())).thenReturn(null); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); org.exoplatform.wiki.model.Page rootPage = mock(org.exoplatform.wiki.model.Page.class); when(rootPage.getName()).thenReturn(NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME); when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); @@ -422,15 +429,10 @@ public void testGetDraftArticles() throws Exception { when(identity.getUserId()).thenReturn("john"); List allowedDraftNewsSpaces = Arrays.asList(space1); NEWS_UTILS.when(() -> NewsUtils.getAllowedDraftNewsSpaces(identity)).thenReturn(allowedDraftNewsSpaces); - when(metadataService.getMetadataItemsByMetadataNameAndTypeAndObjectAndSpaceIds(anyString(), - anyString(), - anyString(), - anyList(), - anyLong(), - anyLong())).thenReturn(metadataItems); + when(metadataService.getMetadataItemsByFilter(any(), anyLong(), anyLong())).thenReturn(metadataItems); when(activityManager.getActivity(nullable(String.class))).thenReturn(null); - when(newsTargetingService.getTargetsByNewsId(anyString())).thenReturn(null); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); // When NewsFilter newsFilter = new NewsFilter(); @@ -443,4 +445,389 @@ public void testGetDraftArticles() throws Exception { assertNotNull(newsList); assertEquals(newsList.size(), 1); } + + @Test + public void testPostNews() throws Exception { + + // Given + 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"); + newsArticle.setActivities("1:2;3:4"); + + Identity identity = mock(Identity.class); + when(identity.getUserId()).thenReturn("john"); + NEWS_UTILS.when(() -> NewsUtils.getUserIdentity(anyString())).thenReturn(identity); + + Space space = mock(Space.class); + when(space.getId()).thenReturn("1"); + when(space.getGroupId()).thenReturn("/space/groupId"); + when(space.getAvatarUrl()).thenReturn("space/avatar/url"); + when(space.getDisplayName()).thenReturn("spaceDisplayName"); + when(space.getVisibility()).thenReturn("public"); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + when(spaceService.getSpaceById(any())).thenReturn(space); + when(spaceService.getSpaceByGroupId(anyString())).thenReturn(space); + NEWS_UTILS.when(() -> NewsUtils.canPublishNews(anyString(), any(Identity.class))).thenReturn(true); + when(spaceService.canRedactOnSpace(any(Space.class), any(Identity.class))).thenReturn(true); + + Wiki wiki = mock(Wiki.class); + when(wikiService.getWikiByTypeAndOwner(anyString(), anyString())).thenReturn(wiki); + org.exoplatform.wiki.model.Page rootPage = mock(org.exoplatform.wiki.model.Page.class); + when(rootPage.getName()).thenReturn(NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME); + when(rootPage.getId()).thenReturn("1"); + when(noteService.getNoteOfNoteBookByName("group", + space.getGroupId(), + NEWS_ARTICLES_ROOT_NOTE_PAGE_NAME)).thenReturn(rootPage); + + Page newsArticlePage = new Page(); + newsArticlePage.setTitle(newsArticle.getTitle()); + newsArticlePage.setContent(newsArticle.getBody()); + newsArticlePage.setParentPageId(rootPage.getId()); + newsArticlePage.setAuthor(newsArticle.getAuthor()); + newsArticlePage.setLang(null); + + Page createdPage = mock(Page.class); + when(createdPage.getId()).thenReturn("1"); + when(noteService.createNote(wiki, rootPage.getName(), newsArticlePage, identity)).thenReturn(createdPage); + PageVersion pageVersion = mock(PageVersion.class); + when(noteService.getPublishedVersionByPageIdAndLang(1L, null)).thenReturn(pageVersion); + when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(new org.exoplatform.social.core.identity.model.Identity("1")); + + // When + newsService.createNews(newsArticle, identity); + + // Then + verify(noteService, times(1)).createNote(wiki, rootPage.getName(), newsArticlePage, identity); + verify(noteService, times(1)).createVersionOfNote(createdPage, identity.getUserId()); + verify(noteService, times(1)).getPublishedVersionByPageIdAndLang(1L, null); + verify(metadataService, atLeast(1)).createMetadataItem(any(MetadataObject.class), + any(MetadataKey.class), + any(Map.class), + anyLong()); + } + + @Test + public void testCreateDraftArticleForExistingPage() 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); + + PageVersion pageVersion = mock(PageVersion.class); + when(noteService.getPublishedVersionByPageIdAndLang(1L, null)).thenReturn(pageVersion); + + when(existingPage.getAuthor()).thenReturn("john"); + when(pageVersion.getTitle()).thenReturn("title"); + when(pageVersion.getContent()).thenReturn("content"); + when(pageVersion.getUpdatedDate()).thenReturn(new Date()); + when(pageVersion.getAuthorFullName()).thenReturn("full name"); + + Space space = mock(Space.class); + when(space.getId()).thenReturn("1"); + when(space.getGroupId()).thenReturn("/space/groupId"); + when(space.getAvatarUrl()).thenReturn("space/avatar/url"); + when(space.getDisplayName()).thenReturn("spaceDisplayName"); + when(space.getVisibility()).thenReturn("public"); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + when(spaceService.getSpaceById(any())).thenReturn(space); + when(spaceService.getSpaceByGroupId(anyString())).thenReturn(space); + + Identity identity = mock(Identity.class); + when(identity.getUserId()).thenReturn("john"); + NEWS_UTILS.when(() -> NewsUtils.getUserIdentity(anyString())).thenReturn(identity); + NEWS_UTILS.when(() -> NewsUtils.canPublishNews(anyString(), any(Identity.class))).thenReturn(false); + NEWS_UTILS.when(() -> NewsUtils.processMentions(anyString(), any())).thenReturn(new HashSet<>()); + + when(activityManager.getActivity(nullable(String.class))).thenReturn(null); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); + + when(noteService.getLatestDraftPageByUserAndTargetPageAndLang(anyLong(), anyString(), anyString())).thenReturn(null); + + News news = new News(); + news.setAuthor("john"); + news.setTitle("new draft title"); + news.setBody("draft body"); + 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())); + + // 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"); + + DraftPage draftPage = mock(DraftPage.class); + when(draftPage.getUpdatedDate()).thenReturn(new Date()); + when(draftPage.getCreatedDate()).thenReturn(new Date()); + when(draftPage.getAuthor()).thenReturn("john"); + when(draftPage.getId()).thenReturn("1"); + when(noteService.createDraftForExistPage(any(DraftPage.class), + any(Page.class), + nullable(String.class), + anyLong(), + anyString())).thenReturn(draftPage); + + // When + newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); + + // Then + verify(noteService, times(1)).createDraftForExistPage(any(DraftPage.class), + eq(existingPage), + nullable(String.class), + anyLong(), + anyString()); + verify(metadataService, times(1)).createMetadataItem(any(NewsLatestDraftObject.class), + any(MetadataKey.class), + any(Map.class), + anyLong()); + + } + + @Test + public void testUpdateDraftArticleForExistingPage() 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); + + Space space = mock(Space.class); + when(space.getId()).thenReturn("1"); + when(space.getGroupId()).thenReturn("/space/groupId"); + when(space.getAvatarUrl()).thenReturn("space/avatar/url"); + when(space.getDisplayName()).thenReturn("spaceDisplayName"); + when(space.getVisibility()).thenReturn("public"); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + when(spaceService.getSpaceById(any())).thenReturn(space); + when(spaceService.getSpaceByGroupId(anyString())).thenReturn(space); + + Identity identity = mock(Identity.class); + when(identity.getUserId()).thenReturn("john"); + NEWS_UTILS.when(() -> NewsUtils.getUserIdentity(anyString())).thenReturn(identity); + 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.getUpdatedDate()).thenReturn(new Date()); + when(draftPage.getCreatedDate()).thenReturn(new Date()); + when(draftPage.getAuthor()).thenReturn("john"); + when(draftPage.getId()).thenReturn("1"); + when(draftPage.getContent()).thenReturn("body"); + when(draftPage.getWikiOwner()).thenReturn("/space/groupId"); + when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); + when(noteService.getLatestDraftPageByUserAndTargetPageAndLang(anyLong(), + anyString(), + nullable(String.class))).thenReturn(draftPage); + + News news = new News(); + news.setAuthor("john"); + news.setTitle("new draft title"); + news.setBody("draft body"); + 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())); + + // 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.updateDraftForExistPage(any(DraftPage.class), + any(Page.class), + nullable(String.class), + anyLong(), + anyString())).thenReturn(draftPage); + + // When + newsService.updateNews(news, "john", false, false, LATEST_DRAFT.name().toLowerCase(), CONTENT.name().toLowerCase()); + + // Then + verify(noteService, times(1)).updateDraftForExistPage(any(DraftPage.class), + eq(existingPage), + nullable(String.class), + anyLong(), + anyString()); + verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + } + + @Test + public void testUpdateNewsArticle() 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); + + Space space = mock(Space.class); + when(space.getId()).thenReturn("1"); + when(space.getGroupId()).thenReturn("/space/groupId"); + when(space.getAvatarUrl()).thenReturn("space/avatar/url"); + when(space.getDisplayName()).thenReturn("spaceDisplayName"); + when(space.getVisibility()).thenReturn("public"); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + when(spaceService.getSpaceById(any())).thenReturn(space); + when(spaceService.getSpaceByGroupId(anyString())).thenReturn(space); + + Identity identity = mock(Identity.class); + when(identity.getUserId()).thenReturn("john"); + NEWS_UTILS.when(() -> NewsUtils.getUserIdentity(anyString())).thenReturn(identity); + 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, null)).thenReturn(pageVersion); + when(noteService.getLatestDraftPageByUserAndTargetPageAndLang(anyLong(), + anyString(), + nullable(String.class))).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.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())); + + // 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))).thenReturn(existingPage); + + // When + newsService.updateNews(news, "john", false, false, ARTICLE.name().toLowerCase(), CONTENT.name().toLowerCase()); + + // Then + verify(noteService, times(1)).updateNote(any(Page.class)); + verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId()); + verify(noteService, times(2)).getPublishedVersionByPageIdAndLang(1L, null); + verify(metadataService, times(1)).updateMetadataItem(any(MetadataItem.class), anyLong()); + } + + @Test + public void testDeleteNewsArticle() 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"); + when(existingPage.getWikiType()).thenReturn("group"); + when(existingPage.getName()).thenReturn("news"); + + 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<>(); + properties.put(NEWS_ACTIVITIES, "1:1;"); + when(metadataItem.getProperties()).thenReturn(properties); + + Space space = mock(Space.class); + when(space.getId()).thenReturn("1"); + when(space.getGroupId()).thenReturn("/space/groupId"); + when(space.getAvatarUrl()).thenReturn("space/avatar/url"); + when(space.getDisplayName()).thenReturn("spaceDisplayName"); + when(space.getVisibility()).thenReturn("public"); + when(spaceService.isSuperManager(anyString())).thenReturn(true); + when(spaceService.getSpaceById(any())).thenReturn(space); + when(spaceService.getSpaceByGroupId(anyString())).thenReturn(space); + + Identity identity = mock(Identity.class); + when(identity.getUserId()).thenReturn("john"); + NEWS_UTILS.when(() -> NewsUtils.getUserIdentity(anyString())).thenReturn(identity); + NEWS_UTILS.when(() -> NewsUtils.canPublishNews(anyString(), any(Identity.class))).thenReturn(false); + when(newsTargetingService.getTargetsByNews(any(News.class))).thenReturn(null); + + PageVersion pageVersion = mock(PageVersion.class); + when(noteService.getPublishedVersionByPageIdAndLang(1L, null)).thenReturn(pageVersion); + + when(existingPage.getAuthor()).thenReturn("john"); + when(pageVersion.getAuthor()).thenReturn("john"); + when(pageVersion.getUpdatedDate()).thenReturn(new Date()); + when(pageVersion.getAuthorFullName()).thenReturn("full name"); + // + assertThrows(IllegalAccessException.class, () -> newsService.deleteNews(existingPage.getId(), identity, false)); + + // when + when(spaceService.canRedactOnSpace(space, identity)).thenReturn(true); + when(noteService.deleteNote(existingPage.getWikiType(), existingPage.getWikiOwner(), existingPage.getName())).thenReturn(true); + DraftPage draftPage = mock(DraftPage.class); + when(draftPage.getId()).thenReturn("1"); + when(noteService.getLatestDraftOfPage(existingPage, identity.getUserId())).thenReturn(draftPage); + when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftPage); + + newsService.deleteNews(existingPage.getId(), identity, false); + + //Then + verify(noteService, times(1)).deleteNote(existingPage.getWikiType(), existingPage.getWikiOwner(), existingPage.getName()); + verify(noteService, times(1)).removeDraftById("1"); + verify(activityManager, times(1)).deleteActivity("1"); + } } 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 0a14d86de..c635244e0 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 @@ -310,12 +310,16 @@ public void testGetAllowedTargets() throws Exception { } @Test - public void testGetTargetsByNewsId() throws Exception { + public void testGetTargetsByNews() throws Exception { // Given NewsTargetingServiceImpl newsTargetingService = new NewsTargetingServiceImpl(metadataService, identityManager, spaceService, organizationService); + News news = new News(); + news.setId("123456"); + news.setSpaceId("1"); + Metadata sliderNews = new Metadata(); sliderNews.setName("sliderNews"); sliderNews.setCreatedDate(100); @@ -330,12 +334,12 @@ public void testGetTargetsByNewsId() throws Exception { metadataItem.setMetadata(sliderNews); metadataItems.add(metadataItem); - NewsTargetObject newsTargetObject = new NewsTargetObject("news", "123456", null); + NewsTargetObject newsTargetObject = new NewsTargetObject("news", "123456", null, 1L); when(metadataService.getMetadataItemsByMetadataTypeAndObject(NewsTargetingService.METADATA_TYPE.getName(), newsTargetObject)).thenReturn(metadataItems); // When - List newsTargets = newsTargetingService.getTargetsByNewsId("123456"); + List newsTargets = newsTargetingService.getTargetsByNews(news); // Then assertNotNull(newsTargets); @@ -367,13 +371,13 @@ public void testSaveNewsTargets() throws Exception { targets.add("sliderNews"); News news = new News(); - news.setSpaceId("spaceId"); + news.setSpaceId("1"); news.setTitle("Test news"); news.setAuthor("user1"); news.setTargets(targets); news.setId("123456"); - NewsTargetObject newsTargetObject = new NewsTargetObject("news", "123456", null); + NewsTargetObject newsTargetObject = new NewsTargetObject("news", "123456", null, 1L); MetadataKey metadataKey = new MetadataKey(NewsTargetingService.METADATA_TYPE.getName(), "sliderNews", 0); Identity userIdentity = new Identity("1"); when(identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, "root")).thenReturn(userIdentity); @@ -381,7 +385,7 @@ public void testSaveNewsTargets() throws Exception { Authenticator authenticator = mock(Authenticator.class); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(IdentityRegistry.class)).thenReturn(identityRegistry); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getCurrentContainer()).thenReturn(container); - when(spaceService.getSpaceById("spaceId")).thenReturn(space); + when(spaceService.getSpaceById("1")).thenReturn(space); when(spaceService.isMember(space, identity.getUserId())).thenReturn(true); EXO_CONTAINER_CONTEXT.when(() -> ExoContainerContext.getService(Authenticator.class)).thenReturn(authenticator); when(authenticator.createIdentity("root")).thenReturn(identity); 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 62ca23c5e..0c6cedf6a 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 @@ -53,6 +53,18 @@ + + + NewsScheduleAndFilterDisplayingFeatureProperties + org.exoplatform.container.ExtendedPropertyConfigurator + + + NewsScheduleAndFilterDisplayingFeatureProperties + Schedule and filter options displaying Feature enablement flag + + + + org.exoplatform.services.resources.ResourceBundleService diff --git a/content-webapp/src/main/webapp/js/newsConstants.js b/content-webapp/src/main/webapp/js/newsConstants.js index 9c3b5207f..de8b4715a 100644 --- a/content-webapp/src/main/webapp/js/newsConstants.js +++ b/content-webapp/src/main/webapp/js/newsConstants.js @@ -35,3 +35,15 @@ export const newsConstants = { MAX_UPLOAD_FILES: 1, userName: eXo.env.portal.userName }; + +export const newsUpdateType = { + CONTENT: 'content', + POSTING_AND_PUBLISHING: 'postingAndPublishing', + SCHEDULE: 'schedule' +}; + +export const newsObjectType = { + DRAFT: 'draft', + ARTICLE: 'article', + LATEST_DRAFT: 'latest_draft' +}; diff --git a/content-webapp/src/main/webapp/js/newsUtils.js b/content-webapp/src/main/webapp/js/newsUtils.js index 484987684..168c73249 100644 --- a/content-webapp/src/main/webapp/js/newsUtils.js +++ b/content-webapp/src/main/webapp/js/newsUtils.js @@ -17,7 +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. */ - + export function convertDate(date) { return `${ pad(date.getMonth()+1) }/${ diff --git a/content-webapp/src/main/webapp/latest-news/components/ExoLatestNews.vue b/content-webapp/src/main/webapp/latest-news/components/ExoLatestNews.vue index 91a13ad73..27f950f40 100644 --- a/content-webapp/src/main/webapp/latest-news/components/ExoLatestNews.vue +++ b/content-webapp/src/main/webapp/latest-news/components/ExoLatestNews.vue @@ -216,7 +216,7 @@ export default { for (let i=0; i
@@ -54,7 +55,7 @@ size="40" :class="isMobile ? 'me-3' : 'mx-3'" class="my-auto"> - +
@@ -90,7 +91,7 @@ { + let newsType = this.newsType; + if (this.activityId && publicationState === this.$newsConstants.newsObjectType.DRAFT) { + newsType = this.$newsConstants.newsObjectType.LATEST_DRAFT; + } + if (this.activityId && publicationState === 'posted') { + newsType = this.$newsConstants.newsObjectType.ARTICLE; + } + return this.$newsServices.updateNews(updatedNews, post, newsType).then((createdNews) => { this.spaceUrl = createdNews.spaceUrl; if (this.news.body !== createdNews.body) { this.imagesURLs = this.extractImagesURLsDiffs(this.news.body, createdNews.body); diff --git a/content-webapp/src/main/webapp/news-activity-composer-app/components/ExoNewsFileDrop.vue b/content-webapp/src/main/webapp/news-activity-composer-app/components/ExoNewsFileDrop.vue index a0840232b..24f539ebc 100644 --- a/content-webapp/src/main/webapp/news-activity-composer-app/components/ExoNewsFileDrop.vue +++ b/content-webapp/src/main/webapp/news-activity-composer-app/components/ExoNewsFileDrop.vue @@ -25,8 +25,11 @@ :class="files.length >0 ? 'imageUploaded' : '' " class="dropMsg" for="uploadedFile"> - - + + fa-regular fa-image + @@ -24,6 +25,10 @@ export default { type: String, default: '' }, + newsType: { + type: String, + default: '' + }, }, data: () => ({ news: null, @@ -33,7 +38,7 @@ export default { showDeleteButton: false, }), created() { - this.$newsServices.getNewsById(this.newsId, false) + this.$newsServices.getNewsById(this.newsId, false, this.newsType) .then(news => { if (news !== null && news !== UNAUTHORIZED_CODE) { this.news = news; diff --git a/content-webapp/src/main/webapp/news-details-app/main.js b/content-webapp/src/main/webapp/news-details-app/main.js index 5e95bf0c5..b348faf7b 100644 --- a/content-webapp/src/main/webapp/news-details-app/main.js +++ b/content-webapp/src/main/webapp/news-details-app/main.js @@ -54,10 +54,11 @@ export function init() { data: function() { return { newsId: getURLQueryParam('newsId'), + newsType: getURLQueryParam('type'), }; }, template: ` - + `, i18n, vuetify diff --git a/content-webapp/src/main/webapp/news-details/components/ExoNewsDetails.vue b/content-webapp/src/main/webapp/news-details/components/ExoNewsDetails.vue index c9c8f1c22..22713d93d 100644 --- a/content-webapp/src/main/webapp/news-details/components/ExoNewsDetails.vue +++ b/content-webapp/src/main/webapp/news-details/components/ExoNewsDetails.vue @@ -38,7 +38,8 @@ + :news-id="newsId" + :news-type="newsType"/> { let createdNewsActivity = null; if (createdNews.activities) { diff --git a/content-webapp/src/main/webapp/news-details/components/ExoNewsDetailsBody.vue b/content-webapp/src/main/webapp/news-details/components/ExoNewsDetailsBody.vue index 45e067fd4..2b635c657 100644 --- a/content-webapp/src/main/webapp/news-details/components/ExoNewsDetailsBody.vue +++ b/content-webapp/src/main/webapp/news-details/components/ExoNewsDetailsBody.vue @@ -23,7 +23,7 @@
- +

{{ $t('news.archive.text') }}

diff --git a/content-webapp/src/main/webapp/news-details/components/ExoNewsEditPublishingDrawer.vue b/content-webapp/src/main/webapp/news-details/components/ExoNewsEditPublishingDrawer.vue index a0e137fb1..8c519e871 100644 --- a/content-webapp/src/main/webapp/news-details/components/ExoNewsEditPublishingDrawer.vue +++ b/content-webapp/src/main/webapp/news-details/components/ExoNewsEditPublishingDrawer.vue @@ -162,7 +162,7 @@ export default { return this.news && this.news.published; }, isHiddenActivity() { - return this.news && this.news.activityPosted; + return this.news && !this.news.activityPosted; }, disableTargetOption() { return this.selectedTargets && this.selectedTargets.length === 0; @@ -202,7 +202,9 @@ export default { openDrawer() { if (this.news) { this.publish = this.news.published; - this.isActivityPosted = !this.news.activityPosted; + if (this.news.publicationState !== this.$newsConstants.newsObjectType.DRAFT) { + this.isActivityPosted = this.news.activityPosted; + } } if (this.$refs.postNewsDrawer) { this.disabled = true; @@ -219,7 +221,7 @@ export default { updateNews() { this.editingNews = true; this.news.published = this.publish; - this.news.activityPosted = !this.isActivityPosted; + this.news.activityPosted = this.isActivityPosted; this.news.targets = this.selectedTargets; if (this.publish) { this.news.audience = this.selectedAudience === this.$t('news.composer.stepper.audienceSection.allUsers') ? 'all' : 'space'; @@ -227,7 +229,7 @@ export default { else { this.news.audience = null; } - return this.$newsServices.updateNews(this.news, false).then(() => { + return this.$newsServices.updateNews(this.news, false, this.$newsConstants.newsObjectType.ARTICLE, this.$newsConstants.newsUpdateType.POSTING_AND_PUBLISHING).then(() => { this.editingNews = false; this.$root.$emit('alert-message', this.$t('news.composer.alert.success.UpdateTargets'), 'success'); this.$emit('refresh-news', this.news.newsId); diff --git a/content-webapp/src/main/webapp/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue b/content-webapp/src/main/webapp/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue index a5093e1b2..2c468bf6d 100644 --- a/content-webapp/src/main/webapp/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue +++ b/content-webapp/src/main/webapp/news-details/components/mobile/ExoNewsDetailsToolBarMobile.vue @@ -89,7 +89,7 @@ export default { return this.news && this.news.spaceMember ? this.news.spaceUrl : `${eXo.env.portal.context}/${eXo.env.portal.metaPortalName}`; }, illustrationUrl() { - return this.news && this.news.illustrationURL ? this.news.illustrationURL.concat('&size=315x128').toString() : '/news/images/news.png'; + return this.news && this.news.illustrationURL ? this.news.illustrationURL.concat('&size=315x128').toString() : '/content/images/news.png'; }, publicationState() { return this.news && this.news.publicationState; diff --git a/content-webapp/src/main/webapp/news-details/initComponents.js b/content-webapp/src/main/webapp/news-details/initComponents.js index 0fa247bcf..49637a57d 100644 --- a/content-webapp/src/main/webapp/news-details/initComponents.js +++ b/content-webapp/src/main/webapp/news-details/initComponents.js @@ -49,9 +49,15 @@ for (const key in components) { } import * as newsServices from '../services/newsServices'; +import * as newsConstants from '../js/newsConstants.js'; if (!Vue.prototype.$newsServices) { window.Object.defineProperty(Vue.prototype, '$newsServices', { value: newsServices, }); +} +if (!Vue.prototype.$newsConstants) { + window.Object.defineProperty(Vue.prototype, '$newsConstants', { + value: newsConstants, + }); } \ No newline at end of file diff --git a/content-webapp/src/main/webapp/news-details/main.js b/content-webapp/src/main/webapp/news-details/main.js index 381752480..6da9d48b9 100644 --- a/content-webapp/src/main/webapp/news-details/main.js +++ b/content-webapp/src/main/webapp/news-details/main.js @@ -58,6 +58,7 @@ export function init(params) { news: params.news, newsId: params.news.newsId, activityId: params.activityId, + newsType: params.newsType, showEditButton: params.news.canEdit, showPublishButton: params.news.canPublish, showDeleteButton: params.news.canDelete, @@ -68,6 +69,7 @@ export function init(params) { :news="news" :news-id="newsId" :activity-id="activityId" + :news-type="newsType" :show-edit-button="showEditButton" :show-publish-button="showPublishButton" :show-delete-button="showDeleteButton"/> diff --git a/content-webapp/src/main/webapp/news-extensions/activity-stream-extensions/extensions.js b/content-webapp/src/main/webapp/news-extensions/activity-stream-extensions/extensions.js index cac149f8f..d0cbe8111 100644 --- a/content-webapp/src/main/webapp/news-extensions/activity-stream-extensions/extensions.js +++ b/content-webapp/src/main/webapp/news-extensions/activity-stream-extensions/extensions.js @@ -51,7 +51,7 @@ const newsActivityTypeExtensionOptions = { hideOnDelete: true, supportsThumbnail: true, windowTitlePrefixKey: 'news.window.title', - getThumbnail: (activity) => activity?.news?.illustrationURL && `${activity?.news?.illustrationURL}&size=305x285` || '/news/images/news.png', + getThumbnail: (activity) => activity?.news?.illustrationURL && `${activity?.news?.illustrationURL}&size=305x285` || '/content/images/news.png', getThumbnailProperties: (activity) => !(activity?.news?.illustrationURL) && { height: '90px', width: '90px', diff --git a/content-webapp/src/main/webapp/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue b/content-webapp/src/main/webapp/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue index 70ebd06c3..616a0664d 100644 --- a/content-webapp/src/main/webapp/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue +++ b/content-webapp/src/main/webapp/news-extensions/favorite-drawer-extensions/components/favorites/NewsFavoriteItem.vue @@ -31,7 +31,7 @@ + src="/content/images/news.png"> @@ -63,10 +63,11 @@ export default { data: () => ({ activityTitle: '', url: '', - isFavorite: true + isFavorite: true, + newsObjectType: 'article', }), created() { - this.$newsServices.getNewsById(this.id, false) + this.$newsServices.getNewsById(this.id, false, this.newsObjectType) .then(news => { this.activityTitle = news.title; this.url = news.url; diff --git a/content-webapp/src/main/webapp/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue b/content-webapp/src/main/webapp/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue index a2f63dd85..0dca816d6 100644 --- a/content-webapp/src/main/webapp/news-extensions/notification-extensions/components/PostNewsNotificationPlugin.vue +++ b/content-webapp/src/main/webapp/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}`; + : `${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/news-list-view/components/NewsListView.vue b/content-webapp/src/main/webapp/news-list-view/components/NewsListView.vue index ee2eab1ca..81b098a9f 100644 --- a/content-webapp/src/main/webapp/news-list-view/components/NewsListView.vue +++ b/content-webapp/src/main/webapp/news-list-view/components/NewsListView.vue @@ -209,9 +209,9 @@ export default { this.retrieveNewsList().finally(() => this.$root.$applicationLoaded()); document.addEventListener(`component-${this.extensionApp}-${this.extensionType}-updated`, this.refreshViewExtensions); this.refreshViewExtensions(); - - document.addEventListener('drawerOpened', () => this.$el.closest('#stickyBlockDesktop').style.position = 'static'); - document.addEventListener('drawerClosed', () => this.$el.closest('#stickyBlockDesktop').style.position = 'sticky'); + }, + beforeDestroy() { + document.removeEventListener(`component-${this.extensionApp}-${this.extensionType}-updated`, this.refreshViewExtensions); }, methods: { retrieveNewsList() { diff --git a/content-webapp/src/main/webapp/news-list-view/components/settings/NewsSettingsDrawer.vue b/content-webapp/src/main/webapp/news-list-view/components/settings/NewsSettingsDrawer.vue index 89cf542de..f4aec9d71 100644 --- a/content-webapp/src/main/webapp/news-list-view/components/settings/NewsSettingsDrawer.vue +++ b/content-webapp/src/main/webapp/news-list-view/components/settings/NewsSettingsDrawer.vue @@ -25,6 +25,7 @@ id="newsSettingsDrawer" right fixed + detached @closed="close">