Skip to content

Commit

Permalink
fix: allow importing custom & multivalujed properties with csv - EXO-…
Browse files Browse the repository at this point in the history
  • Loading branch information
ahamdi authored and Jihed525 committed Aug 17, 2023
1 parent bdbe8e6 commit 72d115c
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public interface ProfilePropertyService {
*/
List<ProfilePropertySetting> getSynchronizedPropertySettings();

/**
* Retrieves the ProfileProperty item with given {@link ProfilePropertySetting}
* propertyName
*
* @return {@link ProfilePropertySetting} if exist or null if not
*/
ProfilePropertySetting getProfileSettingById(Long id);

/**
* Retrieves the ProfileProperty item with given {@link ProfilePropertySetting}
* propertyName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public ProfilePropertySetting getProfileSettingByName(String name) {
return profileSettingStorage.findProfileSettingByName(name);
}

@Override
public ProfilePropertySetting getProfileSettingById(Long id) {
return profileSettingStorage.getProfileSettingById(id);
}

@Override
public ProfilePropertySetting createPropertySetting(ProfilePropertySetting profilePropertySetting) throws ObjectAlreadyExistsException {
if (profilePropertySetting == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import javax.ws.rs.core.UriInfo;

import org.apache.commons.lang3.StringUtils;
import org.exoplatform.social.core.profileproperty.model.ProfilePropertySetting;
import org.json.JSONException;
import org.json.JSONObject;
import org.picocontainer.Startable;
Expand Down Expand Up @@ -959,7 +960,8 @@ public Response updateUserProfileAttributes(@Context HttpServletRequest request,
}

try {
saveProfile(username, profileEntity);
Map<String, Object> userProfileProperties = extractPropertiesFromEntities(profileEntity);
saveProfile(username, userProfileProperties);
} catch (IllegalAccessException e) {
LOG.error("User {} is not allowed to update attributes", currentUser);
return Response.status(Status.UNAUTHORIZED).build();
Expand All @@ -969,6 +971,60 @@ public Response updateUserProfileAttributes(@Context HttpServletRequest request,
}
return Response.noContent().build();
}

private Map<String, Object> extractPropertiesFromEntities(ProfileEntity profileEntity) {
Map<String, Object> userProfileProperties = new HashMap<>();
for(String key: profileEntity.getDataEntity().keySet()) {
if(profileEntity.getDataEntity().get(key) instanceof List<?>) {
List<Map<String, String>> properties = new ArrayList<>();
if(key.equalsIgnoreCase(Profile.CONTACT_IMS)) {
List<IMEntity> imsEntities = (List<IMEntity>) profileEntity.getDataEntity().get(key);
for(IMEntity im : imsEntities){
Map<String, String> imMap = new HashMap<>();
imMap.put(im.getImType(), im.getImId());
properties.add(imMap);
}
} else if(key.equalsIgnoreCase(Profile.CONTACT_PHONES)) {
List<PhoneEntity> phoneEntities = (List<PhoneEntity>) profileEntity.getDataEntity().get(key);
for(PhoneEntity phoneEntity : phoneEntities){
Map<String, String> phoneMap = new HashMap<>();
phoneMap.put(phoneEntity.getPhoneType(), phoneEntity.getPhoneNumber());
properties.add(phoneMap);
}

} else if(key.equalsIgnoreCase(Profile.CONTACT_URLS)) {
List<URLEntity> urlEntities = (List<URLEntity>) profileEntity.getDataEntity().get(key);
for(URLEntity url : urlEntities){
Map<String, String> urlMap = new HashMap<>();
urlMap.put(url.getUrl(), url.getUrl());
properties.add(urlMap);
}
} else if(key.equalsIgnoreCase(Profile.EXPERIENCES)) {
@SuppressWarnings("unchecked")
List<ExperienceEntity> experienceEntities = (List<ExperienceEntity>) profileEntity.getDataEntity().get(key);
for(ExperienceEntity experienceEntity : experienceEntities) {
Map<String, String> experienceMap = new HashMap<>();
if(StringUtils.isNotBlank(experienceEntity.getId())) {
experienceMap.put(Profile.EXPERIENCES_ID, experienceEntity.getId());
}
experienceMap.put(Profile.EXPERIENCES_COMPANY, experienceEntity.getCompany());
experienceMap.put(Profile.EXPERIENCES_DESCRIPTION, experienceEntity.getDescription());
experienceMap.put(Profile.EXPERIENCES_SKILLS, experienceEntity.getSkills());
experienceMap.put(Profile.EXPERIENCES_START_DATE, experienceEntity.getStartDate());
experienceMap.put(Profile.EXPERIENCES_END_DATE, experienceEntity.getEndDate());
experienceMap.put(Profile.EXPERIENCES_POSITION, experienceEntity.getPosition());
experienceMap.put(Profile.EXPERIENCES_IS_CURRENT, String.valueOf(experienceEntity.getIsCurrent()));
properties.add(experienceMap);
}
}
userProfileProperties.put(key, properties);
} else {
userProfileProperties.put(key, profileEntity.getDataEntity().get(key));
}
}
return userProfileProperties;
}

@PATCH
@Path("{id}/profile/properties")
@Operation(summary = "Update set of properties in user profile", method = "PATCH", description = "This can only be done by the logged in user.")
Expand Down Expand Up @@ -1029,43 +1085,18 @@ public Response updateUserProfileAttributes(@Context
profile = getUserIdentity(username).getProfile();
}
} else {
switch (profileProperty.getPropertyName()) {
case Profile.CONTACT_PHONES:
List<PhoneEntity> phoneEntities = new ArrayList<>();
for (ProfilePropertySettingEntity child : profileProperty.getChildren()) {
phoneEntities.add(new PhoneEntity(child.getPropertyName(), child.getValue()));
updateProfileField(profile, profileProperty.getPropertyName(), phoneEntities, true);
}
break;
case Profile.CONTACT_IMS:
List<IMEntity> imEntities = new ArrayList<>();
for (ProfilePropertySettingEntity child : profileProperty.getChildren()) {
imEntities.add(new IMEntity(child.getPropertyName(), child.getValue()));
updateProfileField(profile, profileProperty.getPropertyName(), imEntities, true);
}
break;
case Profile.CONTACT_URLS:
List<URLEntity> urlEntities = new ArrayList<>();
for (ProfilePropertySettingEntity child : profileProperty.getChildren()) {
urlEntities.add(new URLEntity(child.getValue()));
updateProfileField(profile, profileProperty.getPropertyName(), urlEntities, true);
}
break;
default:
List<Map<String, String>> maps = new ArrayList<>();
profileProperty.getChildren().stream().forEach(profilePropertySettingEntity -> {
if (profilePropertySettingEntity.getValue() != null && !profilePropertySettingEntity.getValue().isBlank()
&& (profilePropertySettingEntity.getPropertyName() != null && !profilePropertySettingEntity.getPropertyName().isBlank()
|| profileProperty.isMultiValued())) {
Map<String, String> childrenMap = new HashMap<>();
childrenMap.put("key", profilePropertySettingEntity.getPropertyName());
childrenMap.put("value", profilePropertySettingEntity.getValue());
maps.add(childrenMap);
}
return;
});
updateProfileField(profile, profileProperty.getPropertyName(), maps, true);
}
List<Map<String, String>> maps = new ArrayList<>();
profileProperty.getChildren().forEach(profilePropertySettingEntity -> {
if (profilePropertySettingEntity.getValue() != null && !profilePropertySettingEntity.getValue().isBlank()
&& (profilePropertySettingEntity.getPropertyName() != null && !profilePropertySettingEntity.getPropertyName().isBlank()
|| profileProperty.isMultiValued())) {
Map<String, String> childrenMap = new HashMap<>();
childrenMap.put("key", profilePropertySettingEntity.getPropertyName());
childrenMap.put("value", profilePropertySettingEntity.getValue());
maps.add(childrenMap);
}
});
updateProfileField(profile, profileProperty.getPropertyName(), maps, true);
}
} catch (IllegalAccessException e) {
LOG.error("User {} is not allowed to update attributes", currentUser);
Expand Down Expand Up @@ -1639,6 +1670,7 @@ private String importUser(UserImportResultEntity userImportResultEntity,
user.setPassword(null);
if (userStatus) {
organizationService.getUserHandler().setEnabled(userName, Boolean.valueOf(userObject.getString("enabled")), true);
user.setEnabled(true);
}
organizationService.getUserHandler().saveUser(user, true);
onboardUser = onboardUser && existingUser.isEnabled() && (existingUser.getLastLoginTime().getTime() == existingUser.getCreatedDate().getTime());
Expand Down Expand Up @@ -1707,10 +1739,58 @@ private String importUser(UserImportResultEntity userImportResultEntity,
userObject.remove("groups");
userObject.remove("enabled");

ProfileEntity profileEntity = EntityBuilder.fromJsonString(userObject.toString(), ProfileEntity.class);
Map<String, Object> userProfileProperties = new HashMap<>();
Iterator<String> properties = userObject.keys();
while(properties.hasNext()) {
String propertyName = properties.next();
String propertyValue = userObject.getString(propertyName);
ProfilePropertySetting propertySetting;
ProfilePropertySetting parentPropertySetting = null;
if(propertyName.contains(".")) {
String[] propertyNames = propertyName.split("\\.");
if (propertyNames.length > 2) {
continue;
}
String parentProperty = propertyNames[0];
String childProperty = propertyNames[1];

if (profilePropertyService.getProfileSettingByName(propertyName) == null
&& (profilePropertyService.getProfileSettingByName(parentProperty) == null
|| profilePropertyService.getProfileSettingByName(childProperty) == null)) {
LOG.warn("Parent property {} was not found, its value won't be imported");
continue;
}
propertySetting =
profilePropertyService.getProfileSettingByName(propertyName) != null ? profilePropertyService.getProfileSettingByName(propertyName)
: profilePropertyService.getProfileSettingByName(childProperty);
} else {
propertySetting = profilePropertyService.getProfileSettingByName(propertyName);
}
if(propertySetting != null && propertySetting.getParentId() != null) {
parentPropertySetting = profilePropertyService.getProfileSettingById(propertySetting.getParentId());
}
Map<String, String> childPropertyMap = new HashMap<>();
childPropertyMap.put("value", propertyValue);
if (propertySetting != null && propertySetting.isMultiValued()) {
userProfileProperties.computeIfAbsent(propertySetting.getPropertyName(), k -> new ArrayList<Map<String, String>>());
@SuppressWarnings("unchecked")
ArrayList<Map<String, String>> values = (ArrayList<Map<String, String>>) userProfileProperties.get(propertySetting.getPropertyName());
values.add(childPropertyMap);
userProfileProperties.put(propertySetting.getPropertyName(), values);
} else if (parentPropertySetting != null && parentPropertySetting.isMultiValued()){
childPropertyMap.put("key", propertySetting.getPropertyName());
userProfileProperties.computeIfAbsent(parentPropertySetting.getPropertyName(), k -> new ArrayList<Map<String, String>>());
@SuppressWarnings("unchecked")
ArrayList<Map<String, String>> values = (ArrayList<Map<String, String>>) userProfileProperties.get(parentPropertySetting.getPropertyName());
values.add(childPropertyMap);
userProfileProperties.put(parentPropertySetting.getPropertyName(), values);
} else {
userProfileProperties.put(propertyName.toLowerCase(), propertyValue);
}
}
String warnMessage = null;
try {
saveProfile(userName, profileEntity);
saveProfile(userName, userProfileProperties);
} catch (ObjectNotFoundException e) {
// Not a mandatory operation such as IDM store updates
// This may happen when user is disabled
Expand Down Expand Up @@ -1748,14 +1828,14 @@ private boolean isEmailAlreadyExists(String username, String email) throws Excep
return usersLength > 1 || (usersLength == 1 && !StringUtils.equals(users.load(0, 1)[0].getUserName(), username));
}

private void saveProfile(String username, ProfileEntity profileEntity) throws Exception {
private void saveProfile(String username, Map<String, Object> profileProperties) throws Exception {
Identity userIdentity = getUserIdentity(username);
if (userIdentity == null) {
throw new ObjectNotFoundException("User identity of " + username + " wasn't found. It can be due to a disabled user.");
} else {
Profile profile = userIdentity.getProfile();

Set<Entry<String, Object>> profileEntries = profileEntity.getDataEntity().entrySet();
Set<Entry<String, Object>> profileEntries = profileProperties.entrySet();
for (Entry<String, Object> entry : profileEntries) {
String name = entry.getKey();
Object value = entry.getValue();
Expand Down Expand Up @@ -1883,100 +1963,6 @@ private void updateProfileField(Profile profile,
} finally {
uploadService.removeUploadResource(value.toString());
}
} else if (Profile.CONTACT_IMS.equals(name)) {
@SuppressWarnings("unchecked")
List<IMEntity> imEntities = (List<IMEntity>) value;
if (imEntities == null || imEntities.isEmpty()) {
profile.setProperty(Profile.CONTACT_IMS, Collections.emptyList());
} else {
List<Map<String, String>> imMaps = new ArrayList<>();
for (IMEntity imEntity : imEntities) {
String imType = imEntity.getImType();
String imId = imEntity.getImId();
if (StringUtils.isBlank(imId) || StringUtils.isBlank(imType)) {
continue;
}
Map<String, String> imMap = new HashMap<>();
imMap.put("key", imType);
imMap.put("value", imId);
imMaps.add(imMap);
}
profile.setProperty(Profile.CONTACT_IMS, imMaps);
}

if (save) {
identityManager.updateProfile(profile, getCurrentUser(), true);
}
} else if (Profile.CONTACT_PHONES.equals(name)) {
@SuppressWarnings("unchecked")
List<PhoneEntity> phoneEntities = (List<PhoneEntity>) value;
if (phoneEntities == null || phoneEntities.isEmpty()) {
profile.setProperty(Profile.CONTACT_PHONES, Collections.emptyList());
} else {
List<Map<String, String>> phoneMaps = new ArrayList<>();
for (PhoneEntity phoneEntity : phoneEntities) {
String phoneType = phoneEntity.getPhoneType();
String phoneNumber = phoneEntity.getPhoneNumber();
if (StringUtils.isBlank(phoneType) || StringUtils.isBlank(phoneNumber)) {
continue;
}
Map<String, String> phoneMap = new HashMap<>();
phoneMap.put("key", phoneType);
phoneMap.put("value", phoneNumber);
phoneMaps.add(phoneMap);
}
profile.setProperty(Profile.CONTACT_PHONES, phoneMaps);
}

if (save) {
identityManager.updateProfile(profile, getCurrentUser(), true);
}
} else if (Profile.CONTACT_URLS.equals(name)) {
@SuppressWarnings("unchecked")
List<URLEntity> urlEntities = (List<URLEntity>) value;
if (urlEntities == null || urlEntities.isEmpty()) {
profile.setProperty(Profile.CONTACT_URLS, Collections.emptyList());
} else {
List<Map<String, String>> urlMaps = new ArrayList<>();
for (URLEntity urlEntity : urlEntities) {
String url = urlEntity.getUrl();
if (StringUtils.isBlank(url)) {
continue;
}
Map<String, String> urlMap = new HashMap<>();
urlMap.put("value", url);
urlMaps.add(urlMap);
}
profile.setProperty(Profile.CONTACT_URLS, urlMaps);
}

if (save) {
identityManager.updateProfile(profile, getCurrentUser(), true);
}
} else if (Profile.EXPERIENCES.equals(name)) {
@SuppressWarnings("unchecked")
List<ExperienceEntity> experienceEntities = (List<ExperienceEntity>) value;
if (experienceEntities == null || experienceEntities.isEmpty()) {
profile.setProperty(Profile.EXPERIENCES, Collections.emptyList());
} else {
List<Map<String, Object>> experienceMaps = new ArrayList<>();
for (ExperienceEntity experienceEntity : experienceEntities) {
Map<String, Object> experienceMap = new HashMap<>();
experienceMap.put(Profile.EXPERIENCES_ID, experienceEntity.getId());
experienceMap.put(Profile.EXPERIENCES_COMPANY, experienceEntity.getCompany());
experienceMap.put(Profile.EXPERIENCES_DESCRIPTION, experienceEntity.getDescription());
experienceMap.put(Profile.EXPERIENCES_POSITION, experienceEntity.getPosition());
experienceMap.put(Profile.EXPERIENCES_SKILLS, experienceEntity.getSkills());
experienceMap.put(Profile.EXPERIENCES_IS_CURRENT, experienceEntity.getIsCurrent());
experienceMap.put(Profile.EXPERIENCES_START_DATE, experienceEntity.getStartDate());
experienceMap.put(Profile.EXPERIENCES_END_DATE, experienceEntity.getEndDate());
experienceMaps.add(experienceMap);
}
profile.setProperty(Profile.EXPERIENCES, experienceMaps);
}
if (save) {
identityManager.updateProfile(profile, getCurrentUser(), true);
}
} else {
profile.setProperty(name, value);
if (save) {
Expand Down
Loading

0 comments on commit 72d115c

Please sign in to comment.