Skip to content

Commit 866c483

Browse files
committed
Merge branch '14.2'
2 parents 4634e54 + 5c92ce0 commit 866c483

File tree

7 files changed

+89
-70
lines changed

7 files changed

+89
-70
lines changed

avni-server-api/src/main/java/org/avni/server/dao/UserRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ default User getDefaultSuperAdmin() {
147147

148148
User findTopByOrderByIdDesc();
149149

150+
List<User> findAllByEmailIgnoreCaseAndIsVoidedFalse(String email);
151+
150152
default User getLatestUser() {
151153
return this.findTopByOrderByIdDesc();
152154
}

avni-server-api/src/main/java/org/avni/server/dao/metabase/MetabaseConnector.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.slf4j.LoggerFactory;
1010
import org.springframework.beans.factory.annotation.Value;
1111
import org.springframework.boot.web.client.RestTemplateBuilder;
12+
import org.springframework.core.ParameterizedTypeReference;
1213
import org.springframework.http.HttpEntity;
1314
import org.springframework.http.HttpHeaders;
1415
import org.springframework.http.HttpMethod;
@@ -75,6 +76,12 @@ protected <T> T getForObject(String url, Class<T> responseType) {
7576
return restTemplate.exchange(url, HttpMethod.GET, entity, responseType).getBody();
7677
}
7778

79+
protected <T> T getForObject(String url, ParameterizedTypeReference responseTypeReference) {
80+
HttpHeaders headers = getHeaders();
81+
HttpEntity<Void> entity = new HttpEntity<>(headers);
82+
return (T) restTemplate.exchange(url, HttpMethod.GET, entity, responseTypeReference).getBody();
83+
}
84+
7885
protected <T> T deleteForObject(String url, Class<T> responseType) {
7986
HttpHeaders headers = getHeaders();
8087
HttpEntity<Void> entity = new HttpEntity<>(headers);

avni-server-api/src/main/java/org/avni/server/dao/metabase/MetabaseUserRepository.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
99
import org.springframework.boot.web.client.RestTemplateBuilder;
10+
import org.springframework.core.ParameterizedTypeReference;
1011
import org.springframework.stereotype.Component;
1112

1213
import java.util.ArrayList;
1314
import java.util.List;
15+
import java.util.Map;
1416

1517
@Component
1618
public class MetabaseUserRepository extends MetabaseConnector {
@@ -40,6 +42,16 @@ public MetabaseUserData getUserFromEmail(String email) {
4042
.orElse(null);
4143
}
4244

45+
public Map<String, List<MetabaseGroupMembership>> getAllMemberships() {
46+
String url = metabaseApiUrl + "/permissions/membership";
47+
return getForObject(url, new ParameterizedTypeReference<Map<String, List<MetabaseGroupMembership>>>() {});
48+
}
49+
50+
public void deleteMembership(MetabaseGroupMembership membership) {
51+
String url = metabaseApiUrl + "/permissions/membership/" + membership.membershipId();
52+
deleteForObject(url, String.class);
53+
}
54+
4355
public boolean activeUserExists(String email, boolean excludeSuperAdmins) {
4456
MetabaseAllUsersResponse response = getAllUsers();
4557
return response.getData().stream()
@@ -75,15 +87,20 @@ public void reactivateMetabaseUser(String email) {
7587
sendPutRequest(url, null);
7688
}
7789

78-
public List<UserGroupMemberships> getUserGroupMemberships() {
90+
public List<UserGroupMemberships> buildDefaultUserGroupMemberships(Group orgMetabaseGroup) {
91+
List<UserGroupMemberships> userGroupMemberships = buildAllUserGroupMembership();
92+
if (orgMetabaseGroup == null) orgMetabaseGroup = metabaseGroupRepository.getGroup();
93+
if (orgMetabaseGroup != null) {
94+
UserGroupMemberships currentOrganisationGroup = new UserGroupMemberships(orgMetabaseGroup.getId(), false);
95+
userGroupMemberships.add(currentOrganisationGroup);
96+
}
97+
return userGroupMemberships;
98+
}
99+
100+
public List<UserGroupMemberships> buildAllUserGroupMembership() {
79101
List<UserGroupMemberships> userGroupMemberships = new ArrayList<>();
80102
UserGroupMemberships defaultAllUsers = new UserGroupMemberships(1, false);
81103
userGroupMemberships.add(defaultAllUsers);
82-
Group group = metabaseGroupRepository.getGroup();
83-
if (group != null) {
84-
UserGroupMemberships currentOrganisationGroup = new UserGroupMemberships(group.getId(), false);
85-
userGroupMemberships.add(currentOrganisationGroup);
86-
}
87104
return userGroupMemberships;
88105
}
89106

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.avni.server.domain.metabase;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
public record MetabaseGroupMembership(@JsonProperty("membership_id") Integer membershipId,
6+
@JsonProperty("group_id") Integer groupId,
7+
@JsonProperty("user_id") Integer userId,
8+
@JsonProperty("is_group_manager") boolean isGroupManager) {
9+
10+
public MetabaseGroupMembership(Integer membershipId, Integer groupId, Integer userId, boolean isGroupManager) {
11+
this.membershipId = membershipId;
12+
this.groupId = groupId;
13+
this.userId = userId;
14+
this.isGroupManager = isGroupManager;
15+
}
16+
}

avni-server-api/src/main/java/org/avni/server/service/metabase/MetabaseService.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.avni.server.service.metabase;
22

33
import org.avni.server.config.SelfServiceBatchConfig;
4+
import org.avni.server.dao.UserRepository;
45
import org.avni.server.dao.metabase.*;
56
import org.avni.server.domain.Organisation;
67
import org.avni.server.domain.UserGroup;
@@ -17,6 +18,8 @@
1718
import java.util.ArrayList;
1819
import java.util.List;
1920

21+
import static org.avni.server.domain.Group.METABASE_USERS;
22+
2023
@Service
2124
public class MetabaseService {
2225
private static final String DB_ENGINE = "postgres";
@@ -35,6 +38,7 @@ public class MetabaseService {
3538
private final MetabaseDashboardRepository metabaseDashboardRepository;
3639
private final MetabaseGroupRepository metabaseGroupRepository;
3740
private final MetabaseUserRepository metabaseUserRepository;
41+
private final UserRepository userRepository;
3842

3943
private static final Logger logger = LoggerFactory.getLogger(MetabaseService.class);
4044
private static final long EACH_SLEEP_DURATION = 3;
@@ -49,7 +53,7 @@ public MetabaseService(OrganisationService organisationService,
4953
MetabaseDashboardRepository metabaseDashboardRepository,
5054
MetabaseGroupRepository metabaseGroupRepository,
5155
MetabaseUserRepository metabaseUserRepository, MetabaseDatabaseRepository metabaseDatabaseRepository,
52-
SelfServiceBatchConfig selfServiceBatchConfig) {
56+
SelfServiceBatchConfig selfServiceBatchConfig, UserRepository userRepository) {
5357
this.organisationService = organisationService;
5458
this.avniDatabase = avniDatabase;
5559
this.databaseRepository = databaseRepository;
@@ -61,6 +65,7 @@ public MetabaseService(OrganisationService organisationService,
6165
this.metabaseUserRepository = metabaseUserRepository;
6266
this.metabaseDatabaseRepository = metabaseDatabaseRepository;
6367
this.selfServiceBatchConfig = selfServiceBatchConfig;
68+
this.userRepository = userRepository;
6469
}
6570

6671
private boolean setupDatabase() {
@@ -161,29 +166,43 @@ private CollectionInfoResponse getGlobalCollection() {
161166
return collectionRepository.getCollection(organisation);
162167
}
163168

164-
public void upsertUsersOnMetabase(List<UserGroup> usersToBeAdded) {
169+
public void upsertUsersOnMetabase(List<UserGroup> userGroups) {
165170
Group group = metabaseGroupRepository.findGroup(UserContextHolder.getOrganisation().getName());
171+
List<UserGroup> changesToMetabaseUsersGroup = userGroups.stream().filter(ug -> ug.getGroupName().equals(METABASE_USERS)).toList();
166172
if (group != null) {
167-
List<UserGroupMemberships> userGroupMemberships = metabaseUserRepository.getUserGroupMemberships();
168-
for (UserGroup value : usersToBeAdded) {
169-
if (value.getGroupName().contains(org.avni.server.domain.Group.METABASE_USERS)
170-
&& !metabaseUserRepository.emailExists(value.getUser().getEmail())) {
171-
String[] nameParts = value.getUser().getName().split(" ", 2);
172-
String firstName = nameParts[0];
173-
String lastName = (nameParts.length > 1) ? nameParts[1] : null;
174-
metabaseUserRepository.save(new CreateUserRequest(firstName, lastName, value.getUser().getEmail(), userGroupMemberships));
175-
} else {
176-
if (!metabaseUserRepository.activeUserExists(value.getUser().getEmail())) {
177-
metabaseUserRepository.reactivateMetabaseUser(value.getUser().getEmail());
173+
for (UserGroup value : changesToMetabaseUsersGroup) {
174+
boolean usersSharingEmailAddress = userRepository.findAllByEmailIgnoreCaseAndIsVoidedFalse(value.getUser().getEmail()).size() > 1;
175+
MetabaseUserData metabaseUser = metabaseUserRepository.getUserFromEmail(value.getUser().getEmail());
176+
if (value.isVoided()) {
177+
// Email uniquely identifies a user on metabase but on avni.
178+
// Remove the user from the org group on metabase only if the email id used is unique on avni as well.
179+
if (!usersSharingEmailAddress) {
180+
if (metabaseUser != null && metabaseUser.getGroupIds().contains(group.getId())) {
181+
removeUserFromMetabaseGroup(group.getId(), metabaseUser.getId());
182+
}
178183
}
179-
if (!metabaseUserRepository.userExistsInCurrentOrgGroup((value.getUser().getEmail()))) {
180-
metabaseUserRepository.updateGroupPermissions(new UpdateUserGroupRequest(metabaseUserRepository.getUserFromEmail(value.getUser().getEmail()).getId(), group.getId()));
184+
} else {
185+
if (metabaseUser == null) {
186+
String[] nameParts = value.getUser().getName().split(" ", 2);
187+
String firstName = nameParts[0];
188+
String lastName = (nameParts.length > 1) ? nameParts[1] : null;
189+
List<UserGroupMemberships> userGroupMemberships = metabaseUserRepository.buildDefaultUserGroupMemberships(group);
190+
metabaseUserRepository.save(new CreateUserRequest(firstName, lastName, value.getUser().getEmail(), userGroupMemberships));
191+
} else {
192+
if (!metabaseUser.getGroupIds().contains(group.getId())) {
193+
metabaseUserRepository.updateGroupPermissions(new UpdateUserGroupRequest(metabaseUser.getId(), group.getId()));
194+
}
181195
}
182196
}
183197
}
184198
}
185199
}
186200

201+
public void removeUserFromMetabaseGroup(Integer groupId, Integer userId) {
202+
metabaseUserRepository.getAllMemberships().get(String.valueOf(userId)).stream().filter(metabaseGroupMembership -> metabaseGroupMembership.groupId().equals(groupId) && metabaseGroupMembership.userId().equals(userId))
203+
.findFirst().ifPresent(metabaseUserRepository::deleteMembership);
204+
}
205+
187206
public void fixDatabaseSyncSchedule() {
188207
Organisation organisation = organisationService.getCurrentOrganisation();
189208
Database database = databaseRepository.getDatabase(organisation);

avni-server-api/src/main/java/org/avni/server/web/UserController.java

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@
99
import jakarta.transaction.Transactional;
1010
import org.apache.commons.validator.routines.EmailValidator;
1111
import org.avni.server.dao.*;
12-
import org.avni.server.dao.metabase.MetabaseGroupRepository;
13-
import org.avni.server.dao.metabase.MetabaseUserRepository;
1412
import org.avni.server.domain.*;
1513
import org.avni.server.domain.accessControl.PrivilegeType;
16-
import org.avni.server.domain.metabase.CreateUserRequest;
17-
import org.avni.server.domain.metabase.UpdateUserGroupRequest;
1814
import org.avni.server.framework.security.UserContextHolder;
1915
import org.avni.server.projection.UserWebProjection;
2016
import org.avni.server.service.*;
2117
import org.avni.server.service.accessControl.AccessControlService;
22-
import org.avni.server.service.metabase.DatabaseService;
18+
import org.avni.server.service.metabase.MetabaseService;
2319
import org.avni.server.util.PhoneNumberUtil;
2420
import org.avni.server.util.RegionUtil;
2521
import org.avni.server.util.ValidationUtil;
@@ -61,8 +57,7 @@ public class UserController {
6157
private final SubjectTypeRepository subjectTypeRepository;
6258
private final AccessControlService accessControlService;
6359
private final OrganisationConfigService organisationConfigService;
64-
private final MetabaseUserRepository metabaseUserRepository;
65-
private final MetabaseGroupRepository metabaseGroupRepository;
60+
private final MetabaseService metabaseService;
6661

6762
private final Pattern NAME_INVALID_CHARS_PATTERN = Pattern.compile("^.*[<>=\"].*$");
6863

@@ -76,8 +71,7 @@ public UserController(CatchmentRepository catchmentRepository,
7671
AccountAdminRepository accountAdminRepository, ResetSyncService resetSyncService,
7772
SubjectTypeRepository subjectTypeRepository,
7873
AccessControlService accessControlService, OrganisationConfigService organisationConfigService,
79-
MetabaseUserRepository metabaseUserRepository,
80-
MetabaseGroupRepository metabaseGroupRepository) {
74+
MetabaseService metabaseService) {
8175
this.catchmentRepository = catchmentRepository;
8276
this.userRepository = userRepository;
8377
this.organisationRepository = organisationRepository;
@@ -90,8 +84,7 @@ public UserController(CatchmentRepository catchmentRepository,
9084
this.subjectTypeRepository = subjectTypeRepository;
9185
this.accessControlService = accessControlService;
9286
this.organisationConfigService = organisationConfigService;
93-
this.metabaseUserRepository = metabaseUserRepository;
94-
this.metabaseGroupRepository = metabaseGroupRepository;
87+
this.metabaseService = metabaseService;
9588
logger = LoggerFactory.getLogger(this.getClass());
9689
}
9790

@@ -172,7 +165,7 @@ public ResponseEntity updateUser(@RequestBody UserContract userContract, @PathVa
172165
accountAdminService.createAccountAdmins(user, userContract.getAccountIds());
173166
List<UserGroup> associatedUserGroups = userService.associateUserToGroups(user, userContract.getGroupIds());
174167
if (organisationConfigService.isMetabaseSetupEnabled(UserContextHolder.getOrganisation())) {
175-
performMetabaseUserUpsert(userContract, associatedUserGroups);
168+
metabaseService.upsertUsersOnMetabase(associatedUserGroups);
176169
}
177170
logger.info(String.format("Saved user '%s', UUID '%s'", userContract.getUsername(), user.getUuid()));
178171
return new ResponseEntity<>(user, HttpStatus.CREATED);
@@ -183,32 +176,6 @@ public ResponseEntity updateUser(@RequestBody UserContract userContract, @PathVa
183176
}
184177
}
185178

186-
private void performMetabaseUserUpsert(UserContract userContract, List<UserGroup> associatedUserGroups) {
187-
boolean isPartOfMetabaseUsersGrp = associatedUserGroups.stream()
188-
.filter(ug -> !ug.isVoided() && ug.getGroupName().contains(Group.METABASE_USERS))
189-
.findAny().isPresent();
190-
191-
if (isPartOfMetabaseUsersGrp) {
192-
if (!metabaseUserRepository.emailExists(userContract.getEmail())) {
193-
String[] nameParts = userContract.getName().split(" ", 2);
194-
String firstName = nameParts[0];
195-
String lastName = (nameParts.length > 1) ? nameParts[1] : null;
196-
metabaseUserRepository.save(new CreateUserRequest(firstName, lastName, userContract.getEmail(), metabaseUserRepository.getUserGroupMemberships()));
197-
} else {
198-
if (!metabaseUserRepository.activeUserExists(userContract.getEmail())) {
199-
metabaseUserRepository.reactivateMetabaseUser(userContract.getEmail());
200-
}
201-
if (!metabaseUserRepository.userExistsInCurrentOrgGroup((userContract.getEmail()))) {
202-
metabaseUserRepository.updateGroupPermissions(new UpdateUserGroupRequest(metabaseUserRepository.getUserFromEmail(userContract.getEmail()).getId(), metabaseGroupRepository.getGroup().getId()));
203-
}
204-
}
205-
} else {
206-
if (metabaseUserRepository.activeUserExists(userContract.getEmail(), true)) {
207-
metabaseUserRepository.deactivateMetabaseUser(userContract.getEmail());
208-
}
209-
}
210-
}
211-
212179
private String getRegionForUser(UserContract userContract) {
213180
String region;
214181
if (userContract.getAccountIds().isEmpty()) {

avni-server-api/src/main/java/org/avni/server/web/UserGroupController.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import org.avni.server.dao.GroupRepository;
66
import org.avni.server.dao.UserGroupRepository;
77
import org.avni.server.dao.UserRepository;
8-
import org.avni.server.dao.metabase.MetabaseUserRepository;
98
import org.avni.server.domain.CHSEntity;
109
import org.avni.server.domain.Group;
1110
import org.avni.server.domain.User;
@@ -36,19 +35,17 @@ public class UserGroupController extends AbstractController<UserGroup> implement
3635
private final UserRepository userRepository;
3736
private final GroupRepository groupRepository;
3837
private final AccessControlService accessControlService;
39-
private final MetabaseUserRepository metabaseUserRepository;
4038
private final OrganisationConfigService organisationConfigService;
4139
private final MetabaseService metabaseService;
4240

4341
@Autowired
4442
public UserGroupController(UserGroupRepository userGroupRepository, UserRepository userRepository, GroupRepository groupRepository,
45-
AccessControlService accessControlService, MetabaseUserRepository metabaseUserRepository,
43+
AccessControlService accessControlService,
4644
OrganisationConfigService organisationConfigService, MetabaseService metabaseService) {
4745
this.userGroupRepository = userGroupRepository;
4846
this.userRepository = userRepository;
4947
this.groupRepository = groupRepository;
5048
this.accessControlService = accessControlService;
51-
this.metabaseUserRepository = metabaseUserRepository;
5249
this.organisationConfigService = organisationConfigService;
5350
this.metabaseService = metabaseService;
5451
}
@@ -113,14 +110,8 @@ public ResponseEntity removeUserFromGroup(@PathVariable("id") Long id) {
113110
userGroupRepository.save(userGroup);
114111
if (organisationConfigService.isMetabaseSetupEnabled(UserContextHolder.getOrganisation()) &&
115112
userGroup.getGroupName().contains(Group.METABASE_USERS)) {
116-
deactivateUserOnMetabase(userGroup);
113+
metabaseService.upsertUsersOnMetabase(List.of(userGroup));
117114
}
118115
return new ResponseEntity<>(UserGroupContract.fromEntity(userGroup), HttpStatus.OK);
119116
}
120-
121-
private void deactivateUserOnMetabase(UserGroup userGroup) {
122-
if (metabaseUserRepository.activeUserExists(userGroup.getUser().getEmail(), true)) {
123-
metabaseUserRepository.deactivateMetabaseUser(userGroup.getUser().getEmail());
124-
}
125-
}
126117
}

0 commit comments

Comments
 (0)