user info changes

This commit is contained in:
Efstratios Giannopoulos 2023-11-29 17:41:15 +02:00
parent 0decfb1474
commit b40134e6a7
7 changed files with 207 additions and 6 deletions

View File

@ -73,7 +73,10 @@ public class AuditableAction {
public static final EventId User_Delete = new EventId(11003, "User_Delete"); public static final EventId User_Delete = new EventId(11003, "User_Delete");
public static final EventId User_LookupByEmail = new EventId(11004, "User_LookupByEmail"); public static final EventId User_LookupByEmail = new EventId(11004, "User_LookupByEmail");
public static final EventId User_ExportCsv = new EventId(11005, "User_ExportCsv"); public static final EventId User_ExportCsv = new EventId(11005, "User_ExportCsv");
public static final EventId User_PersistRoles = new EventId(11004, "User_PersistRoles"); public static final EventId User_PersistRoles = new EventId(11006, "User_PersistRoles");
public static final EventId User_LanguageMine = new EventId(11007, "User_LanguageMine");
public static final EventId User_TimezoneMine = new EventId(11008, "User_TimezoneMine");
public static final EventId User_CultureMine = new EventId(11009, "User_CultureMine");
public static final EventId Tenant_Query = new EventId(12000, "Tenant_Query"); public static final EventId Tenant_Query = new EventId(12000, "Tenant_Query");
public static final EventId Tenant_Lookup = new EventId(12001, "Tenant_Lookup"); public static final EventId Tenant_Lookup = new EventId(12001, "Tenant_Lookup");

View File

@ -19,6 +19,9 @@ import java.util.UUID;
public interface UserService { public interface UserService {
User persist(UserPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException; User persist(UserPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException;
void updateLanguageMine(String language) throws InvalidApplicationException, JsonProcessingException;
void updateTimezoneMine(String timezone) throws JsonProcessingException;
void updateCultureMine(String culture) throws JsonProcessingException;
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException;

View File

@ -7,6 +7,7 @@ import eu.eudat.authorization.Permission;
import eu.eudat.commons.JsonHandlingService; import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.ContactInfoType; import eu.eudat.commons.enums.ContactInfoType;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.commons.types.user.AdditionalInfoEntity; import eu.eudat.commons.types.user.AdditionalInfoEntity;
import eu.eudat.convention.ConventionService; import eu.eudat.convention.ConventionService;
import eu.eudat.data.UserEntity; import eu.eudat.data.UserEntity;
@ -78,6 +79,7 @@ public class UserServiceImpl implements UserService {
private final EventBroker eventBroker; private final EventBroker eventBroker;
private final JsonHandlingService jsonHandlingService; private final JsonHandlingService jsonHandlingService;
private final QueryFactory queryFactory; private final QueryFactory queryFactory;
private final UserScope userScope;
@Autowired @Autowired
public UserServiceImpl( public UserServiceImpl(
EntityManager entityManager, EntityManager entityManager,
@ -89,7 +91,8 @@ public class UserServiceImpl implements UserService {
MessageSource messageSource, MessageSource messageSource,
EventBroker eventBroker, EventBroker eventBroker,
JsonHandlingService jsonHandlingService, JsonHandlingService jsonHandlingService,
QueryFactory queryFactory) { QueryFactory queryFactory,
UserScope userScope) {
this.entityManager = entityManager; this.entityManager = entityManager;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory; this.deleterFactory = deleterFactory;
@ -100,6 +103,7 @@ public class UserServiceImpl implements UserService {
this.eventBroker = eventBroker; this.eventBroker = eventBroker;
this.jsonHandlingService = jsonHandlingService; this.jsonHandlingService = jsonHandlingService;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.userScope = userScope;
} }
//region persist //region persist
@ -221,4 +225,86 @@ public class UserServiceImpl implements UserService {
this.eventBroker.emit(new UserTouchedEvent(data.getId())); this.eventBroker.emit(new UserTouchedEvent(data.getId()));
return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, User._id), data); return this.builderFactory.builder(UserBuilder.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermissionOrPublic).build(BaseFieldSet.build(fields, User._id), data);
} }
//region mine
@Override
public void updateLanguageMine(String language) throws JsonProcessingException {
logger.debug(new MapLogEntry("persisting User language").And("language", language));
UUID userId = this.userScope.getUserIdSafe();
if (userId == null) throw new MyForbiddenException(this.errors.getForbidden().getCode(), this.errors.getForbidden().getMessage());
UserEntity data = this.entityManager.find(UserEntity.class, userId);
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), User.class.getSimpleName()}, LocaleContextHolder.getLocale()));
AdditionalInfoEntity additionalInfoEntity = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, data.getAdditionalInfo());
if (additionalInfoEntity == null) additionalInfoEntity = new AdditionalInfoEntity();
additionalInfoEntity.setLanguage(language);
data.setAdditionalInfo(this.jsonHandlingService.toJson(additionalInfoEntity));
data.setUpdatedAt(Instant.now());
this.entityManager.merge(data);
this.entityManager.flush();
this.eventBroker.emit(new UserTouchedEvent(data.getId()));
}
@Override
public void updateTimezoneMine(String timezone) throws JsonProcessingException {
logger.debug(new MapLogEntry("persisting User timezone").And("timezone", timezone));
UUID userId = this.userScope.getUserIdSafe();
if (userId == null) throw new MyForbiddenException(this.errors.getForbidden().getCode(), this.errors.getForbidden().getMessage());
UserEntity data = this.entityManager.find(UserEntity.class, userId);
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), User.class.getSimpleName()}, LocaleContextHolder.getLocale()));
AdditionalInfoEntity additionalInfoEntity = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, data.getAdditionalInfo());
if (additionalInfoEntity == null) additionalInfoEntity = new AdditionalInfoEntity();
additionalInfoEntity.setTimezone(timezone);
data.setAdditionalInfo(this.jsonHandlingService.toJson(additionalInfoEntity));
data.setUpdatedAt(Instant.now());
this.entityManager.merge(data);
this.entityManager.flush();
this.eventBroker.emit(new UserTouchedEvent(data.getId()));
}
@Override
public void updateCultureMine(String culture) throws JsonProcessingException {
logger.debug(new MapLogEntry("persisting User culture").And("culture", culture));
UUID userId = this.userScope.getUserIdSafe();
if (userId == null) throw new MyForbiddenException(this.errors.getForbidden().getCode(), this.errors.getForbidden().getMessage());
UserEntity data = this.entityManager.find(UserEntity.class, userId);
if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), User.class.getSimpleName()}, LocaleContextHolder.getLocale()));
AdditionalInfoEntity additionalInfoEntity = this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, data.getAdditionalInfo());
if (additionalInfoEntity == null) additionalInfoEntity = new AdditionalInfoEntity();
additionalInfoEntity.setCulture(culture);
data.setAdditionalInfo(this.jsonHandlingService.toJson(additionalInfoEntity));
data.setUpdatedAt(Instant.now());
this.entityManager.merge(data);
this.entityManager.flush();
this.eventBroker.emit(new UserTouchedEvent(data.getId()));
}
//endregion
} }

View File

@ -56,6 +56,10 @@ public class PrincipalController {
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._authenticatedAt), BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._authenticatedAt),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._expiresAt), BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._expiresAt),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._more), BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._more),
BaseFieldSet.asIndexer(Account._profile, Account.UserProfileInfo._avatarUrl),
BaseFieldSet.asIndexer(Account._profile, Account.UserProfileInfo._language),
BaseFieldSet.asIndexer(Account._profile, Account.UserProfileInfo._culture),
BaseFieldSet.asIndexer(Account._profile, Account.UserProfileInfo._timezone),
Account._roles, Account._roles,
Account._permissions); Account._permissions);
} }

View File

@ -173,6 +173,39 @@ public class UserController {
return model; return model;
} }
@GetMapping("mine/language/{language}")
@Transactional
public void updateLanguageMine(@PathVariable("language") String language) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("language", language));
this.userTypeService.updateLanguageMine(language);
this.auditService.track(AuditableAction.User_LanguageMine, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("language", language)
));
}
@GetMapping("mine/timezone/{timezone}")
@Transactional
public void updateTimezoneMine(@PathVariable("timezone") String timezone) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("timezone", timezone));
this.userTypeService.updateTimezoneMine(timezone);
this.auditService.track(AuditableAction.User_TimezoneMine, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("timezone", timezone)
));
}
@GetMapping("mine/culture/{culture}")
@Transactional
public void updateCultureMine(@PathVariable("culture") String culture) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JsonProcessingException {
logger.debug(new MapLogEntry("persisting" + User.class.getSimpleName()).And("culture", culture));
this.userTypeService.updateCultureMine(culture);
this.auditService.track(AuditableAction.User_CultureMine, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("culture", culture)
));
}
@PostMapping("persist") @PostMapping("persist")
@Transactional @Transactional
public User persist(@MyValidate @RequestBody UserPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException { public User persist(@MyValidate @RequestBody UserPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {

View File

@ -124,6 +124,48 @@ public class Account {
} }
} }
public static class UserProfileInfo{
public String culture;
public final static String _culture = "culture";
public String language;
public final static String _language = "language";
public String timezone;
public final static String _timezone = "timezone";
public String avatarUrl;
public final static String _avatarUrl = "avatarUrl";
public String getCulture() {
return culture;
}
public void setCulture(String culture) {
this.culture = culture;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
}
public final static String _isAuthenticated = "isAuthenticated"; public final static String _isAuthenticated = "isAuthenticated";
private Boolean isAuthenticated; private Boolean isAuthenticated;
@ -139,6 +181,9 @@ public class Account {
public final static String _principal = "principal"; public final static String _principal = "principal";
private PrincipalInfo principal; private PrincipalInfo principal;
public final static String _profile = "profile";
private UserProfileInfo profile;
public final static String _permissions = "permissions"; public final static String _permissions = "permissions";
private List<String> permissions; private List<String> permissions;
@ -177,4 +222,12 @@ public class Account {
public void setPermissions(List<String> permissions) { public void setPermissions(List<String> permissions) {
this.permissions = permissions; this.permissions = permissions;
} }
public UserProfileInfo getProfile() {
return profile;
}
public void setProfile(UserProfileInfo profile) {
this.profile = profile;
}
} }

View File

@ -1,19 +1,22 @@
package eu.eudat.models.v2; package eu.eudat.models.v2;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.scope.user.UserScope; import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.commons.types.user.AdditionalInfoEntity;
import eu.eudat.data.UserEntity; import eu.eudat.data.UserEntity;
import eu.eudat.data.UserRoleEntity; import eu.eudat.model.User;
import eu.eudat.logic.services.ApiContext;
import gr.cite.commons.web.authz.configuration.AuthorizationConfiguration; import gr.cite.commons.web.authz.configuration.AuthorizationConfiguration;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver; import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.MyPrincipal; import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor; import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorKeys; import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorKeys;
import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.BaseFieldSet; import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet; import gr.cite.tools.fieldset.FieldSet;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.management.InvalidApplicationException; import javax.management.InvalidApplicationException;
@ -27,12 +30,16 @@ public class AccountBuilder {
private final Set<String> excludeMoreClaim; private final Set<String> excludeMoreClaim;
private final CurrentPrincipalResolver currentPrincipalResolver; private final CurrentPrincipalResolver currentPrincipalResolver;
private final AuthorizationConfiguration authorizationConfiguration; private final AuthorizationConfiguration authorizationConfiguration;
private final JsonHandlingService jsonHandlingService;
private final UserScope userScope; private final UserScope userScope;
public AccountBuilder(ClaimExtractor claimExtractor, CurrentPrincipalResolver currentPrincipalResolver, AuthorizationConfiguration authorizationConfiguration,UserScope userScope) { private final EntityManager entityManager;
public AccountBuilder(ClaimExtractor claimExtractor, CurrentPrincipalResolver currentPrincipalResolver, AuthorizationConfiguration authorizationConfiguration, JsonHandlingService jsonHandlingService, UserScope userScope, EntityManager entityManager) {
this.claimExtractor = claimExtractor; this.claimExtractor = claimExtractor;
this.currentPrincipalResolver = currentPrincipalResolver; this.currentPrincipalResolver = currentPrincipalResolver;
this.authorizationConfiguration = authorizationConfiguration; this.authorizationConfiguration = authorizationConfiguration;
this.jsonHandlingService = jsonHandlingService;
this.userScope = userScope; this.userScope = userScope;
this.entityManager = entityManager;
this.excludeMoreClaim = Set.of( this.excludeMoreClaim = Set.of(
ClaimExtractorKeys.Subject, ClaimExtractorKeys.Subject,
ClaimExtractorKeys.Name, ClaimExtractorKeys.Name,
@ -94,6 +101,18 @@ public class AccountBuilder {
Set<String> permissions = authorizationConfiguration.permissionsOfRoles(roles); Set<String> permissions = authorizationConfiguration.permissionsOfRoles(roles);
model.setPermissions(new ArrayList<>(permissions)); model.setPermissions(new ArrayList<>(permissions));
} }
FieldSet profileFields = fields.extractPrefixed(BaseFieldSet.asIndexerPrefix(Account._profile));
if (!profileFields.isEmpty() && this.userScope.getUserIdSafe() != null){
model.setProfile(new Account.UserProfileInfo());
UserEntity data = this.entityManager.find(UserEntity.class, this.userScope.getUserIdSafe());
AdditionalInfoEntity additionalInfoEntity = data == null ? null : this.jsonHandlingService.fromJsonSafe(AdditionalInfoEntity.class, data.getAdditionalInfo());
if (profileFields.hasField(Account.UserProfileInfo._avatarUrl) && additionalInfoEntity != null) model.getProfile().setAvatarUrl(additionalInfoEntity.getAvatarUrl());
if (profileFields.hasField(Account.UserProfileInfo._language) && additionalInfoEntity != null) model.getProfile().setLanguage(additionalInfoEntity.getLanguage());
if (profileFields.hasField(Account.UserProfileInfo._timezone) && additionalInfoEntity != null) model.getProfile().setTimezone(additionalInfoEntity.getTimezone());
if (profileFields.hasField(Account.UserProfileInfo._culture) && additionalInfoEntity != null) model.getProfile().setCulture(additionalInfoEntity.getCulture());
}
return model; return model;
} }
} }