From 51544d24ca740eb263293f74d110560d62667e42 Mon Sep 17 00:00:00 2001 From: Anwar khanfir <93767376+akhanfir@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:04:04 +0100 Subject: [PATCH] fix: Create a new upgrade plugin to add remove duplicated favorite applications - EXO-75399. (#258) Before this change, some users have duplicate favorite applications. To resolve this problem, create an upgrade plugin that fetches all duplicates and keeps one of each duplicate and removes the rest of the items. After this change, all duplicate favorite applications are removed for all users and one favorite application is kept from each duplicate. --- data-upgrade-app-center/pom.xml | 39 ++++++++ .../upgrade/CleanFavoriteApplications.java | 97 +++++++++++++++++++ .../resources/conf/portal/configuration.xml | 62 ++++++++++++ .../CleanFavoriteApplicationsTest.java | 69 +++++++++++++ pom.xml | 1 + 5 files changed, 268 insertions(+) create mode 100644 data-upgrade-app-center/pom.xml create mode 100644 data-upgrade-app-center/src/main/java/org/exoplatform/upgrade/CleanFavoriteApplications.java create mode 100644 data-upgrade-app-center/src/main/resources/conf/portal/configuration.xml create mode 100644 data-upgrade-app-center/src/test/java/org/exoplatform/upgrade/CleanFavoriteApplicationsTest.java diff --git a/data-upgrade-app-center/pom.xml b/data-upgrade-app-center/pom.xml new file mode 100644 index 00000000..856d5181 --- /dev/null +++ b/data-upgrade-app-center/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + org.exoplatform.addons.upgrade + upgrade + 7.0.x-maintenance-SNAPSHOT + + data-upgrade-app-center + jar + eXo Add-on:: Data Upgrade Add-on - App center + + 0.84 + + + + io.meeds.commons + commons-component-upgrade + provided + + + io.meeds.app-center + app-center-services + compile + + + \ No newline at end of file diff --git a/data-upgrade-app-center/src/main/java/org/exoplatform/upgrade/CleanFavoriteApplications.java b/data-upgrade-app-center/src/main/java/org/exoplatform/upgrade/CleanFavoriteApplications.java new file mode 100644 index 00000000..92ce2c0a --- /dev/null +++ b/data-upgrade-app-center/src/main/java/org/exoplatform/upgrade/CleanFavoriteApplications.java @@ -0,0 +1,97 @@ +package org.exoplatform.upgrade; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.exoplatform.commons.api.persistence.ExoTransactional; +import org.exoplatform.commons.persistence.impl.EntityManagerService; +import org.exoplatform.commons.upgrade.UpgradeProductPlugin; +import org.exoplatform.container.xml.InitParams; +import org.exoplatform.services.log.ExoLogger; +import org.exoplatform.services.log.Log; + +import io.meeds.appcenter.entity.ApplicationEntity; +import io.meeds.appcenter.entity.FavoriteApplicationEntity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; + +public class CleanFavoriteApplications extends UpgradeProductPlugin { + + private static final Log log = ExoLogger.getLogger(CleanFavoriteApplications.class.getName()); + + private EntityManagerService entityManagerService; + + public CleanFavoriteApplications(InitParams initParams, EntityManagerService entityManagerService) { + super(initParams); + this.entityManagerService = entityManagerService; + } + + @Override + public void processUpgrade(String oldVersion, String newVersion) { + long startupTime = System.currentTimeMillis(); + EntityManager entityManager = this.entityManagerService.getEntityManager(); + List duplicatedFavoriteAppsEntityList = getDuplicatedFavoriteAppsEntityList(entityManager); + if (duplicatedFavoriteAppsEntityList.isEmpty()) { + return; + } + log.info("Start upgrade of cleaning for favorite applications, {} favorite applications should be deleted", + duplicatedFavoriteAppsEntityList.size()); + Set uniqueUserNames = new HashSet<>(); + duplicatedFavoriteAppsEntityList.forEach(favoriteApplicationEntity -> uniqueUserNames.add((String) favoriteApplicationEntity[2])); + log.info("{} favorite applications duplicated for {} users", duplicatedFavoriteAppsEntityList.size(), uniqueUserNames.size()); + int favoriteApplicationCount = cleanFavoriteApps(entityManager, duplicatedFavoriteAppsEntityList); + log.info("End upgrade : Deleted {} favorite applications done it took {} ms", + favoriteApplicationCount, + System.currentTimeMillis() - startupTime); + } + + private List getDuplicatedFavoriteAppsEntityList(EntityManager entityManager) { + String selectQuery = "SELECT * FROM AC_FAVORITE_APPLICATION favoriteApp " + + "WHERE (favoriteApp.APPLICATION_ID, favoriteApp.USER_NAME) IN (" + + " SELECT favoriteApplication.APPLICATION_ID, favoriteApplication.USER_NAME " + + " FROM AC_FAVORITE_APPLICATION favoriteApplication " + + " GROUP BY favoriteApplication.APPLICATION_ID, favoriteApplication.USER_NAME " + " HAVING COUNT(*) > 1)"; + Query nativeQuery = entityManager.createNativeQuery(selectQuery); + return nativeQuery.getResultList(); + } + + protected int cleanFavoriteApps(EntityManager entityManager, List duplicatedFavoriteApplicationsEntityList) { + List duplicatedFavoriteAppsEntityList = + toFavoriteAppsEntityList(duplicatedFavoriteApplicationsEntityList); + List favoriteAppsEntityList = new ArrayList<>(); + int favoriteAppCount = 0; + for (FavoriteApplicationEntity favoriteApplicationEntity : duplicatedFavoriteAppsEntityList) { + FavoriteApplicationEntity favoriteAppEntityOfIdNull = + new FavoriteApplicationEntity(0L, + favoriteApplicationEntity.getApplication(), + favoriteApplicationEntity.getUserName(), + favoriteApplicationEntity.getOrder()); + if (favoriteAppsEntityList.contains(favoriteAppEntityOfIdNull)) { + deleteFavoriteApplication(entityManager, favoriteApplicationEntity.getId()); + favoriteAppCount += 1; + } else { + favoriteAppsEntityList.add(favoriteAppEntityOfIdNull); + } + } + return favoriteAppCount; + } + + List toFavoriteAppsEntityList(List objects) { + List favoriteAppsEntityList = new ArrayList<>(); + objects.forEach(object -> { + ApplicationEntity applicationEntity = new ApplicationEntity(); + applicationEntity.setId((Long) object[1]); + favoriteAppsEntityList.add(new FavoriteApplicationEntity((Long) object[0], applicationEntity, (String) object[2], null)); + }); + return favoriteAppsEntityList; + } + + @ExoTransactional + protected void deleteFavoriteApplication(EntityManager entityManager, Long favoriteApplicationId) { + String deleteQuery = "DELETE FROM AC_FAVORITE_APPLICATION WHERE ID = " + favoriteApplicationId; + Query query = entityManager.createNativeQuery(deleteQuery); + query.executeUpdate(); + } +} diff --git a/data-upgrade-app-center/src/main/resources/conf/portal/configuration.xml b/data-upgrade-app-center/src/main/resources/conf/portal/configuration.xml new file mode 100644 index 00000000..26380e50 --- /dev/null +++ b/data-upgrade-app-center/src/main/resources/conf/portal/configuration.xml @@ -0,0 +1,62 @@ + + + + + + org.exoplatform.commons.upgrade.UpgradeProductService + + CleanFavoriteApplications + addUpgradePlugin + org.exoplatform.upgrade.CleanFavoriteApplications + Remove duplicated favorite applications for all users + + + product.group.id + The groupId of the product + org.exoplatform.platform + + + plugin.upgrade.target.version + The plugin target version of selected groupId + 7.0.0 + + + plugin.execution.order + The plugin execution order + 10 + + + plugin.upgrade.execute.once + The plugin must be executed only once + true + + + plugin.upgrade.async.execution + The plugin will be executed in an asynchronous mode + true + + + + + diff --git a/data-upgrade-app-center/src/test/java/org/exoplatform/upgrade/CleanFavoriteApplicationsTest.java b/data-upgrade-app-center/src/test/java/org/exoplatform/upgrade/CleanFavoriteApplicationsTest.java new file mode 100644 index 00000000..992fe83b --- /dev/null +++ b/data-upgrade-app-center/src/test/java/org/exoplatform/upgrade/CleanFavoriteApplicationsTest.java @@ -0,0 +1,69 @@ +package org.exoplatform.upgrade; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.exoplatform.commons.persistence.impl.EntityManagerService; +import org.exoplatform.container.xml.InitParams; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; + +public class CleanFavoriteApplicationsTest { + + @Mock + private EntityManagerService entityManagerService; + + @Mock + private EntityManager entityManager; + + @Mock + private Query query; + + private CleanFavoriteApplications cleanFavoriteApplications; + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + InitParams initParams = new InitParams(); + cleanFavoriteApplications = new CleanFavoriteApplications(initParams, entityManagerService); + when(entityManagerService.getEntityManager()).thenReturn(entityManager); + } + + @Test + public void processUpgradeCleanDuplicatedFavoriteApps() { + List results = List.of(new Object[] { 1L, 100L, "user1" }, + new Object[] { 2L, 100L, "user1" }, + new Object[] { 3L, 101L, "test" }, + new Object[] { 4L, 101L, "test" }); + + when(entityManager.createNativeQuery(anyString())).thenReturn(query); + when(query.getResultList()).thenReturn(results); + when(query.executeUpdate()).thenReturn(2); + + cleanFavoriteApplications.processUpgrade("v1", "v1"); + + verify(entityManager, times(3)).createNativeQuery(anyString()); + verify(query, times(2)).executeUpdate(); + verify(entityManagerService, times(1)).getEntityManager(); + } + + @Test + public void processUpgradeNoDuplicatedFavoriteApps() { + List results = List.of(new Object[] { 1L, 100L, "user1" }, new Object[] { 2L, 101L, "test" }); + + when(entityManager.createNativeQuery(anyString())).thenReturn(query); + when(query.getResultList()).thenReturn(results); + + cleanFavoriteApplications.processUpgrade("v1", "v1"); + + verify(query, never()).executeUpdate(); + } +} diff --git a/pom.xml b/pom.xml index a0a39f73..e1d96f4e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ data-upgrade-processes-permissions data-upgrade-move-folders data-upgrade-recordings-permissions + data-upgrade-app-center data-upgrade-packaging