Skip to content

Commit

Permalink
feat: Add an upgrade plugin for content pages properties migration - E…
Browse files Browse the repository at this point in the history
…XO-73181 - Meeds-io/MIPs#128 (#240)

Add an upgrade plugin for content pages properties(summary/illustrationId) migration
  • Loading branch information
hakermi committed Aug 1, 2024
1 parent 25552b2 commit 4102bad
Show file tree
Hide file tree
Showing 5 changed files with 396 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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 <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;
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);
}
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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;

import io.meeds.notes.model.NotePageProperties;
import org.apache.commons.collections4.ListUtils;

import org.exoplatform.commons.file.model.FileItem;
Expand All @@ -56,6 +57,7 @@
import org.exoplatform.services.wcm.publication.lifecycle.stageversion.StageAndVersionPublicationConstant;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.manager.ActivityManager;
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.core.utils.MentionUtils;
Expand Down Expand Up @@ -95,6 +97,8 @@ public class NewsArticlesUpgrade extends UpgradeProductPlugin {
private NoteService noteService;

private IndexingService indexingService;

private IdentityManager identityManager;

private int migratedNewsArticlesCount = 0;

Expand All @@ -114,6 +118,7 @@ public NewsArticlesUpgrade(InitParams initParams,
MetadataService metadataService,
FileService fileService,
NoteService noteService,
IdentityManager identityManager,
IndexingService indexingService) {
super(initParams);
this.repositoryService = repositoryService;
Expand All @@ -124,6 +129,7 @@ public NewsArticlesUpgrade(InitParams initParams,
this.metadataService = metadataService;
this.fileService = fileService;
this.noteService = noteService;
this.identityManager = identityManager;
this.indexingService = indexingService;
}

Expand Down Expand Up @@ -216,6 +222,13 @@ public int manageNewsArticles(List<Node> 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()));
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");
setArticleAttachments(pageVersion.getId(), article.getSpaceId(), newsArticleNode, "newsPageVersion");
Expand Down Expand Up @@ -251,6 +264,13 @@ public int manageNewsArticles(List<Node> newsArticlesNodes, Session session) thr
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,
article.getLang(),
Long.valueOf(identityManager.getOrCreateUserIdentity(news.getAuthor()).getId()));
}
PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(article.getId()), null);
setArticleIllustration(pageVersion.getId(), article.getSpaceId(), publishedNode, "newsPageVersion");
setArticleAttachments(pageVersion.getId(), article.getSpaceId(), publishedNode, "newsPageVersion");
Expand Down Expand Up @@ -295,6 +315,9 @@ private News convertNewsNodeToNewEntity(Node newsNode, Node newsVersionNode) thr
String portalOwner = CommonsUtils.getCurrentPortalOwner();
news.setTitle(getStringProperty(newsVersionNode != null ? newsVersionNode : newsNode, "exo:title"));
news.setName(news.getTitle() + "_" + newsNode.getUUID());
NotePageProperties properties = new NotePageProperties();
properties.setSummary(getStringProperty(newsVersionNode != null ? newsVersionNode : newsNode, "exo:summary"));
news.setProperties(properties);
String body = getStringProperty(newsVersionNode != null ? newsVersionNode : newsNode, "exo:body");
String sanitizedBody = HTMLSanitizer.sanitize(body);
sanitizedBody = sanitizedBody.replaceAll("&#64;", "@");
Expand Down
33 changes: 33 additions & 0 deletions data-upgrade-news/src/main/resources/conf/portal/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,39 @@
</value-param>
</init-params>
</component-plugin>
<component-plugin profiles="content">
<name>ContentArticlePropertiesUpgrade</name>
<set-method>addUpgradePlugin</set-method>
<type>org.exoplatform.news.upgrade.ContentArticlePropertiesUpgrade</type>
<description>Migrate content properties from content to note</description>
<init-params>
<value-param>
<name>product.group.id</name>
<description>The groupId of the product</description>
<value>org.exoplatform.platform</value>
</value-param>
<value-param>
<name>plugin.execution.order</name>
<description>The plugin execution order</description>
<value>1</value>
</value-param>
<value-param>
<name>plugin.upgrade.execute.once</name>
<description>Execute this upgrade plugin only once</description>
<value>true</value>
</value-param>
<value-param>
<name>plugin.upgrade.async.execution</name>
<description>The plugin will be executed in an asynchronous mode</description>
<value>true</value>
</value-param>
<value-param>
<name>plugin.upgrade.target.version</name>
<description>Target version of the plugin</description>
<value>7.0.0</value>
</value-param>
</init-params>
</component-plugin>
</external-component-plugins>

</configuration>
Loading

0 comments on commit 4102bad

Please sign in to comment.