Files
erp-imprimelibros/src/main/java/com/imprimelibros/erp/users/User.java

262 lines
6.9 KiB
Java

package com.imprimelibros.erp.users;
import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import java.util.Set;
import org.hibernate.annotations.Formula;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.hibernate.annotations.SQLRestriction;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
@Entity
@Table(name = "users", uniqueConstraints = {
@UniqueConstraint(name = "uk_users_username", columnNames = "username")
})
@SQLRestriction("deleted = false")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "fullname")
@NotBlank(message = "{validation.required}")
private String fullName;
@Column(name = "username", nullable = false, length = 190)
@Email(message = "{validation.email}")
@NotBlank(message = "{validation.required}")
private String userName;
@Column(name = "password")
@NotBlank(message = "{validation.required}")
private String password;
@Column(name = "enabled")
private boolean enabled;
@Column(name = "deleted", nullable = false)
private boolean deleted = false;
@Column(name = "deleted_at")
private LocalDateTime deletedAt;
@Column(name = "deleted_by")
private Long deletedBy;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REMOVE }, orphanRemoval = true)
@SQLRestriction("deleted = false")
@JsonIgnore
private Set<UserRole> rolesLink = new HashSet<>();
// SUPERADMIN=3, ADMIN=2, USER=1 (ajusta a tus nombres reales)
@Formula("""
(
select coalesce(max(
case r.name
when 'SUPERADMIN' then 3
when 'ADMIN' then 2
else 1
end
), 0)
from users_roles ur
join roles r on r.id = ur.role_id
where ur.user_id = id
)
""")
private Integer roleRank;
@Formula("""
(select group_concat(lower(r.name) order by r.name separator ', ')
from users_roles ur join roles r on r.id = ur.role_id
where ur.user_id = id)
""")
private String rolesConcat;
/* Constructors */
public User() {
}
public User(String fullName, String userName, String password, boolean enabled) {
this.fullName = fullName;
this.userName = userName;
this.password = password;
this.enabled = enabled;
}
public User(String fullName, String userName, String password, boolean enabled,
Set<UserRole> roles) {
this.fullName = fullName;
this.userName = userName;
this.password = password;
this.enabled = enabled;
this.rolesLink = roles;
}
/* Getters and Setters */
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Transient
public Set<Role> getRoles() {
return rolesLink.stream()
.filter(ur -> !ur.isDeleted())
.map(UserRole::getRole)
.collect(Collectors.toSet());
}
@JsonProperty("roles")
public List<String> getRoleNames() {
return this.getRoles().stream()
.map(Role::getName)
.filter(java.util.Objects::nonNull)
.map(String::trim)
.toList();
}
public void setRoles(Set<Role> desired) {
if (desired == null)
desired = Collections.emptySet();
// 1) ids deseados
Set<Long> desiredIds = desired.stream()
.map(Role::getId)
.collect(Collectors.toSet());
// 2) Soft-delete de vínculos activos que ya no se desean
this.rolesLink.stream()
.filter(ur -> !ur.isDeleted() && !desiredIds.contains(ur.getRole().getId()))
.forEach(UserRole::softDelete);
// 3) Para cada rol deseado: si hay vínculo borrado => reactivar; si no existe
// => crear
for (Role role : desired) {
// ya activo
boolean activeExists = this.rolesLink.stream()
.anyMatch(ur -> !ur.isDeleted() && ur.getRole().getId().equals(role.getId()));
if (activeExists)
continue;
// existe borrado => reactivar
Optional<UserRole> deletedLink = this.rolesLink.stream()
.filter(ur -> ur.isDeleted() && ur.getRole().getId().equals(role.getId()))
.findFirst();
if (deletedLink.isPresent()) {
UserRole ur = deletedLink.get();
ur.setDeleted(false);
ur.setDeletedAt(null);
} else {
// crear nuevo vínculo
UserRole ur = new UserRole(this, role);
this.rolesLink.add(ur);
// si tienes la colección inversa en Role:
role.getUsersLink().add(ur);
}
}
}
public Integer getRoleRank() {
return roleRank;
}
public String getRolesConcat() {
return rolesConcat;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public LocalDateTime getDeletedAt() {
return deletedAt;
}
public void setDeletedAt(LocalDateTime deletedAt) {
this.deletedAt = deletedAt;
}
public Long getDeletedBy() {
return deletedBy;
}
public void setDeletedBy(Long deletedBy) {
this.deletedBy = deletedBy;
}
public Set<UserRole> getRolesLink() {
return rolesLink;
}
public void setRolesLink(Set<UserRole> rolesLink) {
this.rolesLink = rolesLink;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", fullName='" + fullName + '\'' +
", userName='" + userName + '\'' +
", enabled=" + enabled +
'}';
}
}