From 9d781652b2e6b5e316a91ffd6aadb2ff4457a737 Mon Sep 17 00:00:00 2001 From: Helmi Akermi <70575401+hakermi@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:46:14 +0100 Subject: [PATCH] feat: Add an upgrade plugin for content pages properties migration and update NewsArticlesUpgradeplugin - EXO-73181 - Meeds-io/MIPs#128 (#242) Add an upgrade plugin for content pages properties(summary/illustrationId) migration and update the NewsArticlesUpgradePlugin to cover different target version context --- .../ContentArticlePropertiesUpgrade.java | 234 ++++++++++++++++++ .../news/upgrade/jcr/NewsArticlesUpgrade.java | 134 +++++++--- .../resources/conf/portal/configuration.xml | 33 +++ .../ContentArticlePropertiesUpgradeTest.java | 164 ++++++++++++ .../upgrade/jcr/NewsArticlesUpgradeTest.java | 47 +++- 5 files changed, 570 insertions(+), 42 deletions(-) create mode 100644 data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java create mode 100644 data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java diff --git a/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java b/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java new file mode 100644 index 000000000..631a68471 --- /dev/null +++ b/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2024 eXo Platform SAS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.exoplatform.news.upgrade; + +import io.meeds.notes.model.NoteMetadataObject; +import org.apache.commons.collections4.MapUtils; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; +import org.exoplatform.commons.upgrade.UpgradeProductPlugin; +import org.exoplatform.container.xml.InitParams; +import org.exoplatform.portal.config.UserACL; +import org.exoplatform.services.log.ExoLogger; +import org.exoplatform.services.log.Log; +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.metadata.MetadataFilter; +import org.exoplatform.social.metadata.MetadataService; +import org.exoplatform.social.metadata.model.MetadataItem; +import org.exoplatform.social.metadata.model.MetadataKey; +import org.exoplatform.wiki.model.Page; +import org.exoplatform.wiki.model.PageVersion; +import org.exoplatform.wiki.service.NoteService; +import org.exoplatform.wiki.utils.Utils; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ContentArticlePropertiesUpgrade extends UpgradeProductPlugin { + + private static final Log LOG = + ExoLogger.getLogger(ContentArticlePropertiesUpgrade.class); + + private final NoteService noteService; + + private final MetadataService metadataService; + + private final IdentityManager identityManager; + + private final SpaceService spaceService; + + private final UserACL userACL; + + private final SettingService settingService; + + private static final MetadataKey NOTES_METADATA_KEY = + new MetadataKey("notes", Utils.NOTES_METADATA_OBJECT_TYPE, 0); + + public static final String NEWS_METADATA_NAME = "news"; + + public static final String NEWS_METADATA_DRAFT_OBJECT_TYPE = "newsDraftPage"; + + public static final String NOTE_METADATA_PAGE_OBJECT_TYPE = "notePage"; + + public static final String NOTE_METADATA_DRAFT_PAGE_OBJECT_TYPE = "noteDraftPage"; + + public static final String NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE = "newsPageVersion"; + + public static final String NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE = "newsLatestDraftPage"; + + public static final String CONTENT_ILLUSTRATION_ID = "illustrationId"; + + public static final String SUMMARY = "summary"; + + public static final String FEATURED_IMAGE_ID = "featuredImageId"; + + private static final String FEATURED_IMAGE_UPDATED_DATE = "featuredImageUpdatedDate"; + + private static final String ARTICLES_UPGRADE_PLUGIN_NAME = "NewsArticlesUpgradePlugin"; + + private static final String ARTICLES_UPGRADE_EXECUTED_KEY = "articlesUpgradeExecuted"; + + public ContentArticlePropertiesUpgrade(InitParams initParams, + NoteService noteService, + MetadataService metadataService, + IdentityManager identityManager, + SpaceService spaceService, + UserACL userACL, + SettingService settingService) { + super(initParams); + this.noteService = noteService; + this.metadataService = metadataService; + this.identityManager = identityManager; + this.spaceService = spaceService; + this.userACL = userACL; + this.settingService = settingService; + } + + @Override + public void processUpgrade(String oldVersion, String newVersion) { + long startupTime = System.currentTimeMillis(); + LOG.info("Start upgrade of content page properties"); + int notMigratedContentPagesPropertiesCount; + int processedContentPagesPropertiesCount = 0; + int totalContentPagesPropertiesCount = 0; + int ignoredContentPagesPropertiesCount = 0; + try { + MetadataFilter metadataFilter = getMetadataFilter(); + metadataFilter.setMetadataObjectTypes(List.of(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE, + NEWS_METADATA_DRAFT_OBJECT_TYPE, + NEWS_METADATA_LATEST_DRAFT_OBJECT_TYPE)); + List metadataItems = metadataService.getMetadataItemsByFilter(metadataFilter, 0, 0); + totalContentPagesPropertiesCount = metadataItems.size(); + for (MetadataItem metadataItem : metadataItems) { + if (metadataItem != null && !MapUtils.isEmpty(metadataItem.getProperties())) { + Map contentProperties = metadataItem.getProperties(); + Page page = null; + String objectType = NOTE_METADATA_PAGE_OBJECT_TYPE; + if (metadataItem.getObjectType().equals(NEWS_METADATA_PAGE_VERSION_OBJECT_TYPE)) { + PageVersion pageVersion = noteService.getPageVersionById(Long.valueOf(metadataItem.getObjectId())); + if (pageVersion != null && pageVersion.getParent() != null) { + page = pageVersion.getParent(); + } + } else { + page = noteService.getDraftNoteById(metadataItem.getObjectId(), userACL.getSuperUser()); + objectType = NOTE_METADATA_DRAFT_PAGE_OBJECT_TYPE; + } + if (page != null && page.getAuthor() != null) { + NoteMetadataObject noteMetadataObject = buildNoteMetadataObject(page, null, objectType); + MetadataItem noteMetadataItem = getNoteMetadataItem(page, null, objectType); + + if (noteMetadataItem != null) { + LOG.info("ContentArticlePropertiesUpgrade: Ignore : Content page properties already migrated"); + ignoredContentPagesPropertiesCount++; + } else { + Map noteProperties = new HashMap<>(); + long creatorId = Long.parseLong(identityManager.getOrCreateUserIdentity(page.getAuthor()).getId()); + + if (contentProperties.getOrDefault(CONTENT_ILLUSTRATION_ID, null) != null) { + noteProperties.put(FEATURED_IMAGE_ID, contentProperties.get(CONTENT_ILLUSTRATION_ID)); + noteProperties.put(FEATURED_IMAGE_UPDATED_DATE, String.valueOf(new Date().getTime())); + } + noteProperties.put(SUMMARY, contentProperties.get(SUMMARY)); + metadataService.createMetadataItem(noteMetadataObject, NOTES_METADATA_KEY, noteProperties, creatorId); + processedContentPagesPropertiesCount++; + LOG.info("ContentArticlePropertiesUpgrade: Processed content page properties: {}/{}", + processedContentPagesPropertiesCount, + totalContentPagesPropertiesCount); + } + } else { + ignoredContentPagesPropertiesCount++; + LOG.warn("ContentArticlePropertiesUpgrade: Content page properties ignored due to data inconsistency: " + + "page exists: {}, page name: {}", + "ObjectType: {}", + "Page Id: {}", + "Page author: {}", + page != null, + page != null ? page.getName() : null, + objectType, + page != null ? page.getId() : null, + null); + } + } else { + LOG.info("ContentArticlePropertiesUpgrade: Ignore : Content page properties are empty"); + ignoredContentPagesPropertiesCount++; + } + } + } catch (Exception e) { + LOG.error("An error occurred while Migrating content pages properties:", e); + } + notMigratedContentPagesPropertiesCount = totalContentPagesPropertiesCount + - (processedContentPagesPropertiesCount + ignoredContentPagesPropertiesCount); + if (notMigratedContentPagesPropertiesCount == 0) { + LOG.info("End ContentArticlePropertiesUpgrade successful migration: total={} processed={} ignored={} error={}. It took {} ms.", + totalContentPagesPropertiesCount, + processedContentPagesPropertiesCount, + ignoredContentPagesPropertiesCount, + notMigratedContentPagesPropertiesCount, + (System.currentTimeMillis() - startupTime)); + } else { + LOG.warn("End ContentArticlePropertiesUpgrade with some errors: total={} processed={} ignored={} error={}. It took {} ms." + + " The not migrated news articles will be processed again next startup.", + totalContentPagesPropertiesCount, + processedContentPagesPropertiesCount, + ignoredContentPagesPropertiesCount, + notMigratedContentPagesPropertiesCount, + (System.currentTimeMillis() - startupTime)); + throw new IllegalStateException("Some content page properties weren't migrated successfully. It will be re-attempted next startup"); + } + } + + @Override + public boolean shouldProceedToUpgrade(String newVersion, String previousGroupVersion) { + SettingValue settingValue = settingService.get(Context.GLOBAL.id(ARTICLES_UPGRADE_PLUGIN_NAME), + Scope.APPLICATION.id(ARTICLES_UPGRADE_PLUGIN_NAME), + ARTICLES_UPGRADE_EXECUTED_KEY); + if (settingValue == null || settingValue.getValue().equals("false")) { + return false; + } + return super.shouldProceedToUpgrade(newVersion, previousGroupVersion); + } + + private MetadataFilter getMetadataFilter() { + MetadataFilter metadataFilter = new MetadataFilter(); + metadataFilter.setMetadataName(NEWS_METADATA_NAME); + metadataFilter.setMetadataTypeName(NEWS_METADATA_NAME); + return metadataFilter; + } + + private NoteMetadataObject buildNoteMetadataObject(Page note, String lang, String objectType) { + Space space = spaceService.getSpaceByGroupId(note.getWikiOwner()); + long spaceId = space != null ? Long.parseLong(space.getId()) : 0L; + String noteId = String.valueOf(note.getId()); + noteId = lang != null ? noteId + "-" + lang : noteId; + return new NoteMetadataObject(objectType, noteId, note.getParentPageId(), spaceId); + } + + private MetadataItem getNoteMetadataItem(Page note, String lang, String objectType) { + NoteMetadataObject noteMetadataObject = buildNoteMetadataObject(note, lang, objectType); + return metadataService.getMetadataItemsByMetadataAndObject(NOTES_METADATA_KEY, noteMetadataObject) + .stream() + .findFirst() + .orElse(null); + } + +} diff --git a/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgrade.java b/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgrade.java index 59604bf11..804cb77f4 100644 --- a/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgrade.java +++ b/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgrade.java @@ -39,9 +39,15 @@ import io.meeds.notes.model.NotePageProperties; import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.MapUtils; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; import org.exoplatform.commons.file.model.FileItem; import org.exoplatform.commons.file.services.FileService; import org.exoplatform.commons.search.index.IndexingService; +import org.exoplatform.commons.upgrade.UpgradePluginExecutionContext; import org.exoplatform.commons.upgrade.UpgradeProductPlugin; import org.exoplatform.commons.utils.CommonsUtils; import org.exoplatform.commons.utils.HTMLSanitizer; @@ -66,6 +72,7 @@ import org.exoplatform.social.metadata.model.MetadataKey; import org.exoplatform.social.metadata.model.MetadataObject; import org.exoplatform.social.metadata.model.MetadataType; +import org.exoplatform.wiki.model.DraftPage; import org.exoplatform.wiki.model.Page; import org.exoplatform.wiki.model.PageVersion; import org.exoplatform.wiki.service.NoteService; @@ -75,6 +82,7 @@ import io.meeds.news.search.NewsIndexingServiceConnector; import io.meeds.news.service.NewsService; import io.meeds.news.utils.NewsUtils; +import org.exoplatform.wiki.utils.Utils; public class NewsArticlesUpgrade extends UpgradeProductPlugin { @@ -97,8 +105,10 @@ public class NewsArticlesUpgrade extends UpgradeProductPlugin { private NoteService noteService; private IndexingService indexingService; - + private IdentityManager identityManager; + + private SettingService settingService; private int migratedNewsArticlesCount = 0; @@ -109,6 +119,14 @@ public class NewsArticlesUpgrade extends UpgradeProductPlugin { private static final MetadataKey NEWS_METADATA_KEY = new MetadataKey(NEWS_METADATA_TYPE.getName(), NEWS_METADATA_NAME, 0); + private static final MetadataKey NOTES_METADATA_KEY = new MetadataKey("notes", Utils.NOTES_METADATA_OBJECT_TYPE, 0); + + private static final String PLUGIN_NAME = "NewsArticlesUpgradePlugin"; + + private static final String PLUGIN_EXECUTED_KEY = "articlesUpgradeExecuted"; + + private boolean upgradeFailed = false; + public NewsArticlesUpgrade(InitParams initParams, RepositoryService repositoryService, SessionProviderService sessionProviderService, @@ -119,7 +137,8 @@ public NewsArticlesUpgrade(InitParams initParams, FileService fileService, NoteService noteService, IdentityManager identityManager, - IndexingService indexingService) { + IndexingService indexingService, + SettingService settingService) { super(initParams); this.repositoryService = repositoryService; this.sessionProviderService = sessionProviderService; @@ -131,6 +150,7 @@ public NewsArticlesUpgrade(InitParams initParams, this.noteService = noteService; this.identityManager = identityManager; this.indexingService = indexingService; + this.settingService = settingService; } @Override @@ -202,10 +222,36 @@ public void processUpgrade(String oldVersion, String newVersion) { migratedNewsArticlesCount, notMigratedNewsArticlesCount, (System.currentTimeMillis() - startupTime)); + this.upgradeFailed = true; throw new IllegalStateException("Some news articles wasn't executed successfully. It will be re-attempted next startup"); } } + @Override + public void afterUpgrade() { + if (!upgradeFailed) { + settingService.set(Context.GLOBAL.id(PLUGIN_NAME), + Scope.APPLICATION.id(PLUGIN_NAME), + PLUGIN_EXECUTED_KEY, + SettingValue.create(true)); + } + } + + @Override + public boolean shouldProceedToUpgrade(String newVersion, String previousGroupVersion, UpgradePluginExecutionContext upgradePluginExecutionContext) { + SettingValue settingValue = settingService.get(Context.GLOBAL.id(PLUGIN_NAME), + Scope.APPLICATION.id(PLUGIN_NAME), + PLUGIN_EXECUTED_KEY); + boolean shouldUpgrade = super.shouldProceedToUpgrade(newVersion, previousGroupVersion, upgradePluginExecutionContext); + if (!shouldUpgrade && settingValue == null) { + settingService.set(Context.GLOBAL.id(PLUGIN_NAME), + Scope.APPLICATION.id(PLUGIN_NAME), + PLUGIN_EXECUTED_KEY, + SettingValue.create(true)); + } + return shouldUpgrade; + } + public int manageNewsArticles(List newsArticlesNodes, Session session) throws Exception { int notMigratedNewsArticlesCount = 0; for (Node newsArticleNode : newsArticlesNodes) { @@ -214,6 +260,7 @@ public int manageNewsArticles(List newsArticlesNodes, Session session) thr News draftArticle = null; try { News news = convertNewsNodeToNewEntity(newsArticleNode, null); + NotePageProperties properties = news.getProperties(); LOG.info("Migrating news article with id '{}' and title '{}'", newsArticleNode.getUUID(), news.getTitle()); Space space = spaceService.getSpaceById(news.getSpaceId()); @@ -222,15 +269,14 @@ public int manageNewsArticles(List newsArticlesNodes, Session session) thr || getStringProperty(newsArticleNode, "publication:currentState").equals("published")) { article = newsService.createNewsArticlePage(news, news.getAuthor()); - if (news.getProperties() != null && news.getAuthor() != null) { - NotePageProperties properties = news.getProperties(); - properties.setNoteId(Long.parseLong(article.getId())); + properties.setNoteId(Long.parseLong(article.getId())); + if (news.getAuthor() != null) { noteService.saveNoteMetadata(properties, article.getLang(), Long.valueOf(identityManager.getOrCreateUserIdentity(news.getAuthor()).getId())); } PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(article.getId()), null); - setArticleIllustration(pageVersion.getId(), article.getSpaceId(), newsArticleNode, "newsPageVersion"); + setArticleIllustration(pageVersion.getParent(), article.getSpaceId(), newsArticleNode, "notePage"); setArticleAttachments(pageVersion.getId(), article.getSpaceId(), newsArticleNode, "newsPageVersion"); /* upgrade news id for news targets and favorite metadatata items */ setArticleMetadatasItems(article.getId(), newsArticleNode.getUUID()); @@ -254,7 +300,15 @@ public int manageNewsArticles(List newsArticlesNodes, Session session) thr space.getGroupId(), news.getAuthor(), news.getCreationDate().getTime()); - setArticleIllustration(draftArticle.getId(), draftArticle.getSpaceId(), newsArticleNode, "newsDraftPage"); + DraftPage draftPage = noteService.getDraftNoteById(draftArticle.getId(), draftArticle.getAuthor()); + properties.setNoteId(Long.parseLong(draftPage.getId())); + properties.setDraft(true); + if (news.getAuthor() != null) { + noteService.saveNoteMetadata(properties, + draftPage.getLang(), + Long.valueOf(identityManager.getOrCreateUserIdentity(news.getAuthor()).getId())); + } + setArticleIllustration(draftPage, draftArticle.getSpaceId(), newsArticleNode, "noteDraftPage"); } else {// drafts of existing articles // upgrade existing articles @@ -262,17 +316,17 @@ public int manageNewsArticles(List newsArticlesNodes, Session session) thr Node versionNode = newsArticleNode.getVersionHistory().getSession().getNodeByUUID(versionNodeUUID); Node publishedNode = versionNode.getNode("jcr:frozenNode"); News publishedNews = convertNewsNodeToNewEntity(newsArticleNode, publishedNode); - article = newsService.createNewsArticlePage(publishedNews, publishedNews.getAuthor()); - if (publishedNews.getProperties() != null && publishedNews.getAuthor() != null) { - NotePageProperties properties = publishedNews.getProperties(); - properties.setNoteId(Long.parseLong(article.getId())); - noteService.saveNoteMetadata(properties, + properties = publishedNews.getProperties(); + properties.setNoteId(Long.parseLong(article.getId())); + if (publishedNews.getAuthor() != null) { + properties = noteService.saveNoteMetadata(properties, article.getLang(), - Long.valueOf(identityManager.getOrCreateUserIdentity(publishedNews.getAuthor()).getId())); + Long.valueOf(identityManager.getOrCreateUserIdentity(publishedNews.getAuthor()) + .getId())); } PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(article.getId()), null); - setArticleIllustration(pageVersion.getId(), article.getSpaceId(), publishedNode, "newsPageVersion"); + setArticleIllustration(pageVersion.getParent(), article.getSpaceId(), publishedNode, "notePage"); setArticleAttachments(pageVersion.getId(), article.getSpaceId(), publishedNode, "newsPageVersion"); /* upgrade news id for news targets and favorite metadatata items */ setArticleMetadatasItems(article.getId(), newsArticleNode.getUUID()); @@ -282,14 +336,15 @@ public int manageNewsArticles(List newsArticlesNodes, Session session) thr // upgrade the drafts of existing articles /* attachments will not be migrated for drafts */ + properties.setDraft(true); + news.setProperties(properties); News draftForExistingArticle = newsService.createDraftForExistingPage(news, news.getAuthor(), publishedPage, news.getCreationDate().getTime()); - setArticleIllustration(draftForExistingArticle.getId(), - draftForExistingArticle.getSpaceId(), - newsArticleNode, - "newsLatestDraftPage"); + DraftPage draftPage = noteService.getDraftNoteById(draftForExistingArticle.getId(), + draftForExistingArticle.getAuthor()); + setArticleIllustration(draftPage, draftForExistingArticle.getSpaceId(), newsArticleNode, "noteDraftPage"); // set the update and the created date setArticleCreateAndUpdateDate(article.getId(), article.getSpaceId(), newsArticleNode); } @@ -372,7 +427,7 @@ private Long saveArticleIllustration(InputStream articleIllustrationFileInputStr FileItem articleIllustrationFileItem = new FileItem(null, fileName, mimeType, - "news", + "wiki", uploadSize, new Date(), IdentityConstants.SYSTEM, @@ -386,10 +441,10 @@ private Long saveArticleIllustration(InputStream articleIllustrationFileInputStr } } - private void setArticleIllustration(String articleId, + private void setArticleIllustration(Page article, String spaceId, Node newsNode, - String articleObjectType) throws RepositoryException { + String articleObjectType) throws Exception { if (newsNode.hasNode("illustration")) { Node illustrationNode = newsNode.getNode("illustration"); Node illustrationContentNode = illustrationNode.getNode("jcr:content"); @@ -397,19 +452,32 @@ private void setArticleIllustration(String articleId, String mimetype = illustrationContentNode.getProperty("jcr:mimeType").getString(); String illustrationNodeName = illustrationNode.getProperty("exo:title").getString(); Long articleIllustrationId = saveArticleIllustration(illustrationNodeInputStream, illustrationNodeName, mimetype, 0); - MetadataObject articleMetaDataObject = new MetadataObject(articleObjectType, articleId, null, Long.parseLong(spaceId)); - - MetadataItem articleMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY, - articleMetaDataObject) - .get(0); - if (articleMetadataItem != null) { - Map articleMetadataItemProperties = articleMetadataItem.getProperties(); - if (articleMetadataItemProperties == null) { - articleMetadataItemProperties = new HashMap<>(); + if (article != null && article.getAuthor() != null) { + long creatorId = Long.parseLong(identityManager.getOrCreateUserIdentity(article.getAuthor()).getId()); + MetadataObject articleMetaDataObject = new MetadataObject(articleObjectType, + article.getId(), + article.getParentPageId(), + Long.parseLong(spaceId)); + + MetadataItem articleMetadataItem = metadataService + .getMetadataItemsByMetadataAndObject(NOTES_METADATA_KEY, + articleMetaDataObject) + .stream() + .findFirst() + .orElse(null); + Map articleMetadataItemProperties = new HashMap<>(); + if (articleMetadataItem != null && !MapUtils.isEmpty(articleMetadataItem.getProperties())) { + articleMetadataItemProperties = articleMetadataItem.getProperties(); + } + articleMetadataItemProperties.put("featuredImageId", String.valueOf(articleIllustrationId)); + articleMetadataItemProperties.put("featuredImageUpdatedDate", String.valueOf(new Date().getTime())); + + if (articleMetadataItem != null) { + articleMetadataItem.setProperties(articleMetadataItemProperties); + metadataService.updateMetadataItem(articleMetadataItem, creatorId); + } else { + metadataService.createMetadataItem(articleMetaDataObject, NOTES_METADATA_KEY, articleMetadataItemProperties, creatorId); } - articleMetadataItemProperties.put("illustrationId", String.valueOf(articleIllustrationId)); - articleMetadataItem.setProperties(articleMetadataItemProperties); - metadataService.updateMetadataItem(articleMetadataItem, articleMetadataItem.getCreatorId()); } } } diff --git a/data-upgrade-news/src/main/resources/conf/portal/configuration.xml b/data-upgrade-news/src/main/resources/conf/portal/configuration.xml index a47efa764..53de8dd9e 100644 --- a/data-upgrade-news/src/main/resources/conf/portal/configuration.xml +++ b/data-upgrade-news/src/main/resources/conf/portal/configuration.xml @@ -48,6 +48,39 @@ + + ContentArticlePropertiesUpgrade + addUpgradePlugin + org.exoplatform.news.upgrade.ContentArticlePropertiesUpgrade + Migrate content properties from content to note + + + product.group.id + The groupId of the product + org.exoplatform.platform + + + plugin.execution.order + The plugin execution order + 1 + + + plugin.upgrade.execute.once + Execute this upgrade plugin only once + true + + + plugin.upgrade.async.execution + The plugin will be executed in an asynchronous mode + true + + + plugin.upgrade.target.version + Target version of the plugin + 7.0.0 + + + diff --git a/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java b/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java new file mode 100644 index 000000000..60f4b4471 --- /dev/null +++ b/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java @@ -0,0 +1,164 @@ +package org.exoplatform.news.upgrade; + +import io.meeds.notes.model.NoteMetadataObject; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.container.xml.InitParams; +import org.exoplatform.container.xml.ValueParam; +import org.exoplatform.portal.config.UserACL; +import org.exoplatform.social.core.identity.model.Identity; +import org.exoplatform.social.core.manager.IdentityManager; +import org.exoplatform.social.core.space.spi.SpaceService; +import org.exoplatform.social.metadata.MetadataService; +import org.exoplatform.social.metadata.model.MetadataItem; +import org.exoplatform.social.metadata.model.MetadataKey; +import org.exoplatform.wiki.model.DraftPage; +import org.exoplatform.wiki.model.Page; +import org.exoplatform.wiki.model.PageVersion; +import org.exoplatform.wiki.service.NoteService; +import org.exoplatform.wiki.utils.Utils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.elasticsearch.annotations.Setting; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class ContentArticlePropertiesUpgradeTest { + + @Mock + private NoteService noteService; + + @Mock + private MetadataService metadataService; + + @Mock + private IdentityManager identityManager; + + @Mock + private SpaceService spaceService; + + @Mock + private UserACL userACL; + + @Mock + private SettingService settingService; + + private ContentArticlePropertiesUpgrade contentArticlePropertiesUpgrade; + + private static final MetadataKey NOTES_METADATA_KEY = new MetadataKey("notes", Utils.NOTES_METADATA_OBJECT_TYPE, 0); + + private static final String ILLUSTRATION_ID = "illustrationId"; + + private static final String SUMMARY = "summary"; + + @Before + public void setUp() { + InitParams initParams = new InitParams(); + ValueParam valueParam = new ValueParam(); + valueParam.setName("product.group.id"); + valueParam.setValue("org.exoplatform.platform"); + initParams.addParameter(valueParam); + this.contentArticlePropertiesUpgrade = new ContentArticlePropertiesUpgrade(initParams, + noteService, + metadataService, + identityManager, + spaceService, + userACL, + settingService); + } + + @Test + public void processUpgrade() throws Exception { + MetadataItem page = new MetadataItem(); + MetadataItem draftOfPage = new MetadataItem(); + MetadataItem draftOfPage2 = new MetadataItem(); + MetadataItem draft = new MetadataItem(); + page.setId(1L); + page.setObjectType("newsPageVersion"); + page.setObjectId("1"); + page.setProperties(Map.of(ILLUSTRATION_ID, "1", SUMMARY, "test summary")); + + draftOfPage.setId(2L); + draftOfPage.setObjectType("newsLatestDraftPage"); + draftOfPage.setObjectId("2"); + draftOfPage.setProperties(Map.of(ILLUSTRATION_ID, "2", SUMMARY, "test summary")); + + draftOfPage2.setId(4L); + draftOfPage2.setObjectType("newsLatestDraftPage"); + draftOfPage2.setObjectId("6"); + draftOfPage2.setProperties(Map.of(ILLUSTRATION_ID, "4", SUMMARY, "test summary")); + + draft.setId(1L); + draft.setObjectId("3"); + draft.setObjectType("newsDraftPage"); + draft.setProperties(Map.of(ILLUSTRATION_ID, "3", SUMMARY, "test summary")); + + Page parentPage = new Page(); + parentPage.setId("2"); + parentPage.setAuthor("user"); + PageVersion pageVersion = new PageVersion(); + pageVersion.setId("1"); + pageVersion.setParent(parentPage); + pageVersion.setAuthor("user"); + + DraftPage draftOfExistingPage = new DraftPage(); + draftOfExistingPage.setId("2"); + draftOfExistingPage.setAuthor("user"); + + DraftPage draftOfExistingPage2 = new DraftPage(); + draftOfExistingPage2.setId("6"); + + DraftPage draftPage = new DraftPage(); + draftPage.setId("3"); + draftPage.setAuthor("user"); + + MetadataItem notePage = new MetadataItem(); + notePage.setId(5L); + notePage.setObjectType("notePage"); + notePage.setObjectId("2"); + + List metadataItems = List.of(page, draftOfPage, draftOfPage2, draft); + Identity identity = mock(Identity.class); + when(metadataService.getMetadataItemsByFilter(any(), anyLong(), anyLong())).thenReturn(metadataItems); + when(noteService.getPageVersionById(anyLong())).thenReturn(pageVersion); + when(noteService.getDraftNoteById(anyString(), anyString())).thenReturn(draftOfExistingPage, draftOfExistingPage2, draftPage); + when(identityManager.getOrCreateUserIdentity(anyString())).thenReturn(identity); + when(metadataService.getMetadataItemsByMetadataAndObject(NOTES_METADATA_KEY, + new NoteMetadataObject("noteDraftPage", "3", null, 0L))) + .thenReturn(new ArrayList<>()); + when(metadataService.getMetadataItemsByMetadataAndObject(NOTES_METADATA_KEY, + new NoteMetadataObject("noteDraftPage", "2", null, 0L))) + .thenReturn(new ArrayList<>()); + when(metadataService.getMetadataItemsByMetadataAndObject(NOTES_METADATA_KEY, + new NoteMetadataObject("notePage", "2", null, 0L))) + .thenReturn(List.of(notePage)); + + when(userACL.getSuperUser()).thenReturn("root"); + when(identity.getId()).thenReturn("1"); + contentArticlePropertiesUpgrade.processUpgrade(null, null); + + verify(metadataService, times(2)).createMetadataItem(any(), any(), any(), anyLong()); + } + + @Test + public void shouldProceedToUpgrade() { + SettingValue settingValue = mock(SettingValue.class); + when(settingValue.getValue()).thenReturn("false"); + when(settingService.get(any(), any(), anyString())).thenReturn(null, settingValue); + assertFalse(contentArticlePropertiesUpgrade.shouldProceedToUpgrade("1.0", "1.2")); + assertFalse(contentArticlePropertiesUpgrade.shouldProceedToUpgrade("1.0", "1.2")); + when(settingValue.getValue()).thenReturn("true"); + assertTrue(contentArticlePropertiesUpgrade.shouldProceedToUpgrade("1.0", "1.2")); + } +} diff --git a/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgradeTest.java b/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgradeTest.java index 6bfa9a14c..d9c489cf1 100644 --- a/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgradeTest.java +++ b/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/jcr/NewsArticlesUpgradeTest.java @@ -16,18 +16,16 @@ */ package org.exoplatform.news.upgrade.jcr; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -45,6 +43,10 @@ import javax.jcr.query.QueryManager; import javax.jcr.query.QueryResult; +import io.meeds.notes.model.NotePageProperties; +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.upgrade.UpgradePluginExecutionContext; import org.exoplatform.social.core.identity.model.Identity; import org.exoplatform.social.core.manager.IdentityManager; import org.junit.AfterClass; @@ -124,6 +126,9 @@ public class NewsArticlesUpgradeTest { @Mock private IndexingService indexingService; + @Mock + private SettingService settingService; + private NewsArticlesUpgrade newsArticlesUpgrade; @AfterClass @@ -150,7 +155,8 @@ public void setUp() { fileService, noteService, identityManager, - indexingService); + indexingService, + settingService); } @Test @@ -216,9 +222,12 @@ public void testProcessUpgrade() throws Exception { News article = mock(News.class); when(article.getId()).thenReturn("1"); when(article.getSpaceId()).thenReturn("1"); - when(newsService.createNewsArticlePage(any(News.class), anyString())).thenReturn(article); - + Page page = new Page(); + page.setId("1"); + page.setAuthor("user"); + when(identityManager.getOrCreateUserIdentity("user")).thenReturn(identity); PageVersion pageVersion = mock(PageVersion.class); + when(pageVersion.getParent()).thenReturn(page); when(noteService.getPublishedVersionByPageIdAndLang(anyLong(), nullable(String.class))).thenReturn(pageVersion); when(noteService.getNoteById(anyString())).thenReturn(mock(Page.class)); when(pageVersion.getId()).thenReturn("1"); @@ -276,6 +285,12 @@ public void testProcessUpgrade() throws Exception { when(startTimeProperty.getDate()).thenReturn(startTimePropertyCalendar); when(startTimePropertyCalendar.getTime()).thenReturn(mock(Date.class)); + Method method = newsArticlesUpgrade.getClass().getDeclaredMethod("convertNewsNodeToNewEntity", Node.class, Node.class); + method.setAccessible(true); + News news1 = (News) method.invoke(newsArticlesUpgrade, node1, null); + News news2 = (News) method.invoke(newsArticlesUpgrade, node2, null); + when(newsService.createNewsArticlePage(news1, "")).thenReturn(article); + when(newsService.createNewsArticlePage(news2, "")).thenReturn(article); // Run the processUpgrade method newsArticlesUpgrade.processUpgrade("1.0", "2.0"); @@ -286,4 +301,18 @@ public void testProcessUpgrade() throws Exception { verify(activityManager, times(1)).getActivity(any()); verify(activityManager, times(1)).updateActivity(any(ExoSocialActivity.class), eq(false)); } + + @Test + public void shouldProceedToUpgrade() { + SettingValue settingValue = mock(SettingValue.class); + UpgradePluginExecutionContext context = new UpgradePluginExecutionContext("0.9", 1); + when(settingService.get(any(), any(), anyString())).thenReturn(null); + newsArticlesUpgrade.shouldProceedToUpgrade("0.9", "1.0", context); + verify(settingService, times(1)).set(any(), any(), anyString(), any()); + reset(settingService); + when(settingService.get(any(), any(), anyString())).thenReturn(settingValue); + context.setVersion("1.2"); + newsArticlesUpgrade.shouldProceedToUpgrade("1.2", "1.0", context); + verify(settingService, times(0)).set(any(), any(), anyString(), any()); + } }