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

fix: Create a new upgrade plugin to add remove duplicated favorite applications - EXO-75399 - Meeds-io/meeds#2683. #371

Merged
merged 1 commit into from
Dec 16, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package io.meeds.appcenter.upgrade;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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.container.xml.ValueParam;
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;

@Component
public class CleanFavoriteApplications extends UpgradeProductPlugin {

private static final Log log = ExoLogger.getLogger(CleanFavoriteApplications.class.getName());

private static final String GROUP_ID_PARAM = "product.group.id";

private static final String TARGET_VERSION_PARAM = "plugin.upgrade.target.version";

private static final String EXECUTION_ORDER_PARAM = "plugin.execution.order";

private static final String EXECUTION_ONCE_PARAM = "plugin.upgrade.execute.once";

private static final String ASYNC_EXECUTION_PARAM = "plugin.upgrade.async.execution";

private static final String PLUGIN_NAME = "CleanFavoriteApplications";

private final EntityManagerService entityManagerService;

@Autowired
public CleanFavoriteApplications(EntityManagerService entityManagerService) {
super(getInitParams());
this.entityManagerService = entityManagerService;
}

@Override
public void processUpgrade(String oldVersion, String newVersion) {
long startupTime = System.currentTimeMillis();
EntityManager entityManager = this.entityManagerService.getEntityManager();
List<Object[]> duplicatedFavoriteAppsEntityList = getDuplicatedFavoriteAppsEntityList(entityManager);
if (duplicatedFavoriteAppsEntityList.isEmpty()) {
return;
}
log.info("Start upgrade of cleaning for favorite applications, {} favorite applications should be deleted",
duplicatedFavoriteAppsEntityList.size());
Set<String> 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<Object[]> 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<Object[]> duplicatedFavoriteApplicationsEntityList) {
List<FavoriteApplicationEntity> duplicatedFavoriteAppsEntityList =
toFavoriteAppsEntityList(duplicatedFavoriteApplicationsEntityList);
List<FavoriteApplicationEntity> 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<FavoriteApplicationEntity> toFavoriteAppsEntityList(List<Object[]> objects) {
List<FavoriteApplicationEntity> 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();
}

private static InitParams getInitParams() {
InitParams initParams = new InitParams();
ValueParam groupIdParam = new ValueParam();
groupIdParam.setName(GROUP_ID_PARAM);
groupIdParam.setValue("org.exoplatform.platform");
initParams.addParameter(groupIdParam);

ValueParam targetVersionParam = new ValueParam();
targetVersionParam.setName(TARGET_VERSION_PARAM);
targetVersionParam.setValue("7.0.0");
initParams.addParameter(targetVersionParam);

ValueParam executionOrderParam = new ValueParam();
executionOrderParam.setName(EXECUTION_ORDER_PARAM);
executionOrderParam.setValue("10");
initParams.addParameter(executionOrderParam);

ValueParam executionOnceParam = new ValueParam();
executionOnceParam.setName(EXECUTION_ONCE_PARAM);
executionOnceParam.setValue("true");
initParams.addParameter(executionOnceParam);

ValueParam asyncExecutionParam = new ValueParam();
asyncExecutionParam.setName(ASYNC_EXECUTION_PARAM);
asyncExecutionParam.setValue("true");
initParams.addParameter(asyncExecutionParam);

return initParams;
}

@Override
public String getName() {
return PLUGIN_NAME;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package io.meeds.appcenter.upgrade;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

import org.exoplatform.commons.persistence.impl.EntityManagerService;

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;

@SpringBootTest(classes = { CleanFavoriteApplications.class })
@ExtendWith(MockitoExtension.class)
public class CleanFavoriteApplicationsTest {

@MockBean
private EntityManagerService entityManagerService;

@MockBean
private EntityManager entityManager;

@MockBean
private Query query;

@Autowired
private CleanFavoriteApplications cleanFavoriteApplications;

@BeforeEach
void setUp() {
cleanFavoriteApplications = new CleanFavoriteApplications(entityManagerService);
when(entityManagerService.getEntityManager()).thenReturn(entityManager);
when(entityManager.createNativeQuery(anyString())).thenReturn(query);
}

@Test
void processUpgradeCleanDuplicatedFavoriteApps() {
List<Object[]> results = List.of(new Object[] { 1L, 100L, "user1" },
new Object[] { 2L, 100L, "user1" },
new Object[] { 3L, 101L, "test" },
new Object[] { 4L, 101L, "test" });

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
void processUpgradeNoDuplicatedFavoriteApps() {
List<Object[]> results = List.of(new Object[] { 1L, 100L, "user1" }, new Object[] { 2L, 101L, "test" });

when(query.getResultList()).thenReturn(results);

cleanFavoriteApplications.processUpgrade("v1", "v1");

verify(query, never()).executeUpdate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--

Copyright (C) 2003-2021 eXo Platform SAS.

This is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This software 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.

-->
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_3.xsd http://www.exoplatform.org/xml/ns/kernel_1_3.xsd"
xmlns="http://www.exoplatform.org/xml/ns/kernel_1_3.xsd">

<external-component-plugins>
<target-component>org.exoplatform.commons.upgrade.UpgradeProductService</target-component>
<component-plugin profiles="app-center">
<name>CleanFavoriteApplications</name>
<set-method>addUpgradePlugin</set-method>
<type>io.meeds.appcenter.upgrade.CleanFavoriteApplications</type>
<description>Remove duplicated favorite applications for all users</description>
</component-plugin>
</external-component-plugins>
</configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
<import>war:/conf/app-center/portal-configuration.xml</import>
<import>war:/conf/app-center/bundle-configuration.xml</import>
<import>war:/conf/app-center/search-configuration.xml</import>

<import>war:/conf/app-center/upgrade-configuration.xml</import>
</configuration>
Loading