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..3a8ffbbf3
--- /dev/null
+++ b/data-upgrade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java
@@ -0,0 +1,194 @@
+/*
+ * 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.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 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";
+
+ public ContentArticlePropertiesUpgrade(InitParams initParams,
+ NoteService noteService,
+ MetadataService metadataService,
+ IdentityManager identityManager,
+ SpaceService spaceService,
+ UserACL userACL) {
+ super(initParams);
+ this.noteService = noteService;
+ this.metadataService = metadataService;
+ this.identityManager = identityManager;
+ this.spaceService = spaceService;
+ this.userACL = userACL;
+ }
+
+ @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;
+ 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);
+ Map noteProperties = new HashMap<>();
+ long creatorId = Long.parseLong(identityManager.getOrCreateUserIdentity(page.getAuthor()).getId());
+ if (noteMetadataItem != null && noteMetadataItem.getProperties() != null) {
+ noteProperties = noteMetadataItem.getProperties();
+ }
+ if (noteProperties.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));
+
+ if (noteMetadataItem != null) {
+ noteMetadataItem.setProperties(noteProperties);
+ metadataService.updateMetadataItem(noteMetadataItem, creatorId);
+ } else {
+ metadataService.createMetadataItem(noteMetadataObject, NOTES_METADATA_KEY, noteProperties, creatorId);
+ }
+ processedContentPagesPropertiesCount++;
+ LOG.info("ContentArticlePropertiesUpgrade: Processed content page properties: {}/{}",
+ totalContentPagesPropertiesCount,
+ processedContentPagesPropertiesCount);
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("An error occurred while Migrating content pages properties:", e);
+ }
+ notMigratedContentPagesPropertiesCount = totalContentPagesPropertiesCount - processedContentPagesPropertiesCount;
+ if (notMigratedContentPagesPropertiesCount == 0) {
+ LOG.info("End ContentArticlePropertiesUpgrade successful migration: total={} succeeded={} error={}. It took {} ms.",
+ totalContentPagesPropertiesCount,
+ processedContentPagesPropertiesCount,
+ notMigratedContentPagesPropertiesCount,
+ (System.currentTimeMillis() - startupTime));
+ } else {
+ LOG.warn("End ContentArticlePropertiesUpgrade with some errors: total={} succeeded={} error={}. It took {} ms."
+ + " The not migrated news articles will be processed again next startup.",
+ totalContentPagesPropertiesCount,
+ processedContentPagesPropertiesCount,
+ notMigratedContentPagesPropertiesCount,
+ (System.currentTimeMillis() - startupTime));
+ throw new IllegalStateException("Some content page properties weren't migrated successfully. It will be re-attempted next startup");
+ }
+ }
+
+ 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/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..5cf834931
--- /dev/null
+++ b/data-upgrade-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java
@@ -0,0 +1,136 @@
+package org.exoplatform.news.upgrade;
+
+import io.meeds.notes.model.NoteMetadataObject;
+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 java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+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;
+
+ 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);
+ }
+
+ @Test
+ public void processUpgrade() throws Exception {
+ MetadataItem page = new MetadataItem();
+ MetadataItem draftOfPage = 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"));
+
+ 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 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, 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, 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(1)).updateMetadataItem(any(), anyLong());
+ verify(metadataService, times(2)).createMetadataItem(any(), any(), any(), anyLong());
+ }
+}