Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement an upgrade plugin for content articles attachments migration and adapt the NewsArticleUpgradePlugin - EXO-74446 #253

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data-upgrade-news/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<artifactId>ecms-ext-authoring-services</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.exoplatform.ecms</groupId>
<artifactId>ecms-core-services</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.meeds.content</groupId>
<artifactId>content-service</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* 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 jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import org.apache.commons.lang3.StringUtils;
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.persistence.impl.EntityManagerService;
import org.exoplatform.commons.upgrade.UpgradeProductPlugin;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.component.RequestLifeCycle;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.attachments.storage.AttachmentStorage;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.wiki.model.PageVersion;
import org.exoplatform.wiki.service.NoteService;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class ArticleAttachmentsUpgradePlugin extends UpgradeProductPlugin {

private static final Log LOG = ExoLogger.getLogger(ArticleAttachmentsUpgradePlugin.class);

private SettingService settingService;

private NoteService noteService;

private EntityManagerService entityManagerService;

private AttachmentStorage attachmentStorage;

private final PortalContainer container;

private static final String ARTICLES_UPGRADE_EXECUTED_KEY = "articlesUpgradeExecuted";

private static final String ARTICLES_UPGRADE_PLUGIN_NAME = "NewsArticlesUpgradePlugin";

public ArticleAttachmentsUpgradePlugin(InitParams initParams,
EntityManagerService entityManagerService,
SettingService settingService,
NoteService noteService,
AttachmentStorage attachmentStorage, PortalContainer container) {
super(initParams);
this.settingService = settingService;
this.entityManagerService = entityManagerService;
this.noteService = noteService;
this.attachmentStorage = attachmentStorage;
this.container = container;
}

@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);
}

@Override
public void processUpgrade(String oldVersion, String newVersion) {
ExoContainerContext.setCurrentContainer(container);
long startupTime = System.currentTimeMillis();
int attachmentCount = 0;
int articleCount = 0;
boolean transactionStarted = false;
RequestLifeCycle.begin(this.entityManagerService);
EntityManager entityManager = this.entityManagerService.getEntityManager();
try {
if (!entityManager.getTransaction().isActive()) {
entityManager.getTransaction().begin();
transactionStarted = true;
}

List<Object[]> results = getAttachments(entityManager);
if (results.isEmpty()) {
return;
}
LOG.info("Start updating article attachments, {} articles should be updated", results.size());
for (Object[] result : results) {
String versionId = (String) result[0];
String originalVersionId = versionId;
String propertyValue = (String) result[1]; // get the value
PageVersion pageVersion = noteService.getPageVersionById(Long.valueOf(versionId));
if (pageVersion != null && pageVersion.getParent() != null && StringUtils.isNotEmpty(pageVersion.getParent().getId())) {
PageVersion latestVersion =
noteService.getPublishedVersionByPageIdAndLang(Long.valueOf(pageVersion.getParent().getId()),
null);
versionId = latestVersion.getId();
}
String[] attachmentIds = propertyValue.split(";");
attachmentCount += linkAttachmentsToEntity(versionId, attachmentIds);
articleCount += 1;
LOG.info("{} attachments linked to {} articles", attachmentCount, articleCount);

removeAttachmentProperty(originalVersionId, entityManager, transactionStarted);
}
if (transactionStarted && entityManager.getTransaction().isActive()) {
entityManager.getTransaction().commit();
}
LOG.info("Updating article attachments done it took {} ms", System.currentTimeMillis() - startupTime);
} catch (Exception e) {
if (transactionStarted && entityManager.getTransaction().isActive() && entityManager.getTransaction().getRollbackOnly()) {
entityManager.getTransaction().rollback();
}
LOG.error("Error when processing article attachments upgrade plugin", e);
} finally {
RequestLifeCycle.end();
}
}

private int linkAttachmentsToEntity(String articleId, String[] attachmentIds) {
AtomicInteger linkedAttachments = new AtomicInteger(0);

Arrays.stream(attachmentIds).forEach(id -> {
try {
// Link the attachment to the entity
this.attachmentStorage.linkAttachmentToEntity(Long.parseLong(articleId), "WIKI_PAGE_VERSIONS", id);
linkedAttachments.incrementAndGet();
} catch (Exception e) {
LOG.error("Error when linking attachment with id {} to entity with id {}", id, articleId, e);
}
});

return linkedAttachments.get();
}

private void removeAttachmentProperty(String articleId, EntityManager entityManager, boolean transactionStarted) {

String deleteQuery = "DELETE FROM SOC_METADATA_ITEMS_PROPERTIES "
+ "WHERE metadata_item_id IN (SELECT metadata_item_id FROM SOC_METADATA_ITEMS WHERE object_id = '" + articleId + "')"
+ " AND name = 'attachmentsIds'";

Query query = entityManager.createNativeQuery(deleteQuery);
query.executeUpdate();
}

private List<Object[]> getAttachments(EntityManager entityManager) {
String selectQuery = "SELECT mi.object_id, p.value " + "FROM SOC_METADATA_ITEMS mi " + "JOIN SOC_METADATA_ITEMS_PROPERTIES p "
+ "ON mi.metadata_item_id = p.metadata_item_id " + "WHERE mi.object_type = 'newsPageVersion' "
+ "AND p.name = 'attachmentsIds' " + "AND mi.object_id IS NOT NULL " + "AND mi.object_id != '' "
+ "AND p.value IS NOT NULL " + "AND p.value != '';";
Query nativeQuery = entityManager.createNativeQuery(selectQuery);
return nativeQuery.getResultList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.commons.collections4.ListUtils;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.exoplatform.commons.api.settings.SettingService;
import org.exoplatform.commons.api.settings.SettingValue;
import org.exoplatform.commons.api.settings.data.Context;
Expand All @@ -52,6 +53,7 @@
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.commons.utils.HTMLSanitizer;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.attachments.storage.AttachmentStorage;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.ext.app.SessionProviderService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
Expand Down Expand Up @@ -110,6 +112,8 @@ public class NewsArticlesUpgrade extends UpgradeProductPlugin {

private SettingService settingService;

private AttachmentStorage attachmentStorage;

private int migratedNewsArticlesCount = 0;

public static final MetadataType NEWS_METADATA_TYPE = new MetadataType(1000, "news");
Expand Down Expand Up @@ -138,6 +142,7 @@ public NewsArticlesUpgrade(InitParams initParams,
NoteService noteService,
IdentityManager identityManager,
IndexingService indexingService,
AttachmentStorage attachmentStorage,
SettingService settingService) {
super(initParams);
this.repositoryService = repositoryService;
Expand All @@ -151,6 +156,7 @@ public NewsArticlesUpgrade(InitParams initParams,
this.identityManager = identityManager;
this.indexingService = indexingService;
this.settingService = settingService;
this.attachmentStorage = attachmentStorage;
}

@Override
Expand Down Expand Up @@ -279,7 +285,7 @@ public int manageNewsArticles(List<Node> newsArticlesNodes, Session session) thr
}
PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(article.getId()), null);
setArticleIllustration(pageVersion.getParent(), article.getSpaceId(), newsArticleNode, "notePage");
setArticleAttachments(pageVersion.getId(), article.getSpaceId(), newsArticleNode, "newsPageVersion");
setArticleAttachments(pageVersion.getId(), newsArticleNode);
/* upgrade news id for news targets and favorite metadatata items */
setArticleMetadatasItems(article.getId(), newsArticleNode.getUUID());
if (getStringProperty(newsArticleNode, "publication:currentState").equals("published")) {
Expand Down Expand Up @@ -330,7 +336,7 @@ public int manageNewsArticles(List<Node> newsArticlesNodes, Session session) thr
}
PageVersion pageVersion = noteService.getPublishedVersionByPageIdAndLang(Long.parseLong(article.getId()), null);
setArticleIllustration(pageVersion.getParent(), article.getSpaceId(), publishedNode, "notePage");
setArticleAttachments(pageVersion.getId(), article.getSpaceId(), publishedNode, "newsPageVersion");
setArticleAttachments(pageVersion.getId(), publishedNode);
/* upgrade news id for news targets and favorite metadatata items */
setArticleMetadatasItems(article.getId(), newsArticleNode.getUUID());
setArticleActivities(article, publishedNode);
Expand Down Expand Up @@ -544,28 +550,14 @@ private void setArticleViews(News article, Node newsNode) throws RepositoryExcep
}

private void setArticleAttachments(String articleId,
String spaceId,
Node newsNode,
String articleObjectType) throws RepositoryException {
Node newsNode) throws RepositoryException {
if (newsNode.hasProperty("exo:attachmentsIds")) {
Property attachmentsIdsProperty = newsNode.getProperty("exo:attachmentsIds");
String attachmentsIds = "";
for (Value value : attachmentsIdsProperty.getValues()) {
String attachmentId = value.getString();
attachmentsIds += attachmentId + ";";
}
MetadataObject articleMetaDataObject = new MetadataObject(articleObjectType, articleId, null, Long.parseLong(spaceId));
MetadataItem articleMetadataItem = metadataService.getMetadataItemsByMetadataAndObject(NEWS_METADATA_KEY,
articleMetaDataObject)
.get(0);
if (articleMetadataItem != null) {
Map<String, String> articleMetadataItemProperties = articleMetadataItem.getProperties();
if (articleMetadataItemProperties == null) {
articleMetadataItemProperties = new HashMap<>();
if (StringUtils.isNotEmpty(attachmentId) && StringUtils.isNotEmpty(articleId)) {
attachmentStorage.linkAttachmentToEntity(Long.valueOf(articleId), "WIKI_PAGE_VERSIONS", attachmentId);
}
articleMetadataItemProperties.put("attachmentsIds", attachmentsIds);
articleMetadataItem.setProperties(articleMetadataItemProperties);
metadataService.updateMetadataItem(articleMetadataItem, articleMetadataItem.getCreatorId());
}
}
}
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 @@ -81,6 +81,39 @@
</value-param>
</init-params>
</component-plugin>
<component-plugin profiles="content">
<name>ContentArticleAttachmentsUpgrade</name>
<set-method>addUpgradePlugin</set-method>
<type>org.exoplatform.news.upgrade.ArticleAttachmentsUpgradePlugin</type>
<description>Migrate content attachments from metadata properties to attachments context</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