Skip to content

Commit

Permalink
feat: Implement Notes/Content insert image option - EXO-74754 - Meeds…
Browse files Browse the repository at this point in the history
…-io/MIPs#145 (#312)

Implement notes/content insert image option.
  • Loading branch information
sofyenne committed Nov 19, 2024
1 parent 02d5c18 commit 89e33c4
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2024 Meeds Association [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package io.meeds.news.plugin;

import io.meeds.news.model.News;
import io.meeds.news.service.NewsService;
import jakarta.annotation.PostConstruct;
import org.exoplatform.commons.exception.ObjectNotFoundException;
import org.exoplatform.services.security.Identity;
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 articleVersionId) throws ObjectNotFoundException {
PageVersion pageVersion = noteService.getPageVersionById(Long.parseLong(articleVersionId));
News news = newsService.getNewsArticleById(pageVersion.getParent().getId());
return news != null ? Long.parseLong(news.getSpaceId()) : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -941,6 +942,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,
Expand Down Expand Up @@ -1020,10 +1022,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());
Expand Down Expand Up @@ -1065,6 +1069,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(),
Expand Down Expand Up @@ -1218,6 +1223,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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -1974,6 +1982,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,
Expand Down Expand Up @@ -2137,8 +2146,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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* This file is part of the Meeds project (https://meeds.io/).
*
* Copyright (C) 2020 - 2024 Meeds Association [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package io.meeds.news.plugin;

import io.meeds.news.model.News;
import io.meeds.news.service.NewsService;
import org.exoplatform.social.attachment.AttachmentService;
import org.exoplatform.wiki.model.Page;
import org.exoplatform.wiki.model.PageVersion;
import org.exoplatform.wiki.service.NoteService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static io.meeds.news.utils.NewsUtils.NewsObjectType.ARTICLE;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class ArticleAttachmentPluginTest {

@Mock
private NoteService noteService;

@Mock
private NewsService newsService;

@Mock
private AttachmentService attachmentService;

@InjectMocks
private ArticlePageVersionAttachmentPlugin plugin;

@Before
public void setUp() {
plugin.init();
}

@Test
public void testGetObjectType() {
Assert.assertEquals("articlePageVersion", plugin.getObjectType());
}

@Test
public void testHasAccessPermission() throws Exception {
org.exoplatform.services.security.Identity userIdentity = mock(org.exoplatform.services.security.Identity.class);
PageVersion pageVersion = mock(PageVersion.class);
Page page = mock(Page.class);
News news = mock(News.class);

when(userIdentity.getUserId()).thenReturn("user123");
when(noteService.getPageVersionById(anyLong())).thenReturn(pageVersion);
when(pageVersion.getParent()).thenReturn(page);
when(page.getId()).thenReturn("1");
when(newsService.getNewsArticleById(anyString())).thenReturn(news);
when(newsService.canViewNews(news, userIdentity.getUserId())).thenReturn(true);

assertTrue(plugin.hasAccessPermission(userIdentity, "1"));
}

@Test
public void testHasEditPermission() throws Exception {
org.exoplatform.services.security.Identity userIdentity = mock(org.exoplatform.services.security.Identity.class);
PageVersion pageVersion = mock(PageVersion.class);
Page page = mock(Page.class);
News news = mock(News.class);

when(noteService.getPageVersionById(anyLong())).thenReturn(pageVersion);
when(pageVersion.getParent()).thenReturn(page);
when(page.getId()).thenReturn("1");
when(newsService.getNewsById("1", userIdentity, false, ARTICLE.name())).thenReturn(news);
when(news.isCanEdit()).thenReturn(true);

assertTrue(plugin.hasEditPermission(userIdentity, "1"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ export default {
spacePrettyName: null,
editorExtensions: null,
autosaveProcessedFromEditorExtension: false,
allowedTargets: []
allowedTargets: [],
draftObjectType: 'wikiDraft',
};
},
watch: {
Expand Down Expand Up @@ -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;
Expand All @@ -342,10 +345,14 @@ export default {
this.article.schedulePostDate = createdArticle.schedulePostDate;
this.article.publicationState = createdArticle.publicationState;
this.article.scheduleUnpublishDate = createdArticle.scheduleUnpublishDate;
this.article.body = createdArticle.body;
this.article.lang = createdArticle.lang;
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(() => {
Expand Down Expand Up @@ -374,6 +381,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',
Expand Down Expand Up @@ -420,6 +428,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;
Expand All @@ -431,6 +441,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(() => {
Expand All @@ -457,6 +470,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) {
Expand Down Expand Up @@ -523,6 +539,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();
Expand All @@ -538,6 +555,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();
Expand Down

0 comments on commit 89e33c4

Please sign in to comment.