Skip to content

Commit

Permalink
HELLODATA-1939 - [CSV] send over extra roles
Browse files Browse the repository at this point in the history
  • Loading branch information
Slawomir Wieczorek committed Feb 13, 2025
1 parent f69c51d commit db8cdb7
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 236 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.data;

import ch.bedag.dap.hellodata.commons.sidecars.modules.ModuleType;

import java.util.List;

public record ModuleRoleNames(ModuleType moduleType, List<String> roleNames) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@
package ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.data;

import ch.bedag.dap.hellodata.commons.sidecars.context.role.HdRoleName;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.ToString;

import java.io.Serializable;
import java.util.List;
import java.util.Map;


@ToString
@Data
public class UserContextRoleUpdate implements Serializable {
private String email;
private List<ContextRole> contextRoles;
private Map<String, List<ModuleRoleNames>> extraModuleRoles;

@ToString
@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package ch.bedag.dap.hellodata.portal.csv.service;

import ch.bedag.dap.hellodata.commons.sidecars.context.HdContextType;
import ch.bedag.dap.hellodata.commons.sidecars.modules.ModuleType;
import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.data.ModuleRoleNames;
import ch.bedag.dap.hellodata.portal.csv.data.CsvUserRole;
import ch.bedag.dap.hellodata.portal.role.data.RoleDto;
import ch.bedag.dap.hellodata.portal.user.data.BatchUpdateContextRolesForUserDto;
import ch.bedag.dap.hellodata.portal.user.data.ContextDto;
import ch.bedag.dap.hellodata.portal.user.data.UserContextRoleDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.csv.CSVFormat;
Expand All @@ -12,8 +19,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.*;

import static ch.bedag.dap.hellodata.commons.sidecars.context.role.HdRoleName.DATA_DOMAIN_VIEWER;

Expand All @@ -30,7 +36,48 @@ public class CsvParserService {
private static final char CSV_DELIMITER = ';';
private static final String ROLE_DELIMITER = ",";

public List<CsvUserRole> parseCsvFile(InputStream inputStream) {
public List<BatchUpdateContextRolesForUserDto> transform(InputStream csvStream) {
List<CsvUserRole> parsedData = parseCsvFile(csvStream);
Map<String, BatchUpdateContextRolesForUserDto> usersMap = new LinkedHashMap<>();

for (CsvUserRole row : parsedData) {
String email = row.email();
String businessDomainRole = row.businessDomainRole();
String dataDomain = row.context();
String dataDomainRole = row.dataDomainRole();
List<String> supersetRoles = row.supersetRoles();

usersMap.putIfAbsent(email, new BatchUpdateContextRolesForUserDto());
BatchUpdateContextRolesForUserDto userDto = usersMap.get(email);

Map<String, List<ModuleRoleNames>> contextToModuleRoleNamesMap = userDto.getContextToModuleRoleNamesMap();
contextToModuleRoleNamesMap.computeIfAbsent(dataDomain, k -> new ArrayList<>()).add(new ModuleRoleNames(ModuleType.SUPERSET, supersetRoles));

userDto.setEmail(email);
userDto.setBusinessDomainRole(new RoleDto());
userDto.getBusinessDomainRole().setContextType(HdContextType.BUSINESS_DOMAIN);
userDto.getBusinessDomainRole().setName(businessDomainRole);
if (userDto.getDataDomainRoles() == null) {
userDto.setDataDomainRoles(new ArrayList<>());
}
Optional<UserContextRoleDto> alreadyAdded = userDto.getDataDomainRoles().stream().filter(userContextRoleDto ->
userContextRoleDto.getContext().getContextKey().equals(dataDomain) && userContextRoleDto.getRole().getName().equals(dataDomainRole)).findFirst();
if (dataDomain != null && !dataDomain.isEmpty() && dataDomainRole != null && !dataDomainRole.isEmpty() && alreadyAdded.isEmpty()) {
UserContextRoleDto userContextRole = new UserContextRoleDto();
userContextRole.setRole(new RoleDto());
userContextRole.getRole().setName(dataDomainRole);
userContextRole.getRole().setContextType(HdContextType.DATA_DOMAIN);
ContextDto contextDto = new ContextDto();
contextDto.setContextKey(dataDomain);
userContextRole.setContext(contextDto);
userDto.getDataDomainRoles().add(userContextRole);
}

}
return new ArrayList<>(usersMap.values());
}

List<CsvUserRole> parseCsvFile(InputStream inputStream) {
List<CsvUserRole> records = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@
@EqualsAndHashCode(callSuper = true)
public class BatchUpdateContextRolesForUserDto extends UpdateContextRolesForUserDto {
private String email;

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,22 @@
*/
package ch.bedag.dap.hellodata.portal.user.data;

import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.data.ModuleRoleNames;
import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.request.DashboardForUserDto;
import ch.bedag.dap.hellodata.portal.role.data.RoleDto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class UpdateContextRolesForUserDto {
private RoleDto businessDomainRole;
private List<UserContextRoleDto> dataDomainRoles;
private Map<String, List<DashboardForUserDto>> selectedDashboardsForUser;
//CONTEXT -> MODULE -> ROLE NAMES i.e. "Data Domain One" -> "Superset DD One" -> ["Role1", "Role2"]
private Map<String, List<ModuleRoleNames>> contextToModuleRoleNamesMap = new HashMap<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,7 @@
*/
package ch.bedag.dap.hellodata.portal.user.service;

import ch.bedag.dap.hellodata.commons.metainfomodel.entities.MetaInfoResourceEntity;
import ch.bedag.dap.hellodata.commons.sidecars.modules.ModuleResourceKind;
import ch.bedag.dap.hellodata.commons.sidecars.modules.ModuleType;
import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.dashboard.DashboardResource;
import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.dashboard.response.superset.SupersetDashboard;
import ch.bedag.dap.hellodata.commons.sidecars.resources.v1.user.request.DashboardForUserDto;
import ch.bedag.dap.hellodata.portal.csv.service.CsvParserService;
import ch.bedag.dap.hellodata.portal.metainfo.service.MetaInfoResourceService;
import ch.bedag.dap.hellodata.portal.role.data.RoleDto;
import ch.bedag.dap.hellodata.portal.role.service.RoleService;
Expand All @@ -56,17 +51,17 @@
public class BatchUsersInvitationService {
private static final String LOCAL_AD_REGEX = "\\b\\w+-\\d+\\b";

// private final ExcelParserService excelParserService;
private final CsvParserService csvParserService;
private final UserService userService;
private final MetaInfoResourceService metaInfoResourceService;
private final RoleService roleService;

private final String batchUsersFileLocation;

public BatchUsersInvitationService(
UserService userService, MetaInfoResourceService metaInfoResourceService, RoleService roleService,
@Value("${hello-data.batch-users-file.location}") String batchUsersFileLocation) {
// this.excelParserService = excelParserService;
public BatchUsersInvitationService(CsvParserService csvParserService,
UserService userService, MetaInfoResourceService metaInfoResourceService, RoleService roleService,
@Value("${hello-data.batch-users-file.location}") String batchUsersFileLocation) {
this.csvParserService = csvParserService;
this.userService = userService;
this.batchUsersFileLocation = batchUsersFileLocation;
this.metaInfoResourceService = metaInfoResourceService;
Expand All @@ -84,15 +79,13 @@ public void inviteUsers() throws InterruptedException {
List<RoleDto> allRoles = roleService.getAll();
ContextsDto availableContexts = userService.getAvailableContexts();

Map<String, List<SupersetDashboard>> contextKeyToDashboardsMap = getContextKeyToDashboardsMap();
for (BatchUpdateContextRolesForUserDto user : users) {
Optional<AdUserDto> any = this.userService.searchUser(user.getEmail()).stream().findAny();
Optional<AdUserDto> firstAD = this.userService.searchUser(user.getEmail()).stream().filter(adUserDto -> !adUserDto.getFirstName().matches(LOCAL_AD_REGEX)).findFirst();
AdUserDto adUserDto = firstAD.orElseGet(any::orElseThrow);
String userId = userService.createUser(adUserDto.getEmail(), adUserDto.getFirstName(), adUserDto.getLastName());
insertFullBusinessDomainRole(user, allRoles);
insertFullContextRoles(user, allRoles, availableContexts);
insertFullDashboards(user, contextKeyToDashboardsMap);
Thread.sleep(500L);
userService.updateContextRolesForUser(UUID.fromString(userId), user);
}
Expand Down Expand Up @@ -132,43 +125,6 @@ private void insertFullBusinessDomainRole(BatchUpdateContextRolesForUserDto user
user.setBusinessDomainRole(businessDomainRole);
}

/**
* Inserts full dashboards to the selection from the file. The selection from the file has only id and title.
*
* @param user
* @param contextKeyToDashboardsMap
*/
private void insertFullDashboards(BatchUpdateContextRolesForUserDto user, Map<String, List<SupersetDashboard>> contextKeyToDashboardsMap) {
Map<String, List<DashboardForUserDto>> selectedDashboardsForUser = user.getSelectedDashboardsForUser();
selectedDashboardsForUser.forEach((contextKey, dashboards) -> {
List<SupersetDashboard> dashboardsForContext = contextKeyToDashboardsMap.get(contextKey);
if (dashboardsForContext == null) {
log.warn("No dashboards found for context key: {}", contextKey);
return;
}

List<DashboardForUserDto> dashboardsForUser = dashboards.stream()
.filter(dashboard -> dashboardsForContext.stream().anyMatch(d -> d.getId() == dashboard.getId() && d.getDashboardTitle().equalsIgnoreCase(dashboard.getTitle())))
.collect(Collectors.toList());

user.getSelectedDashboardsForUser().put(contextKey, dashboardsForUser);
});
}

/**
* Fetches all dashboards from the meta info resources and maps them to their context key.
*/
private Map<String, List<SupersetDashboard>> getContextKeyToDashboardsMap() {
Map<String, List<SupersetDashboard>> contextKeyToDashboardsMap = new HashMap<>();
List<MetaInfoResourceEntity> metaInfoResources = metaInfoResourceService.findAllByModuleTypeAndKind(ModuleType.SUPERSET, ModuleResourceKind.HELLO_DATA_DASHBOARDS);
metaInfoResources.forEach(metaInfoResourceEntity -> {
DashboardResource dashboardResource = (DashboardResource) metaInfoResourceEntity.getMetainfo();
String contextKey = metaInfoResourceEntity.getContextKey();
contextKeyToDashboardsMap.put(contextKey, dashboardResource.getData());
});
return contextKeyToDashboardsMap;
}

private void deleteFile(File file) {
if (file.delete()) {
log.info("Batch users file successfully deleted: {}", file.getAbsolutePath());
Expand All @@ -184,16 +140,16 @@ List<BatchUpdateContextRolesForUserDto> fetchUsersFile(boolean removeFilesAfterF
return Collections.emptyList();
}

File[] files = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".xlsx"));
File[] files = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".csv"));
if (files == null || files.length == 0) {
log.warn("No .xlsx files found in directory: {}", batchUsersFileLocation);
log.warn("No .csv files found in directory: {}", batchUsersFileLocation);
return Collections.emptyList();
}

List<BatchUpdateContextRolesForUserDto> allUsers = new ArrayList<>();
for (File file : files) {
try (FileInputStream fis = new FileInputStream(file)) {
List<BatchUpdateContextRolesForUserDto> users = null;
List<BatchUpdateContextRolesForUserDto> users = csvParserService.transform(fis);
allUsers.addAll(users);
if (removeFilesAfterFetch) {
deleteFile(file);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
import ch.bedag.dap.hellodata.portal.role.service.RoleService;
import ch.bedag.dap.hellodata.portal.user.entity.UserEntity;
import ch.bedag.dap.hellodata.portal.user.repository.UserRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Log4j2
@Service
@AllArgsConstructor
Expand Down Expand Up @@ -74,7 +72,7 @@ private void addMissingContextRole(UserEntity userEntity, List<String> businessD
log.debug("User {} is not an admin, setting missing role to NONE", userEntity.getEmail());
roleService.addContextRoleToUser(userEntity, dataDomainKeyNotFoundInUserRole, HdRoleName.NONE);
}
userService.synchronizeContextRolesWithSubsystems(userEntity);
userService.synchronizeContextRolesWithSubsystems(userEntity, new HashMap<>());
}
}

Expand Down
Loading

0 comments on commit db8cdb7

Please sign in to comment.