diff --git a/content-service/src/main/java/io/meeds/news/plugin/ArticlePageVersionAttachmentPlugin.java b/content-service/src/main/java/io/meeds/news/plugin/ArticlePageVersionAttachmentPlugin.java new file mode 100644 index 000000000..3289769cc --- /dev/null +++ b/content-service/src/main/java/io/meeds/news/plugin/ArticlePageVersionAttachmentPlugin.java @@ -0,0 +1,73 @@ +package io.meeds.news.plugin; + +import io.meeds.news.model.News; +import io.meeds.news.service.NewsService; +import io.meeds.news.utils.NewsUtils; +import jakarta.annotation.PostConstruct; +import org.exoplatform.commons.exception.ObjectNotFoundException; +import org.exoplatform.container.ExoContainerContext; +import org.exoplatform.services.security.Identity; +import org.exoplatform.services.security.IdentityRegistry; +import org.exoplatform.social.attachment.AttachmentPlugin; +import org.exoplatform.social.attachment.AttachmentService; +import org.exoplatform.wiki.model.PageVersion; +import org.exoplatform.wiki.service.NoteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE; + +@Component +public class ArticlePageVersionAttachmentPlugin extends AttachmentPlugin { + + @Autowired + private AttachmentService attachmentService; + + @Autowired + private NewsService newsService; + + @Autowired + private NoteService noteService; + + public static final String OBJECT_TYPE = "articlePageVersion"; + + @PostConstruct + public void init() { + attachmentService.addPlugin(this); + } + + @Override + public String getObjectType() { + return OBJECT_TYPE; + } + + @Override + public boolean hasAccessPermission(Identity identity, String articleVersionId) throws ObjectNotFoundException { + PageVersion pageVersion = noteService.getPageVersionById(Long.parseLong(articleVersionId)); + News news = newsService.getNewsArticleById(pageVersion.getParent().getId()); + return news != null && newsService.canViewNews(news, identity.getUserId()); + } + + @Override + public boolean hasEditPermission(Identity identity, String articleVersionId) throws ObjectNotFoundException { + News news = null; + try { + PageVersion pageVersion = noteService.getPageVersionById(Long.parseLong(articleVersionId)); + news = newsService.getNewsById(pageVersion.getParent().getId(), identity, false, ARTICLE.name()); + } catch (IllegalAccessException e) { + return false; + } + return news != null && news.isCanEdit(); + } + + @Override + public long getAudienceId(String s) throws ObjectNotFoundException { + return 0; + } + + @Override + public long getSpaceId(String articleId) throws ObjectNotFoundException { + News news = newsService.getNewsArticleById(articleId); + return news != null ? Long.parseLong(news.getSpaceId()) : 0; + } +} 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 fb3170a8d..4e2e97b06 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 @@ -39,6 +39,7 @@ import java.util.regex.Matcher; import java.util.stream.Stream; +import io.meeds.news.plugin.ArticlePageVersionAttachmentPlugin; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -940,6 +941,7 @@ public News createDraftArticleForNewPage(News draftArticle, draftArticle.setId(draftArticlePage.getId()); draftArticle.setCreationDate(draftArticlePage.getCreatedDate()); draftArticle.setUpdateDate(draftArticlePage.getUpdatedDate()); + draftArticle.setBody(draftArticlePage.getContent()); Space draftArticleSpace = spaceService.getSpaceByGroupId(pageOwnerId); draftArticle.setSpaceId(draftArticleSpace.getId()); NewsDraftObject draftArticleMetaDataObject = new NewsDraftObject(NEWS_METADATA_DRAFT_OBJECT_TYPE, @@ -1019,10 +1021,12 @@ public News createNewsArticlePage(News newsArticle, String newsArticleCreator) t newsArticlePage.setProperties(new NotePageProperties(Long.parseLong(draftNewsId), null, null, false, false, true)); } newsArticlePage = noteService.createNote(wiki, newsArticlesRootNotePage.getName(), newsArticlePage, poster); + noteService.createVersionOfNote(newsArticlePage, poster.getUserId(), ArticlePageVersionAttachmentPlugin.OBJECT_TYPE, draftNewsId); if (newsArticlePage != null) { PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(newsArticlePage.getId()), null); // set properties newsArticle.setId(newsArticlePage.getId()); + newsArticle.setBody(pageVersion.getContent()); newsArticle.setLang(newsArticlePage.getLang()); newsArticle.setCreationDate(pageVersion.getCreatedDate()); newsArticle.setProperties(newsArticlePage.getProperties()); @@ -1064,6 +1068,7 @@ public News createDraftForExistingPage(News draftArticle, draftArticle.setTargetPageId(draftArticlePage.getTargetPageId()); draftArticle.setProperties(draftArticlePage.getProperties()); draftArticle.setId(draftArticlePage.getId()); + draftArticle.setBody(draftArticlePage.getContent()); NewsLatestDraftObject latestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, draftArticlePage.getId(), targetArticlePage.getId(), @@ -1217,6 +1222,7 @@ private News updateDraftArticleForNewPage(News draftArticle, String draftArticle Long.parseLong(identityManager.getOrCreateUserIdentity(draftArticleUpdater) .getId())); draftArticle.setProperties(draftPage.getProperties()); + draftArticle.setBody(draftPage.getContent()); draftArticle.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftPage.getProperties(), draftArticle.getLang())); // Update content permissions @@ -1849,8 +1855,10 @@ private News updateArticle(News news, Identity updater, String newsUpdateType) t // create the version if (newsUpdateType.equalsIgnoreCase(CONTENT_AND_TITLE.name())) { - noteService.createVersionOfNote(existingPage, updater.getUserId()); - news.setLatestVersionId(noteService.getPublishedVersionByPageIdAndLang(Long.valueOf(news.getId()), news.getLang()).getId()); + noteService.createVersionOfNote(existingPage, updater.getUserId(), ArticlePageVersionAttachmentPlugin.OBJECT_TYPE, null); + PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.valueOf(news.getId()), news.getLang()); + news.setLatestVersionId(pageVersion.getId()); + news.setBody(pageVersion.getContent()); // remove the draft DraftPage draftPage = noteService.getLatestDraftPageByUserAndTargetPageAndLang(Long.parseLong(existingPage.getId()), updater.getUserId(), @@ -1975,6 +1983,7 @@ private News updateDraftArticleForExistingPage(News news, String updater, Page p news.setDraftUpdater(draftPage.getAuthor()); news.setTargetPageId(draftPage.getTargetPageId()); news.setProperties(draftPage.getProperties()); + news.setBody(draftPage.getContent()); news.setIllustrationURL(NewsUtils.buildIllustrationUrl(draftPage.getProperties(), news.getLang())); NewsLatestDraftObject latestDraftObject = new NewsLatestDraftObject(NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE, @@ -2138,8 +2147,10 @@ private News addNewArticleVersionWithLang(News news, Identity versionCreator, Sp properties.setDraft(false); } existingPage.setProperties(properties); - noteService.createVersionOfNote(existingPage, versionCreator.getUserId()); - news.setLatestVersionId(noteService.getPublishedVersionByPageIdAndLang(Long.valueOf(newsId), news.getLang()).getId()); + noteService.createVersionOfNote(existingPage, versionCreator.getUserId(), ArticlePageVersionAttachmentPlugin.OBJECT_TYPE, null); + PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.valueOf(newsId), news.getLang()); + news.setLatestVersionId(pageVersion.getId()); + news.setBody(pageVersion.getContent()); news.setIllustrationURL(NewsUtils.buildIllustrationUrl(news.getProperties(), news.getLang())); DraftPage draftPage = noteService.getLatestDraftPageByTargetPageAndLang(Long.parseLong(newsId), news.getLang()); if (draftPage != null) { 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 fe779cebd..b0ad0d7fe 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 @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; +import io.meeds.news.plugin.ArticlePageVersionAttachmentPlugin; import io.meeds.news.search.NewsSearchConnector; import io.meeds.news.search.NewsESSearchResult; import io.meeds.notes.model.NoteFeaturedImage; @@ -622,6 +623,7 @@ public void testCreateDraftArticleForExistingPage() throws Exception { when(draftPage.getCreatedDate()).thenReturn(new Date()); when(draftPage.getAuthor()).thenReturn("john"); when(draftPage.getId()).thenReturn("1"); + when(draftPage.getContent()).thenReturn("content"); when(noteService.createDraftForExistPage(any(DraftPage.class), any(Page.class), nullable(String.class), @@ -783,7 +785,7 @@ public void testUpdateNewsArticle() throws Exception { // Then verify(noteService, times(1)).updateNote(any(Page.class), any(), any()); - verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId()); + verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId(), ArticlePageVersionAttachmentPlugin.OBJECT_TYPE, null); verify(noteService, times(2)).getPublishedVersionByPageIdAndLang(1L, null); } @@ -1015,6 +1017,7 @@ public void testAddNewsArticleTranslation() throws Exception { when(pageVersion.getAuthor()).thenReturn("john"); when(pageVersion.getUpdatedDate()).thenReturn(new Date()); when(pageVersion.getAuthorFullName()).thenReturn("full name"); + when(pageVersion.getContent()).thenReturn("content"); News news = new News(); news.setAuthor("john"); @@ -1043,7 +1046,7 @@ public void testAddNewsArticleTranslation() throws Exception { // Then verify(noteService, times(1)).updateNote(any(Page.class), any(), any()); - verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId()); + verify(noteService, times(1)).createVersionOfNote(existingPage, identity.getUserId(), ArticlePageVersionAttachmentPlugin.OBJECT_TYPE, null); verify(noteService, times(2)).getPublishedVersionByPageIdAndLang(1L, null); NEWS_UTILS.verify(() -> NewsUtils.broadcastEvent(eq(NewsUtils.ADD_ARTICLE_TRANSLATION), anyObject(), anyObject()), times(1)); } diff --git a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ContentRichEditor.vue b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ContentRichEditor.vue index 5d747d34f..8f6de76fe 100644 --- a/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ContentRichEditor.vue +++ b/content-webapp/src/main/webapp/vue-app/news-activity-composer-app/components/ContentRichEditor.vue @@ -134,7 +134,8 @@ export default { spacePrettyName: null, editorExtensions: null, autosaveProcessedFromEditorExtension: false, - allowedTargets: [] + allowedTargets: [], + draftObjectType: 'wikiDraft', }; }, watch: { @@ -329,6 +330,8 @@ export default { if (updatedArticle?.properties) { updatedArticle.properties.draft = true; } + updatedArticle.body = this.$noteUtils.sanitizeSrcImageTags(updatedArticle.body); + const setEditorDataMutely = this.$noteUtils.isHasImagesToBeProcessed(updatedArticle.body, this.draftObjectType); updatedArticle.publicationState = 'draft'; return this.$newsServices.updateNews(updatedArticle, false, this.articleType).then((createdArticle) => { this.spaceUrl = createdArticle.spaceUrl; @@ -346,6 +349,9 @@ export default { if (this.article.body !== createdArticle.body) { this.imagesURLs = this.extractImagesURLsDiffs(this.article.body, createdArticle.body); } + if (setEditorDataMutely) { + this.$refs?.editor?.setEditorDataMutely?.(createdArticle.body); + } }).then(() => this.$emit('draftUpdated')) .then(() => this.draftSavingStatus = this.$t('news.composer.draft.savedDraftStatus')) .finally(() => { @@ -374,6 +380,7 @@ export default { this.imagesURLs = this.extractImagesURLsDiffs(this.article.body, createdArticle.body); } this.fillArticle(createdArticle.id, false, createdArticle.lang); + this.$refs?.editor?.setEditorDataMutely?.(createdArticle.body); this.displayAlert({ message: this.$t('news.save.success.message'), type: 'success', @@ -420,6 +427,8 @@ export default { properties: properties, draftPage: true }; + article.body = this.$noteUtils.sanitizeSrcImageTags(article.body); + const setEditorDataMutely = this.$noteUtils.isHasImagesToBeProcessed(article.body, this.draftObjectType); if (this.article.id) { if (this.article.title || this.article.body) { article.id = this.article.id; @@ -431,6 +440,9 @@ export default { this.article.draftPage = true; this.article.id = updatedArticle.id; this.article.properties = updatedArticle?.properties; + if (setEditorDataMutely) { + this.$refs?.editor?.setEditorDataMutely?.(updatedArticle.body); + } }) .then(() => this.$emit('draftUpdated')) .then(() => { @@ -457,6 +469,9 @@ export default { if (!this.articleId) { this.articleId = createdArticle.id; } + if (setEditorDataMutely) { + this.$refs?.editor?.setEditorDataMutely?.(createdArticle.body); + } this.$emit('draftCreated'); this.savingDraft = false; if (this.autosaveProcessedFromEditorExtension) { @@ -523,6 +538,7 @@ export default { if (article.publicationState ==='staged') { this.$newsServices.scheduleNews(article, this.articleType).then((scheduleArticle) => { this.articleType = 'latest_draft'; + this.$refs?.editor?.setEditorDataMutely?.(scheduleArticle.body); this.fillArticle(scheduleArticle.id, false, null).then(() => { this.updateUrl(); this.initDataPropertiesFromUrl(); @@ -538,6 +554,7 @@ export default { } else { this.$newsServices.saveNews(article).then((createdArticle) => { this.articleType = 'latest_draft'; + this.$refs?.editor?.setEditorDataMutely?.(createdArticle.body); this.fillArticle(createdArticle.id, false, createdArticle.lang || this.selectedLanguage).then(() => { this.updateUrl(); this.initDataPropertiesFromUrl();