diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CollectionUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CollectionUtils.java index e6b59a1b00..785cae029f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CollectionUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/CollectionUtils.java @@ -2,10 +2,12 @@ package com.appsmith.server.helpers; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; public class CollectionUtils { @@ -65,4 +67,29 @@ public class CollectionUtils { list.addAll(set); } + /** + * Finds all the elements which do not exist in the intersection between the two sets + * @param set1 + * @param set2 + * @return + * @param + */ + public static Set findSymmetricDiff(Set set1, Set set2) { + Map map = new HashMap<>(); + set1.forEach(e -> putKeyForFindingSymmetricDiff(map, e)); + set2.forEach(e -> putKeyForFindingSymmetricDiff(map, e)); + return map.entrySet().stream() + .filter(e -> e.getValue() == 1) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + } + + private static void putKeyForFindingSymmetricDiff(Map map, T key) { + if (map.containsKey(key)) { + map.replace(key, Integer.MAX_VALUE); + } else { + map.put(key, 1); + } + } + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java index 3a11d3f109..80f2dd675e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java @@ -52,6 +52,7 @@ import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.PolicyUtils; import com.appsmith.server.helpers.TextUtils; +import com.appsmith.server.repositories.CacheableRepositoryHelper; import com.appsmith.server.repositories.NewPageRepository; import com.appsmith.server.repositories.UserRepository; import com.appsmith.server.services.WorkspaceService; @@ -109,10 +110,12 @@ import static com.appsmith.server.acl.AclPermission.RESET_PASSWORD_USERS; import static com.appsmith.server.constants.EnvVariables.APPSMITH_ADMIN_EMAILS; import static com.appsmith.server.constants.FieldName.DEFAULT_PERMISSION_GROUP; import static com.appsmith.server.constants.FieldName.PERMISSION_GROUP_ID; +import static com.appsmith.server.helpers.CollectionUtils.findSymmetricDiff; import static com.appsmith.server.migrations.DatabaseChangelog.dropIndexIfExists; import static com.appsmith.server.migrations.DatabaseChangelog.ensureIndexes; import static com.appsmith.server.migrations.DatabaseChangelog.getUpdatedDynamicBindingPathList; import static com.appsmith.server.migrations.DatabaseChangelog.makeIndex; +import static com.appsmith.server.migrations.MigrationHelperMethods.evictPermissionCacheForUsers; import static com.appsmith.server.repositories.BaseAppsmithRepositoryImpl.fieldName; import static java.lang.Boolean.TRUE; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -2288,7 +2291,7 @@ public class DatabaseChangelog2 { } @ChangeSet(order = "033", id = "update-super-users", author = "", runAlways = true) - public void updateSuperUsers(MongockTemplate mongockTemplate) { + public void updateSuperUsers(MongockTemplate mongockTemplate, CacheableRepositoryHelper cacheableRepositoryHelper) { // Read the admin emails from the environment and update the super users accordingly String adminEmailsStr = System.getenv(String.valueOf(APPSMITH_ADMIN_EMAILS)); @@ -2325,6 +2328,9 @@ public class DatabaseChangelog2 { }) .collect(Collectors.toSet()); + Set oldSuperUsers = instanceAdminPG.getAssignedToUserIds(); + Set updatedUserIds = findSymmetricDiff(oldSuperUsers, userIds); + evictPermissionCacheForUsers(updatedUserIds, mongockTemplate, cacheableRepositoryHelper); instanceAdminPG.setAssignedToUserIds(userIds); mongockTemplate.save(instanceAdminPG); } @@ -2334,6 +2340,7 @@ public class DatabaseChangelog2 { user.setEmail(email); user.setIsEnabled(false); user.setTenantId(tenantId); + user.setCreatedAt(Instant.now()); user = mongockTemplate.save(user); // Assign the user to the default permissions diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java index 22b0806c65..1f17589bc2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java @@ -4,10 +4,16 @@ import com.appsmith.external.models.InvisibleActionFields; import com.appsmith.server.constants.ResourceModes; import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.NewAction; +import com.appsmith.server.domains.QUser; +import com.appsmith.server.domains.User; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.dtos.ApplicationJson; import com.appsmith.server.helpers.CollectionUtils; +import com.appsmith.server.repositories.CacheableRepositoryHelper; +import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.decorator.impl.MongockTemplate; import org.apache.commons.lang.StringUtils; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; import java.time.Instant; import java.util.ArrayList; @@ -19,6 +25,7 @@ import java.util.stream.Collectors; import static com.appsmith.server.constants.ResourceModes.EDIT; import static com.appsmith.server.constants.ResourceModes.VIEW; +import static com.appsmith.server.repositories.BaseAppsmithRepositoryImpl.fieldName; public class MigrationHelperMethods { // Migration for deprecating archivedAt field in ActionDTO @@ -165,4 +172,22 @@ public class MigrationHelperMethods { }); } } + + public static void evictPermissionCacheForUsers(Set userIds, + MongockTemplate mongockTemplate, + CacheableRepositoryHelper cacheableRepositoryHelper) { + + if (userIds == null || userIds.isEmpty()) { + // Nothing to do here. + return; + } + + userIds.forEach(userId -> { + Query query = new Query(new Criteria(fieldName(QUser.user.id)).is(userId)); + User user = mongockTemplate.findOne(query, User.class); + // blocking call for cache eviction to ensure its subscribed immediately before proceeding further. + cacheableRepositoryHelper.evictPermissionGroupsUser(user.getEmail(), user.getTenantId()) + .block(); + }); + } }