From 299ce06f54e3d7435110cc4c4950542e48657e01 Mon Sep 17 00:00:00 2001 From: Trisha Anand Date: Mon, 9 Dec 2024 14:03:09 +0530 Subject: [PATCH] fix: Only updating the required fields in User while generating usage pulse to avoid overwriting default fields. (#38030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … ## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /test all ### :mag: Cypress test results > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: > Commit: 9f3eebbb4b55da337e6bcb3d80c1bd8c6fbf8e96 > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Mon, 09 Dec 2024 08:27:39 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit ## Release Notes - **New Features** - Introduced methods to update user records directly by ID, enhancing user management capabilities. - Added functionality to update user information without permission checks for administrative purposes. - **Bug Fixes** - Improved error handling for user updates, ensuring robustness in user management operations. - **Documentation** - Updated documentation to reflect new methods and their functionalities in user services. --- .../repositories/ce/CustomUserRepositoryCE.java | 3 +++ .../ce/CustomUserRepositoryCEImpl.java | 11 +++++++++++ .../services/ce/UsagePulseServiceCEImpl.java | 16 ++++++++++------ .../server/services/ce/UserServiceCE.java | 3 +++ .../server/services/ce/UserServiceCEImpl.java | 10 ++++++++++ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCE.java index d071b5e04e7e..6ceef7aed4a5 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCE.java @@ -3,6 +3,7 @@ import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.User; import com.appsmith.server.repositories.AppsmithRepository; +import org.springframework.data.mongodb.core.query.UpdateDefinition; import reactor.core.publisher.Mono; public interface CustomUserRepositoryCE extends AppsmithRepository { @@ -12,4 +13,6 @@ public interface CustomUserRepositoryCE extends AppsmithRepository { Mono findByEmailAndTenantId(String email, String tenantId); Mono isUsersEmpty(); + + Mono updateById(String id, UpdateDefinition updateObj); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCEImpl.java index 8508431a7257..b09ac27cc259 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCEImpl.java @@ -3,11 +3,14 @@ import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.User; +import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.ce.bridge.Bridge; import com.appsmith.server.helpers.ce.bridge.BridgeQuery; import com.appsmith.server.projections.IdOnly; import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.mongodb.core.query.UpdateDefinition; import reactor.core.publisher.Mono; import java.util.HashSet; @@ -50,4 +53,12 @@ protected Set getSystemGeneratedUserEmails() { systemGeneratedEmails.add(FieldName.ANONYMOUS_USER); return systemGeneratedEmails; } + + @Override + public Mono updateById(String id, UpdateDefinition updateObj) { + if (id == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } + return queryBuilder().byId(id).updateFirst(updateObj); + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UsagePulseServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UsagePulseServiceCEImpl.java index 1d15be8c9007..55027b06933b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UsagePulseServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UsagePulseServiceCEImpl.java @@ -7,6 +7,8 @@ import com.appsmith.server.dtos.UsagePulseDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; +import com.appsmith.server.helpers.ce.bridge.Bridge; +import com.appsmith.server.helpers.ce.bridge.BridgeUpdate; import com.appsmith.server.repositories.UsagePulseRepository; import com.appsmith.server.services.ConfigService; import com.appsmith.server.services.SessionUserService; @@ -83,19 +85,21 @@ public Mono createPulse(UsagePulseDTO usagePulseDTO) { return save(usagePulse); } usagePulse.setIsAnonymousUser(false); - User updateUser = new User(); + BridgeUpdate updateUserObj = Bridge.update(); + String hashedEmail = user.getHashedEmail(); if (StringUtils.isEmpty(hashedEmail)) { hashedEmail = DigestUtils.sha256Hex(user.getEmail()); // Hashed user email is stored to user for future mapping of user and pulses - updateUser.setHashedEmail(hashedEmail); + updateUserObj.set(User.Fields.hashedEmail, hashedEmail); } usagePulse.setUser(hashedEmail); - updateUser.setLastActiveAt(Instant.now()); - // Avoid updating policies - updateUser.setPolicies(null); - return userService.updateWithoutPermission(user.getId(), updateUser).then(save(usagePulse)); + updateUserObj.set(User.Fields.lastActiveAt, Instant.now()); + + return userService + .updateWithoutPermission(user.getId(), updateUserObj) + .then(save(usagePulse)); }); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCE.java index 3c489065891f..2bdb85f67803 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCE.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCE.java @@ -8,6 +8,7 @@ import com.appsmith.server.dtos.UserSignupDTO; import com.appsmith.server.dtos.UserUpdateDTO; import com.appsmith.server.services.CrudService; +import org.springframework.data.mongodb.core.query.UpdateDefinition; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -30,6 +31,8 @@ public interface UserServiceCE extends CrudService { Mono userCreate(User user, boolean isAdminUser); + Mono updateWithoutPermission(String id, UpdateDefinition updateObj); + Mono updateCurrentUser(UserUpdateDTO updates, ServerWebExchange exchange); Mono isUsersEmpty(); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java index 9cede7c2f620..35d24c352aa4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java @@ -43,6 +43,7 @@ import org.apache.hc.core5.http.message.BasicNameValuePair; import org.apache.hc.core5.net.WWWFormCodec; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.query.UpdateDefinition; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.ReactiveSecurityContextHolder; @@ -568,6 +569,15 @@ public Mono updateWithoutPermission(String id, User update) { return userFromRepository.flatMap(existingUser -> this.update(existingUser, update)); } + @Override + public Mono updateWithoutPermission(String id, UpdateDefinition updateObj) { + Mono userFromRepository = repository + .findById(id) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER, id))); + + return userFromRepository.flatMap(existingUser -> repository.updateById(id, updateObj)); + } + private Mono update(User existingUser, User userUpdate) { // The password is being updated. Hash it first and then store it