| /*
|
| * Copyright @ 2013 CurisTEC, S.A.S. All Rights Reserved.
|
| */
|
| package net.curisit.securis.db;
|
|
|
| import java.io.Serializable;
|
| import java.util.ArrayList;
|
| import java.util.Collection;
|
| import java.util.Date;
|
| import java.util.HashSet;
|
| import java.util.List;
|
| import java.util.Set;
|
| import java.util.stream.Collectors;
|
|
|
| import jakarta.persistence.Column;
|
| import jakarta.persistence.Entity;
|
| import jakarta.persistence.Id;
|
| import jakarta.persistence.JoinColumn;
|
| import jakarta.persistence.JoinTable;
|
| import jakarta.persistence.ManyToMany;
|
| import jakarta.persistence.NamedQueries;
|
| import jakarta.persistence.NamedQuery;
|
| import jakarta.persistence.Table;
|
|
|
| import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
| import com.fasterxml.jackson.annotation.JsonIgnore;
|
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
| import com.fasterxml.jackson.annotation.JsonInclude;
|
| import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
| import com.fasterxml.jackson.annotation.JsonProperty;
|
|
|
| /**
|
| * User
|
| * <p>
|
| * Application user with bitmask-based roles and membership in organizations
|
| * and applications. Exposes convenience JSON properties to fetch/set related
|
| * entity IDs without fetching full entities.
|
| *
|
| * Mapping details:
|
| * - Table: user
|
| * - ManyToMany organizations via user_organization
|
| * - ManyToMany applications via user_application
|
| * - Named queries: list-users, get-user, auth-user, delete-all-users
|
| *
|
| * Roles:
|
| * - Stored as integer bitmask; see {@link Rol}.
|
| *
|
| * @author JRA
|
| * Last reviewed by JRA on Oct 5, 2025.
|
| */
|
| @JsonAutoDetect
|
| @JsonInclude(Include.NON_NULL)
|
| @JsonIgnoreProperties(ignoreUnknown = true)
|
| @Entity
|
| @Table(name = "user")
|
| @NamedQueries({
|
| @NamedQuery(name = "list-users", query = "SELECT u FROM User u"),
|
| @NamedQuery(name = "get-user", query = "SELECT u FROM User u where u.username = :username"),
|
| @NamedQuery(name = "auth-user", query = "SELECT u FROM User u where u.username = :username and u.password = :password"),
|
| @NamedQuery(name = "delete-all-users", query = "delete FROM User u")
|
| })
|
| public class User implements Serializable {
|
|
|
| private static final long serialVersionUID = 1L;
|
|
|
| /** Username (PK). */
|
| @Id
|
| private String username;
|
|
|
| /** Password hash/string (not exposed in JSON). */
|
| private String password;
|
|
|
| @JsonProperty("first_name")
|
| @Column(name = "first_name")
|
| private String firstName;
|
|
|
| @JsonProperty("last_name")
|
| @Column(name = "last_name")
|
| private String lastName;
|
|
|
| /** Roles bitmask (see Rol constants). */
|
| private int roles;
|
|
|
| @Column(name = "last_login")
|
| private Date lastLogin;
|
|
|
| @Column(name = "modification_timestamp")
|
| private Date modificationTimestamp;
|
|
|
| @Column(name = "creation_timestamp")
|
| @JsonProperty("creation_timestamp")
|
| private Date creationTimestamp;
|
|
|
| private String lang;
|
| private String email;
|
|
|
| @JsonIgnore
|
| @ManyToMany
|
| @JoinTable(name = "user_organization",
|
| joinColumns = { @JoinColumn(name = "username", referencedColumnName = "username") },
|
| inverseJoinColumns = { @JoinColumn(name = "organization_id", referencedColumnName = "id") })
|
| private Set<Organization> organizations;
|
|
|
| @JsonIgnore
|
| @ManyToMany
|
| @JoinTable(name = "user_application",
|
| joinColumns = { @JoinColumn(name = "username", referencedColumnName = "username") },
|
| inverseJoinColumns = { @JoinColumn(name = "application_id", referencedColumnName = "id") })
|
| private Set<Application> applications;
|
|
|
| // -------- Getters & setters --------
|
|
|
| /**
|
| * getUsername<p>
|
| * Return username (PK).
|
| *
|
| * @return username
|
| */
|
| public String getUsername() { return username; }
|
|
|
| /**
|
| * setUsername<p>
|
| * Set username (PK).
|
| *
|
| * @param username
|
| */
|
| public void setUsername(String username) { this.username = username; }
|
|
|
| /**
|
| * getDummyPassword<p>
|
| * Forces password to be omitted in JSON responses.
|
| *
|
| * @return always null
|
| */
|
| @JsonProperty("password")
|
| public String getDummyPassword() { return null; }
|
|
|
| /**
|
| * getPassword<p>
|
| * Return raw/hashed password (internal use).
|
| *
|
| * @return password
|
| */
|
| public String getPassword() { return password; }
|
|
|
| /**
|
| * setPassword<p>
|
| * Set raw/hashed password (internal use).
|
| *
|
| * @param password
|
| */
|
| public void setPassword(String password) { this.password = password; }
|
|
|
| /**
|
| * getRoles<p>
|
| * Return list of individual role flags contained in the bitmask.
|
| *
|
| * @return list of role integers or null if no roles
|
| */
|
| public List<Integer> getRoles() {
|
| if (roles == 0) return null;
|
| List<Integer> aux = new ArrayList<>();
|
| for (int rol : Rol.ALL) {
|
| if ((roles & rol) != 0) aux.add(rol);
|
| }
|
| return aux;
|
| }
|
|
|
| /**
|
| * setRoles<p>
|
| * Set the roles bitmask from a list of role flags.
|
| *
|
| * @param roles list of flags
|
| */
|
| public void setRoles(List<Integer> roles) {
|
| this.roles = 0;
|
| if (roles != null) {
|
| for (Integer rol : roles) this.roles |= rol;
|
| }
|
| }
|
|
|
| /**
|
| * getFirstName<p>
|
| * Return first name.
|
| *
|
| * @return firstName
|
| */
|
| public String getFirstName() { return firstName; }
|
|
|
| /**
|
| * setFirstName<p>
|
| * Set first name.
|
| *
|
| * @param firstName
|
| */
|
| public void setFirstName(String firstName) { this.firstName = firstName; }
|
|
|
| /**
|
| * getLastName<p>
|
| * Return last name.
|
| *
|
| * @return lastName
|
| */
|
| public String getLastName() { return lastName; }
|
|
|
| /**
|
| * setLastName<p>
|
| * Set last name.
|
| *
|
| * @param lastName
|
| */
|
| public void setLastName(String lastName) { this.lastName = lastName; }
|
|
|
| /**
|
| * getLastLogin<p>
|
| * Return last login timestamp.
|
| *
|
| * @return lastLogin
|
| */
|
| public Date getLastLogin() { return lastLogin; }
|
|
|
| /**
|
| * setLastLogin<p>
|
| * Set last login timestamp.
|
| *
|
| * @param lastLogin
|
| */
|
| public void setLastLogin(Date lastLogin) { this.lastLogin = lastLogin; }
|
|
|
| /**
|
| * getModificationTimestamp<p>
|
| * Return modification timestamp.
|
| *
|
| * @return modificationTimestamp
|
| */
|
| public Date getModificationTimestamp() { return modificationTimestamp; }
|
|
|
| /**
|
| * setModificationTimestamp<p>
|
| * Set modification timestamp.
|
| *
|
| * @param modificationTimestamp
|
| */
|
| public void setModificationTimestamp(Date modificationTimestamp) { this.modificationTimestamp = modificationTimestamp; }
|
|
|
| /**
|
| * getCreationTimestamp<p>
|
| * Return creation timestamp.
|
| *
|
| * @return creationTimestamp
|
| */
|
| public Date getCreationTimestamp() { return creationTimestamp; }
|
|
|
| /**
|
| * setCreationTimestamp<p>
|
| * Set creation timestamp.
|
| *
|
| * @param creationTimestamp
|
| */
|
| public void setCreationTimestamp(Date creationTimestamp) { this.creationTimestamp = creationTimestamp; }
|
|
|
| /**
|
| * getLang<p>
|
| * Return preferred language.
|
| *
|
| * @return lang
|
| */
|
| public String getLang() { return lang; }
|
|
|
| /**
|
| * setLang<p>
|
| * Set preferred language.
|
| *
|
| * @param lang
|
| */
|
| public void setLang(String lang) { this.lang = lang; }
|
|
|
| /**
|
| * getEmail<p>
|
| * Return email address.
|
| *
|
| * @return email
|
| */
|
| public String getEmail() { return email; }
|
|
|
| /**
|
| * setEmail<p>
|
| * Set email address.
|
| *
|
| * @param email
|
| */
|
| public void setEmail(String email) { this.email = email; }
|
|
|
| /**
|
| * getOrganizations<p>
|
| * Return organizations (entity set).
|
| *
|
| * @return organizations
|
| */
|
| public Set<Organization> getOrganizations() { return organizations; }
|
|
|
| /**
|
| * setOrganizations<p>
|
| * Set organizations (entity set).
|
| *
|
| * @param organizations
|
| */
|
| public void setOrganizations(Set<Organization> organizations) { this.organizations = organizations; }
|
|
|
| /**
|
| * getApplications<p>
|
| * Return applications (entity set).
|
| *
|
| * @return applications
|
| */
|
| public Set<Application> getApplications() { return applications; }
|
|
|
| /**
|
| * setApplications<p>
|
| * Set applications (entity set).
|
| *
|
| * @param applications
|
| */
|
| public void setApplications(Set<Application> applications) { this.applications = applications; }
|
|
|
| // -------- JSON helpers for related IDs --------
|
|
|
| /**
|
| * setOrgsIds<p>
|
| * Replace organizations from a list of org IDs.
|
| *
|
| * @param orgsIds
|
| */
|
| @JsonProperty("organizations_ids")
|
| public void setOrgsIds(List<Integer> orgsIds) {
|
| organizations = new HashSet<>();
|
| for (Integer orgid : orgsIds) {
|
| Organization o = new Organization();
|
| o.setId(orgid);
|
| organizations.add(o);
|
| }
|
| }
|
|
|
| /**
|
| * getOrgsIds<p>
|
| * Expose organization IDs.
|
| *
|
| * @return orgsIds
|
| */
|
| @JsonProperty("organizations_ids")
|
| public Set<Integer> getOrgsIds() {
|
| if (organizations == null) return null;
|
| Set<Integer> ids = new HashSet<>();
|
| for (Organization org : organizations) ids.add(org.getId());
|
| return ids;
|
| }
|
|
|
| /**
|
| * setAppsIds<p>
|
| * Replace applications from a collection of app IDs.
|
| *
|
| * @param appIds
|
| */
|
| @JsonProperty("applications_ids")
|
| public void setAppsIds(Collection<Integer> appIds) {
|
| applications = new HashSet<>();
|
| for (Integer appid : appIds) {
|
| Application a = new Application();
|
| a.setId(appid);
|
| applications.add(a);
|
| }
|
| }
|
|
|
| /**
|
| * getAppsIds<p>
|
| * Expose application IDs.
|
| *
|
| * @return appsIds
|
| */
|
| @JsonProperty("applications_ids")
|
| public Set<Integer> getAppsIds() {
|
| if (applications == null) return null;
|
| Set<Integer> ids = new HashSet<>();
|
| for (Application app : applications) ids.add(app.getId());
|
| return ids;
|
| }
|
|
|
| // -------- Derived scopes --------
|
|
|
| /**
|
| * getAllOrgsIds<p>
|
| * Compute full organization scope including descendants.
|
| *
|
| * @return set of org IDs (may be null when no organizations)
|
| */
|
| @JsonIgnore
|
| public Set<Integer> getAllOrgsIds() {
|
| if (organizations == null) return null;
|
| Set<Integer> ids = new HashSet<>();
|
| includeAllOrgs(this.organizations, ids);
|
| return ids;
|
| }
|
|
|
| /**
|
| * getAllAppsIds<p>
|
| * Compute application scope (direct associations only).
|
| *
|
| * @return set of application IDs (may be null when no applications)
|
| */
|
| @JsonIgnore
|
| public Set<Integer> getAllAppsIds() {
|
| if (applications == null) return null;
|
| return this.applications.parallelStream().map(Application::getId).collect(Collectors.toSet());
|
| }
|
|
|
| /**
|
| * includeAllOrgs<p>
|
| * Walk organization hierarchy to include all descendants.
|
| *
|
| * @param list current level orgs
|
| * @param orgIds accumulator of ids
|
| */
|
| private void includeAllOrgs(Set<Organization> list, Set<Integer> orgIds) {
|
| for (Organization org : list) {
|
| orgIds.add(org.getId());
|
| includeAllOrgs(org.getChildOrganizations(), orgIds);
|
| }
|
| }
|
|
|
| /**
|
| * toString<p>
|
| * Get the string describing the current object
|
| *
|
| * @return object string
|
| */
|
| @Override
|
| public String toString() {
|
| return "{User: " + username + " Name: " + firstName + " " + lastName + ", last login: " + lastLogin + "}";
|
| }
|
|
|
|
|
| /**
|
| * Rol
|
| * <p>
|
| * Bitmask constants for user roles. Each constant must occupy a distinct bit.
|
| */
|
| public static class Rol {
|
| public static final int ADVANCE = 0x01;
|
| public static final int ADMIN = 0x02;
|
| public static final int BASIC = 0x04;
|
| public static final int API_CLIENT= 0x80;
|
| public static final int[] ALL = new int[] { ADVANCE, ADMIN, BASIC, API_CLIENT };
|
| }
|
| }
|