Skip to content

Commit 988537f

Browse files
authored
chore: Dynamically fetch system generated users via DB query (#40323)
1 parent f7e8aad commit 988537f

File tree

4 files changed

+148
-11
lines changed

4 files changed

+148
-11
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.appsmith.server.projections;
2+
3+
import lombok.NonNull;
4+
5+
public record EmailOnly(@NonNull String email) {}

app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCE.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
import com.appsmith.server.domains.User;
44
import com.appsmith.server.repositories.AppsmithRepository;
55
import org.springframework.data.mongodb.core.query.UpdateDefinition;
6+
import reactor.core.publisher.Flux;
67
import reactor.core.publisher.Mono;
78

8-
import java.util.Set;
9-
109
public interface CustomUserRepositoryCE extends AppsmithRepository<User> {
1110

1211
Mono<User> findByEmailAndOrganizationId(String email, String organizationId);
1312

1413
Mono<Boolean> isUsersEmpty();
1514

16-
Set<String> getSystemGeneratedUserEmails();
15+
Flux<String> getSystemGeneratedUserEmails(String organizationId);
1716

1817
Mono<Integer> updateById(String id, UpdateDefinition updateObj);
1918
}

app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ce/CustomUserRepositoryCEImpl.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
import com.appsmith.server.exceptions.AppsmithError;
66
import com.appsmith.server.exceptions.AppsmithException;
77
import com.appsmith.server.helpers.ce.bridge.Bridge;
8+
import com.appsmith.server.projections.EmailOnly;
89
import com.appsmith.server.projections.IdOnly;
910
import com.appsmith.server.repositories.BaseAppsmithRepositoryImpl;
1011
import lombok.extern.slf4j.Slf4j;
1112
import org.springframework.data.mongodb.core.query.UpdateDefinition;
13+
import reactor.core.publisher.Flux;
1214
import reactor.core.publisher.Mono;
1315

14-
import java.util.HashSet;
15-
import java.util.Set;
16+
import static com.appsmith.server.helpers.ce.bridge.Bridge.notExists;
1617

1718
@Slf4j
1819
public class CustomUserRepositoryCEImpl extends BaseAppsmithRepositoryImpl<User> implements CustomUserRepositoryCE {
@@ -25,26 +26,30 @@ public Mono<User> findByEmailAndOrganizationId(String email, String organization
2526
}
2627

2728
/**
28-
* Fetch minimal information from *a* user document in the database, limit to two documents, filter anonymousUser
29+
* Fetch minimal information from *a* user document in the database, limit to two documents, filter system generated
30+
* users.
2931
* If no documents left return true otherwise return false.
3032
*
3133
* @return Boolean, indicated where there exists at least one user in the system or not.
3234
*/
3335
@Override
3436
public Mono<Boolean> isUsersEmpty() {
3537
return queryBuilder()
36-
.criteria(Bridge.notIn(User.Fields.email, getSystemGeneratedUserEmails()))
38+
.criteria(Bridge.or(
39+
notExists(User.Fields.isSystemGenerated), Bridge.isFalse(User.Fields.isSystemGenerated)))
3740
.limit(1)
3841
.all(IdOnly.class)
3942
.count()
4043
.map(count -> count == 0);
4144
}
4245

4346
@Override
44-
public Set<String> getSystemGeneratedUserEmails() {
45-
Set<String> systemGeneratedEmails = new HashSet<>();
46-
systemGeneratedEmails.add(FieldName.ANONYMOUS_USER);
47-
return systemGeneratedEmails;
47+
public Flux<String> getSystemGeneratedUserEmails(String organizationId) {
48+
return queryBuilder()
49+
.criteria(Bridge.equal(User.Fields.isSystemGenerated, true)
50+
.equal(User.Fields.organizationId, organizationId))
51+
.all(EmailOnly.class)
52+
.map(EmailOnly::email);
4853
}
4954

5055
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package com.appsmith.server.repositories.ce;
2+
3+
import com.appsmith.server.domains.Organization;
4+
import com.appsmith.server.domains.User;
5+
import com.appsmith.server.repositories.OrganizationRepository;
6+
import com.appsmith.server.repositories.UserRepository;
7+
import org.junit.jupiter.api.AfterEach;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.boot.test.context.SpringBootTest;
12+
import reactor.core.publisher.Flux;
13+
import reactor.test.StepVerifier;
14+
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
import java.util.Set;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
@SpringBootTest
22+
public class CustomUserRepositoryCEImplTest {
23+
24+
@Autowired
25+
private UserRepository userRepository;
26+
27+
@Autowired
28+
private OrganizationRepository organizationRepository;
29+
30+
private final List<User> savedUsers = new ArrayList<>();
31+
private static final Set<String> PREDEFINED_SYSTEM_USERS = Set.of("anonymousUser");
32+
33+
@BeforeEach
34+
public void setUp() {
35+
this.savedUsers.clear();
36+
}
37+
38+
@AfterEach
39+
public void cleanUp() {
40+
for (User savedUser : savedUsers) {
41+
userRepository.deleteById(savedUser.getId()).block();
42+
}
43+
}
44+
45+
@Test
46+
public void getSystemGeneratedUserEmails_WhenSystemGeneratedUsersExist_ReturnsTheirEmails() {
47+
String defaultOrgId = organizationRepository
48+
.findBySlug("default")
49+
.map(Organization::getId)
50+
.block();
51+
52+
// Create an additional system-generated user
53+
User systemUser = new User();
54+
systemUser.setEmail("[email protected]");
55+
systemUser.setIsSystemGenerated(true);
56+
systemUser.setOrganizationId(defaultOrgId);
57+
User savedSystemUser = userRepository.save(systemUser).block();
58+
savedUsers.add(savedSystemUser);
59+
60+
// Create a non-system-generated user
61+
User nonSystemUser = new User();
62+
nonSystemUser.setEmail("[email protected]");
63+
nonSystemUser.setIsSystemGenerated(false);
64+
nonSystemUser.setOrganizationId(defaultOrgId);
65+
User savedNonSystemUser = userRepository.save(nonSystemUser).block();
66+
savedUsers.add(savedNonSystemUser);
67+
68+
// Test the method
69+
Flux<String> systemGeneratedEmails = userRepository.getSystemGeneratedUserEmails(defaultOrgId);
70+
71+
StepVerifier.create(systemGeneratedEmails.collectList())
72+
.assertNext(emails -> {
73+
// Verify all predefined system users are present
74+
assertThat(emails).containsAll(PREDEFINED_SYSTEM_USERS);
75+
// Verify our test system user is present
76+
assertThat(emails).contains("[email protected]");
77+
// Verify non-system user is not present
78+
assertThat(emails).doesNotContain("[email protected]");
79+
// Verify total count is correct (predefined users + our test user)
80+
assertThat(emails).hasSize(PREDEFINED_SYSTEM_USERS.size() + 1);
81+
})
82+
.verifyComplete();
83+
}
84+
85+
@Test
86+
public void getSystemGeneratedUserEmails_WhenNoAdditionalSystemGeneratedUsersExist_ReturnsOnlyPredefinedUsers() {
87+
String defaultOrgId = organizationRepository
88+
.findBySlug("default")
89+
.map(Organization::getId)
90+
.block();
91+
92+
// Create only non-system-generated user
93+
User nonSystemUser = new User();
94+
nonSystemUser.setEmail("[email protected]");
95+
nonSystemUser.setIsSystemGenerated(false);
96+
nonSystemUser.setOrganizationId(defaultOrgId);
97+
User savedNonSystemUser = userRepository.save(nonSystemUser).block();
98+
savedUsers.add(savedNonSystemUser);
99+
100+
// Test the method
101+
Flux<String> systemGeneratedEmails = userRepository.getSystemGeneratedUserEmails(defaultOrgId);
102+
103+
StepVerifier.create(systemGeneratedEmails.collectList())
104+
.assertNext(emails -> {
105+
// Verify only predefined system users are present
106+
assertThat(emails).containsExactlyInAnyOrderElementsOf(PREDEFINED_SYSTEM_USERS);
107+
// Verify non-system user is not present
108+
assertThat(emails).doesNotContain("[email protected]");
109+
})
110+
.verifyComplete();
111+
}
112+
113+
@Test
114+
public void isUsersEmpty_WhenNonSystemUsersExist_ReturnsFalse() {
115+
// Create a non-system-generated user
116+
User nonSystemUser = new User();
117+
nonSystemUser.setEmail("[email protected]");
118+
User savedNonSystemUser = userRepository.save(nonSystemUser).block();
119+
savedUsers.add(savedNonSystemUser);
120+
121+
// Test the method
122+
StepVerifier.create(userRepository.isUsersEmpty())
123+
.assertNext(isEmpty -> {
124+
assertThat(isEmpty).isFalse();
125+
})
126+
.verifyComplete();
127+
}
128+
}

0 commit comments

Comments
 (0)