-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add an upgrade plugin for content pages properties migration - E…
…XO-73181 - Meeds-io/MIPs#128 (#240) Add an upgrade plugin for content pages properties(summary/illustrationId) migration
- Loading branch information
Showing
3 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
208 changes: 208 additions & 0 deletions
208
...rade-news/src/main/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgrade.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
/* | ||
* 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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
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; | ||
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<MetadataItem> metadataItems = metadataService.getMetadataItemsByFilter(metadataFilter, 0, 0); | ||
totalContentPagesPropertiesCount = metadataItems.size(); | ||
for (MetadataItem metadataItem : metadataItems) { | ||
if (metadataItem != null && !MapUtils.isEmpty(metadataItem.getProperties())) { | ||
Map<String, String> 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<String, String> 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); | ||
} | ||
} else { | ||
ignoredContentPagesPropertiesCount++; | ||
LOG.info("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); | ||
} | ||
processedContentPagesPropertiesCount++; | ||
LOG.info("ContentArticlePropertiesUpgrade: Processed content page properties: {}/{}", | ||
processedContentPagesPropertiesCount, | ||
totalContentPagesPropertiesCount); | ||
} | ||
} | ||
} 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={} ignored={} error={}. It took {} ms.", | ||
totalContentPagesPropertiesCount, | ||
processedContentPagesPropertiesCount, | ||
ignoredContentPagesPropertiesCount, | ||
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); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 145 additions & 0 deletions
145
...-news/src/test/java/org/exoplatform/news/upgrade/ContentArticlePropertiesUpgradeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
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 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<MetadataItem> 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(1)).updateMetadataItem(any(), anyLong()); | ||
verify(metadataService, times(2)).createMetadataItem(any(), any(), any(), anyLong()); | ||
} | ||
} |