hunk.code_window:             analyticsProperties.remove("request");
           }
           TrackMessage.Builder messageBuilder = TrackMessage.builder(event).userId(userId);
  
hunk.labels: add keep keep keep
hunk.after_edit:             if (!CollectionUtils.isEmpty(analyticsProperties)) {
                   for (final Map.Entry<String, Object> entry : analyticsProperties.entrySet()) {
                       if (entry.getValue() == null) {
                           analyticsProperties.put(entry.getKey(), "");
                       } else if (entry.getValue().equals(userId)) {
                           analyticsProperties.put(entry.getKey(), hashedUserId);
                       }
                   }
               }
               userId = hashedUserId;
  
hunk.file_path: app/server/appsmith-server/src/main/java/com/appsmith/server/services/AnalyticsService.java
hunk.type: add
file: package com.appsmith.server.services;
  
  import com.appsmith.external.models.Policy;
  import com.appsmith.server.acl.AclPermission;
  import com.appsmith.server.acl.AppsmithRole;
  import com.appsmith.server.acl.PolicyGenerator;
  import com.appsmith.server.constants.FieldName;
  import com.appsmith.server.domains.Application;
  import com.appsmith.server.domains.CommentThread;
  import com.appsmith.server.domains.Organization;
  import com.appsmith.server.domains.User;
  import com.appsmith.server.domains.UserRole;
  import com.appsmith.server.exceptions.AppsmithError;
  import com.appsmith.server.helpers.PolicyUtils;
  import com.appsmith.server.repositories.ApplicationRepository;
  import com.appsmith.server.repositories.CommentThreadRepository;
  import com.appsmith.server.repositories.OrganizationRepository;
  import com.appsmith.server.repositories.UserRepository;
  import lombok.extern.slf4j.Slf4j;
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  import org.junit.runner.RunWith;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.context.SpringBootTest;
  import org.springframework.security.test.context.support.WithUserDetails;
  import org.springframework.test.annotation.DirtiesContext;
  import org.springframework.test.context.junit4.SpringRunner;
  import reactor.core.publisher.Mono;
  import reactor.test.StepVerifier;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_ADMIN;
  import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_DEVELOPER;
  import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_VIEWER;
  import static org.junit.Assert.assertFalse;
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.junit.jupiter.api.Assertions.assertEquals;
  
  @Slf4j
  @RunWith(SpringRunner.class)
  @SpringBootTest
  @DirtiesContext
  class UserOrganizationServiceTest {
  
      @Autowired
      private UserOrganizationService userOrganizationService;
  
      @Autowired
      private OrganizationRepository organizationRepository;
  
      @Autowired
      private UserRepository userRepository;
  
      @Autowired
      private PolicyUtils policyUtils;
  
      @Autowired
      private ApplicationRepository applicationRepository;
  
      @Autowired
      private CommentService commentService;
  
      @Autowired
      private CommentThreadRepository commentThreadRepository;
  
      @Autowired
      private PolicyGenerator policyGenerator;
  
      private Organization organization;
      private User user;
  
      @BeforeEach
      public void setup() {
          Organization org = new Organization();
          org.setName("Test org");
          org.setUserRoles(new ArrayList<>());
          this.organization = organizationRepository.save(org).block();
      }
  
      private UserRole createUserRole(String username, String userId, AppsmithRole role) {
          UserRole userRole = new UserRole();
          userRole.setUsername(username);
          userRole.setUserId(userId);
          userRole.setName(username);
          if(role != null) {
              userRole.setRoleName(role.getName());
              userRole.setRole(role);
          }
          return userRole;
      }
  
      private void addRolesToOrg(List<UserRole> roles) {
          this.organization.setUserRoles(roles);
          for (UserRole userRole : roles) {
              Set<AclPermission> rolePermissions = userRole.getRole().getPermissions();
              Map<String, Policy> orgPolicyMap = policyUtils.generatePolicyFromPermission(
                      rolePermissions, userRole.getUsername()
              );
              this.organization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization);
          }
          this.organization = organizationRepository.save(organization).block();
      }
  
      @AfterEach
      public void clear() {
          User currentUser = userRepository.findByEmail("api_user").block();
          currentUser.getOrganizationIds().remove(organization.getId());
          userRepository.save(currentUser);
          organizationRepository.deleteById(organization.getId()).block();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      void leaveOrganization_WhenUserExistsInOrg_RemovesUser() {
          User currentUser = userRepository.findByEmail("api_user").block();
          Set<String> organizationIdsBefore = Set.copyOf(currentUser.getOrganizationIds());
  
          List<UserRole> userRolesBeforeAddUser = List.copyOf(organization.getUserRoles());
  
          currentUser.getOrganizationIds().add(organization.getId());
          userRepository.save(currentUser).block();
  
          UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_DEVELOPER);
  
          Organization updatedOrganization = userOrganizationService.addUserToOrganizationGivenUserObject(
                  this.organization, currentUser, userRole
          ).block();
  
          Mono<User> userMono = userOrganizationService.leaveOrganization(this.organization.getId());
          StepVerifier.create(userMono).assertNext(user -> {
              assertEquals("api_user", user.getEmail());
              assertEquals(organizationIdsBefore, user.getOrganizationIds());
          }).verifyComplete();
  
          StepVerifier.create(organizationRepository.findById(this.organization.getId())).assertNext(organization1 -> {
              assertEquals(userRolesBeforeAddUser.size(), organization1.getUserRoles().size());
          }).verifyComplete();
  
          StepVerifier.create(userRepository.findByEmail("api_user")).assertNext(user1 -> {
              assertFalse(
                      "user's orgId list should not have left org id",
                      user1.getOrganizationIds().contains(this.organization.getId())
              );
          }).verifyComplete();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      void leaveOrganization_WhenUserDoesNotExistInOrg_ThrowsException() {
          Mono<User> userMono = userOrganizationService.leaveOrganization(this.organization.getId());
          StepVerifier.create(userMono).expectErrorMessage(
                  AppsmithError.NO_RESOURCE_FOUND.getMessage(FieldName.USER + " api_user in the organization", organization.getName())
          ).verify();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void updateRoleForMember_WhenAdminRoleRemovedWithNoOtherAdmin_ThrowsExceptions() {
          // add the current user as an admin to the organization first
          User currentUser = userRepository.findByEmail("api_user").block();
          UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN);
  
          userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block();
  
          // try to remove the user from org
          UserRole updatedRole = new UserRole();
          updatedRole.setUsername(currentUser.getUsername());
  
          Mono<UserRole> userRoleMono = userOrganizationService.updateRoleForMember(organization.getId(), updatedRole, null);
          StepVerifier.create(userRoleMono).expectErrorMessage(
                  AppsmithError.REMOVE_LAST_ORG_ADMIN_ERROR.getMessage()
          ).verify();
      }
  
      @Test
      @WithUserDetails(value = "api_user")
      public void updateRoleForMember_WhenAdminRoleRemovedButOtherAdminExists_MemberRemoved() {
          // add another admin role to the organization
          UserRole adminRole = createUserRole("dummy_username2", "dummy_user_id2", ORGANIZATION_ADMIN);
          this.organization.getUserRoles().add(adminRole);
          this.organization = organizationRepository.save(this.organization).block();
  
          // add the current user as an admin to the organization
          User currentUser = userRepository.findByEmail("api_user").block();
          UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN);
          userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block();
  
          // try to remove the user from org
          UserRole updatedRole = new UserRole();
          updatedRole.setUsername(currentUser.getUsername());
  
          Mono<UserRole> userRoleMono = userOrganizationService.updateRoleForMember(organization.getId(), updatedRole, null);
          StepVerifier.create(userRoleMono).assertNext(
                  userRole1 -> {
                      assertEquals(currentUser.getUsername(), userRole1.getUsername());
                  }
          ).verifyComplete();
      }
  
      private Application createTestApplicationForCommentThreadTests() {
          // add a two roles to the organization
          User devUser = new User();
          devUser.setEmail("test_developer");
          userRepository.findByEmail("test_developer")
                  .switchIfEmpty(userRepository.save(devUser))
                  .block();
  
          UserRole adminRole = createUserRole("api_user", "api_user", ORGANIZATION_ADMIN);
          UserRole devRole = createUserRole("test_developer", "test_developer", ORGANIZATION_DEVELOPER);
  
          List<UserRole> userRoles = new ArrayList<>(2);
          userRoles.add(adminRole);
          userRoles.add(devRole);
  
          addRolesToOrg(userRoles);
  
          // create a test application
          Application application = new Application();
          application.setOrganizationId(this.organization.getId());
          application.setName("Test application");
          Set<Policy> documentPolicies = policyGenerator.getAllChildPolicies(
                  organization.getPolicies(), Organization.class, Application.class
          );
          application.setPolicies(documentPolicies);
          return application;
      }
  
      @Test
      @WithUserDetails("api_user")
      public void updateRoleForMember_WhenCommentThreadExists_ThreadPoliciesUnchanged() {
          // create a test application
          Mono<CommentThread> commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests())
                  .flatMap(savedApplication -> {
                      CommentThread commentThread = new CommentThread();
                      commentThread.setApplicationId(savedApplication.getId());
                      commentThread.setPolicies(policyGenerator.getAllChildPolicies(
                              savedApplication.getPolicies(), Application.class, CommentThread.class
                      ));
                      return commentThreadRepository.save(commentThread);
                  }).flatMap(commentThread -> {
                      // update an user's role
                      UserRole updatedRole = createUserRole("test_developer", "test_developer", ORGANIZATION_VIEWER);
                      return userOrganizationService.updateRoleForMember(
                              organization.getId(), updatedRole, null
                      ).thenReturn(commentThread);
                  }).flatMap(commentThread ->
                      commentThreadRepository.findById(commentThread.getId())
                  );
  
          StepVerifier.create(commentThreadMono).assertNext(commentThread -> {
              Set<Policy> policies = commentThread.getPolicies();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "test_developer"
              )).isTrue();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "api_user"
              )).isTrue();
          }).verifyComplete();
      }
  
      @Test
      @WithUserDetails("api_user")
      public void updateRoleForMember_WhenCommentThreadExistsAndUserRemoved_UserRemovedFromThreadPolicies() {
          Mono<CommentThread> commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests())
                  .flatMap(savedApplication -> {
                      CommentThread commentThread = new CommentThread();
                      commentThread.setApplicationId(savedApplication.getId());
                      commentThread.setPolicies(policyGenerator.getAllChildPolicies(
                              savedApplication.getPolicies(), Application.class, CommentThread.class
                      ));
                      return commentThreadRepository.save(commentThread);
                  }).flatMap(commentThread -> {
                      // remove the test_developer user from the organization
                      UserRole updatedRole = createUserRole("test_developer", "test_developer", null);
                      return userOrganizationService.updateRoleForMember(organization.getId(), updatedRole, null)
                              .thenReturn(commentThread);
                  }).flatMap(commentThread ->
                          commentThreadRepository.findById(commentThread.getId())
                  );
  
          StepVerifier.create(commentThreadMono).assertNext(commentThread -> {
              Set<Policy> policies = commentThread.getPolicies();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "test_developer"
              )).isFalse();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "api_user"
              )).isTrue();
          }).verifyComplete();
      }
  
      @Test
      @WithUserDetails("api_user")
      public void bulkAddUsersToOrganization_WhenNewUserAdded_ThreadPolicyUpdated() {
          // create a new user
          User user = new User();
          user.setEmail("new_test_user");
          Mono<User> saveUserMono = userRepository.save(user);
  
          Mono<CommentThread> commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests())
                  .flatMap(savedApplication -> {
                      CommentThread commentThread = new CommentThread();
                      commentThread.setApplicationId(savedApplication.getId());
                      commentThread.setPolicies(policyGenerator.getAllChildPolicies(
                              savedApplication.getPolicies(), Application.class, CommentThread.class
                      ));
                      return commentThreadRepository.save(commentThread);
                  }).flatMap(commentThread -> {
                      // add the new user to the organization
                      List<User> users = new ArrayList<>(1);
                      users.add(user);
                      return userOrganizationService
                              .bulkAddUsersToOrganization(organization, users, ORGANIZATION_DEVELOPER.getName())
                              .thenReturn(commentThread);
                  }).flatMap(commentThread ->
                          commentThreadRepository.findById(commentThread.getId())
                  );
  
          StepVerifier.create(saveUserMono.then(commentThreadMono)).assertNext(commentThread -> {
              Set<Policy> policies = commentThread.getPolicies();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "test_developer"
              )).isTrue();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "new_test_user"
              )).isTrue();
              assertThat(policyUtils.isPermissionPresentForUser(
                      policies, AclPermission.READ_THREAD.getValue(), "api_user"
              )).isTrue();
          }).verifyComplete();
      }
  }