init commit

This commit is contained in:
David Melendez
2026-01-14 22:41:30 +01:00
parent 0ea321b6d8
commit 1c026c7be8
92 changed files with 15836 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
@Schema(description = "Generic API response wrapper")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> {
@Schema(description = "Response status")
private String status;
@Schema(description = "Response message")
private String message;
@Schema(description = "Response data")
private T data;
@Schema(description = "Error details")
private String error;
public ApiResponse() {}
public ApiResponse(String status, String message) {
this.status = status;
this.message = message;
}
public ApiResponse(String status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
// Static factory methods
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>("success", "Operation completed successfully", data);
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>("success", message, data);
}
public static <T> ApiResponse<T> error(String message) {
ApiResponse<T> response = new ApiResponse<>("error", message);
response.setError(message);
return response;
}
public static <T> ApiResponse<T> error(String message, String error) {
ApiResponse<T> response = new ApiResponse<>("error", message);
response.setError(error);
return response;
}
// Getters and Setters
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public T getData() { return data; }
public void setData(T data) { this.data = data; }
public String getError() { return error; }
public void setError(String error) { this.error = error; }
}

View File

@@ -0,0 +1,422 @@
/**
* Authentication Response DTO
*
* Data transfer object for authentication responses.
* Contains authentication tokens, user information,
* and security status after successful login.
*
* @author David Valera Melendez <david@valera-melendez.de>
* @since February 2025
*/
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.LocalDateTime;
/**
* Response DTO for authentication operations
*
* Provides authentication tokens, user details, and security
* information after successful login or registration.
*/
@Schema(description = "Authentication response data")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AuthResponse {
/**
* JWT access token
*
* Short-lived token for API authentication.
* Should be included in Authorization header.
*/
@Schema(description = "JWT access token for API authentication")
private String accessToken;
/**
* JWT refresh token
*
* Long-lived token for obtaining new access tokens.
* Should be stored securely on the client.
*/
@Schema(description = "JWT refresh token for token renewal")
private String refreshToken;
/**
* Token type
*
* Type of the access token, typically "Bearer".
*/
@Schema(description = "Token type",
example = "Bearer")
private String tokenType = "Bearer";
/**
* Token expiration time
*
* Timestamp when the access token expires.
* Client should refresh before this time.
*/
@Schema(description = "Access token expiration time")
private LocalDateTime expiresAt;
/**
* User information
*
* Basic user profile information for the
* authenticated user.
*/
@Schema(description = "Authenticated user information")
private UserResponse user;
/**
* Two-factor authentication required
*
* Indicates if 2FA verification is required
* to complete the authentication process.
*/
@Schema(description = "Whether 2FA verification is required",
example = "false")
private Boolean requiresTwoFactor = false;
/**
* Device verification required
*
* Indicates if device verification is required
* for this login attempt.
*/
@Schema(description = "Whether device verification is required",
example = "false")
private Boolean requiresDeviceVerification = false;
/**
* Session token for multi-step authentication
*
* Temporary token for completing multi-step
* authentication processes (2FA, device verification).
*/
@Schema(description = "Temporary session token for multi-step auth")
private String sessionToken;
/**
* Available 2FA methods
*
* List of 2FA methods available to the user
* when 2FA is required.
*/
@Schema(description = "Available 2FA methods",
example = "[\"totp\", \"sms\"]")
private String[] availableTwoFactorMethods;
/**
* Device trust status
*
* Indicates the trust level of the current device.
*/
@Schema(description = "Current device trust status",
example = "trusted")
private String deviceTrustStatus;
/**
* Login timestamp
*
* Timestamp when the authentication occurred.
*/
@Schema(description = "Login timestamp")
private LocalDateTime loginAt;
/**
* IP address of the login
*
* IP address from which the authentication
* was performed.
*/
@Schema(description = "IP address of the login",
example = "192.168.1.100")
private String ipAddress;
/**
* New device detected flag
*
* Indicates if this login was from a new/unknown device.
*/
@Schema(description = "Whether this is a new device",
example = "false")
private Boolean isNewDevice = false;
/**
* Security alerts count
*
* Number of pending security alerts for the user.
*/
@Schema(description = "Number of pending security alerts",
example = "0")
private Integer securityAlertsCount = 0;
/**
* Last login information
*
* Information about the user's previous login
* for security awareness.
*/
@Schema(description = "Previous login information")
private LastLoginInfo lastLogin;
/**
* Default constructor
*/
public AuthResponse() {
this.loginAt = LocalDateTime.now();
}
/**
* Constructor for successful authentication
*
* @param accessToken JWT access token
* @param refreshToken JWT refresh token
* @param expiresAt Token expiration time
* @param user User information
*/
public AuthResponse(String accessToken, String refreshToken,
LocalDateTime expiresAt, UserResponse user) {
this();
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.expiresAt = expiresAt;
this.user = user;
}
/**
* Constructor for multi-step authentication
*
* @param sessionToken Temporary session token
* @param requiresTwoFactor Whether 2FA is required
* @param requiresDeviceVerification Whether device verification is required
*/
public AuthResponse(String sessionToken, Boolean requiresTwoFactor,
Boolean requiresDeviceVerification) {
this();
this.sessionToken = sessionToken;
this.requiresTwoFactor = requiresTwoFactor;
this.requiresDeviceVerification = requiresDeviceVerification;
}
/**
* Creates a successful authentication response
*
* @param accessToken JWT access token
* @param refreshToken JWT refresh token
* @param expiresAt Token expiration
* @param user User information
* @return AuthResponse instance
*/
public static AuthResponse success(String accessToken, String refreshToken,
LocalDateTime expiresAt, UserResponse user) {
return new AuthResponse(accessToken, refreshToken, expiresAt, user);
}
/**
* Creates a response requiring 2FA
*
* @param sessionToken Temporary session token
* @param availableMethods Available 2FA methods
* @return AuthResponse instance
*/
public static AuthResponse requireTwoFactor(String sessionToken, String[] availableMethods) {
AuthResponse response = new AuthResponse(sessionToken, true, false);
response.setAvailableTwoFactorMethods(availableMethods);
return response;
}
/**
* Creates a response requiring device verification
*
* @param sessionToken Temporary session token
* @return AuthResponse instance
*/
public static AuthResponse requireDeviceVerification(String sessionToken) {
return new AuthResponse(sessionToken, false, true);
}
/**
* Checks if authentication is complete
*
* @return true if user is fully authenticated
*/
public boolean isAuthenticationComplete() {
return accessToken != null && !requiresTwoFactor && !requiresDeviceVerification;
}
/**
* Checks if additional verification is needed
*
* @return true if more steps are required
*/
public boolean requiresAdditionalVerification() {
return requiresTwoFactor || requiresDeviceVerification;
}
// Getters and Setters
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getTokenType() {
return tokenType;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public LocalDateTime getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(LocalDateTime expiresAt) {
this.expiresAt = expiresAt;
}
public UserResponse getUser() {
return user;
}
public void setUser(UserResponse user) {
this.user = user;
}
public Boolean getRequiresTwoFactor() {
return requiresTwoFactor;
}
public void setRequiresTwoFactor(Boolean requiresTwoFactor) {
this.requiresTwoFactor = requiresTwoFactor;
}
public Boolean getRequiresDeviceVerification() {
return requiresDeviceVerification;
}
public void setRequiresDeviceVerification(Boolean requiresDeviceVerification) {
this.requiresDeviceVerification = requiresDeviceVerification;
}
public String getSessionToken() {
return sessionToken;
}
public void setSessionToken(String sessionToken) {
this.sessionToken = sessionToken;
}
public String[] getAvailableTwoFactorMethods() {
return availableTwoFactorMethods;
}
public void setAvailableTwoFactorMethods(String[] availableTwoFactorMethods) {
this.availableTwoFactorMethods = availableTwoFactorMethods;
}
public String getDeviceTrustStatus() {
return deviceTrustStatus;
}
public void setDeviceTrustStatus(String deviceTrustStatus) {
this.deviceTrustStatus = deviceTrustStatus;
}
public LocalDateTime getLoginAt() {
return loginAt;
}
public void setLoginAt(LocalDateTime loginAt) {
this.loginAt = loginAt;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public Boolean getIsNewDevice() {
return isNewDevice;
}
public void setIsNewDevice(Boolean isNewDevice) {
this.isNewDevice = isNewDevice;
}
public Integer getSecurityAlertsCount() {
return securityAlertsCount;
}
public void setSecurityAlertsCount(Integer securityAlertsCount) {
this.securityAlertsCount = securityAlertsCount;
}
public LastLoginInfo getLastLogin() {
return lastLogin;
}
public void setLastLogin(LastLoginInfo lastLogin) {
this.lastLogin = lastLogin;
}
/**
* Last login information nested class
*/
@Schema(description = "Previous login information")
public static class LastLoginInfo {
@Schema(description = "Previous login timestamp")
private LocalDateTime timestamp;
@Schema(description = "Previous login IP address")
private String ipAddress;
@Schema(description = "Previous login location")
private String location;
@Schema(description = "Previous login device")
private String device;
// Constructors
public LastLoginInfo() {}
public LastLoginInfo(LocalDateTime timestamp, String ipAddress, String location, String device) {
this.timestamp = timestamp;
this.ipAddress = ipAddress;
this.location = location;
this.device = device;
}
// Getters and Setters
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
public String getIpAddress() { return ipAddress; }
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getDevice() { return device; }
public void setDevice(String device) { this.device = device; }
}
}

View File

@@ -0,0 +1,446 @@
/**
* Device Response DTO
*
* Data transfer object for trusted device information responses.
* Contains device details for client device management interfaces.
*
* @author David Valera Melendez <david@valera-melendez.de>
* @since February 2025
*/
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.company.auth.entity.TrustedDevice;
import java.time.LocalDateTime;
/**
* Response DTO for device information
*
* Provides device data for management interfaces,
* excluding sensitive fingerprint details.
*/
@Schema(description = "Trusted device information response")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DeviceResponse {
/**
* Device unique identifier
*/
@Schema(description = "Device unique identifier",
example = "123e4567-e89b-12d3-a456-426614174000")
private String id;
/**
* User-friendly device name
*/
@Schema(description = "User-friendly device name",
example = "John's MacBook Pro")
private String deviceName;
/**
* Device type classification
*/
@Schema(description = "Device type",
example = "desktop")
private String deviceType;
/**
* Operating system information
*/
@Schema(description = "Operating system",
example = "macOS 14.1")
private String operatingSystem;
/**
* Browser information
*/
@Schema(description = "Browser information",
example = "Chrome 118.0.0.0")
private String browser;
/**
* Device location information
*/
@Schema(description = "Device location",
example = "New York, NY, USA")
private String location;
/**
* Last IP address used
*/
@Schema(description = "Last known IP address",
example = "192.168.1.100")
private String lastIpAddress;
/**
* Device trust status
*/
@Schema(description = "Device trust status",
example = "TRUSTED")
private String trustStatus;
/**
* Device trust level (0-100)
*/
@Schema(description = "Device trust level",
example = "95")
private Integer trustLevel;
/**
* Whether device is currently active
*/
@Schema(description = "Whether device is currently active",
example = "true")
private Boolean isActive;
/**
* Whether this is the current device
*/
@Schema(description = "Whether this is the current device",
example = "false")
private Boolean isCurrent;
/**
* When device was first trusted
*/
@Schema(description = "When device was first trusted")
private LocalDateTime trustedAt;
/**
* Last time device was used
*/
@Schema(description = "Last activity timestamp")
private LocalDateTime lastSeenAt;
/**
* When device trust expires
*/
@Schema(description = "Device trust expiration")
private LocalDateTime expiresAt;
/**
* Number of successful logins
*/
@Schema(description = "Number of successful logins",
example = "42")
private Integer loginCount;
/**
* Number of failed login attempts
*/
@Schema(description = "Number of failed attempts",
example = "0")
private Integer failedAttempts;
/**
* Security risk assessment
*/
@Schema(description = "Security risk level",
example = "LOW")
private String riskLevel;
/**
* Device creation timestamp
*/
@Schema(description = "Device registration timestamp")
private LocalDateTime createdAt;
/**
* Last update timestamp
*/
@Schema(description = "Last update timestamp")
private LocalDateTime updatedAt;
/**
* Default constructor
*/
public DeviceResponse() {}
/**
* Constructor with basic device information
*
* @param id Device ID
* @param deviceName Device name
* @param deviceType Device type
* @param trustStatus Trust status
* @param isActive Active status
*/
public DeviceResponse(String id, String deviceName, String deviceType,
String trustStatus, Boolean isActive) {
this.id = id;
this.deviceName = deviceName;
this.deviceType = deviceType;
this.trustStatus = trustStatus;
this.isActive = isActive;
}
/**
* Creates DeviceResponse from TrustedDevice entity
*
* @param device TrustedDevice entity
* @return DeviceResponse instance
*/
public static DeviceResponse fromEntity(TrustedDevice device) {
if (device == null) return null;
DeviceResponse response = new DeviceResponse();
response.setId(device.getId().toString());
response.setDeviceName(device.getDeviceName());
response.setDeviceType(device.getDeviceType());
response.setOperatingSystem(device.getOperatingSystem());
response.setBrowser(device.getBrowser());
response.setLocation(device.getLocation());
response.setLastIpAddress(device.getLastIpAddress());
response.setTrustStatus(device.getTrustStatus());
response.setTrustLevel(device.getTrustLevel());
response.setIsActive(device.getIsActive());
response.setTrustedAt(device.getTrustedAt());
response.setLastSeenAt(device.getLastSeenAt());
response.setExpiresAt(device.getExpiresAt());
response.setLoginCount(device.getLoginCount());
response.setFailedAttempts(device.getFailedAttempts());
response.setRiskLevel(device.getRiskLevel().name());
response.setCreatedAt(device.getCreatedAt());
response.setUpdatedAt(device.getUpdatedAt());
return response;
}
/**
* Creates a summary DeviceResponse with minimal information
*
* @param device TrustedDevice entity
* @return Summary DeviceResponse instance
*/
public static DeviceResponse summary(TrustedDevice device) {
if (device == null) return null;
DeviceResponse response = new DeviceResponse();
response.setId(device.getId().toString());
response.setDeviceName(device.getDeviceName());
response.setDeviceType(device.getDeviceType());
response.setBrowser(device.getBrowser());
response.setLocation(device.getLocation());
response.setTrustStatus(device.getTrustStatus());
response.setIsActive(device.getIsActive());
response.setLastSeenAt(device.getLastSeenAt());
return response;
}
/**
* Checks if device is trusted
*
* @return true if device is trusted
*/
public boolean isTrusted() {
return "TRUSTED".equals(trustStatus);
}
/**
* Checks if device trust is expired
*
* @return true if device trust has expired
*/
public boolean isExpired() {
return expiresAt != null && LocalDateTime.now().isAfter(expiresAt);
}
/**
* Checks if device has high trust level
*
* @return true if trust level is >= 80
*/
public boolean hasHighTrust() {
return trustLevel != null && trustLevel >= 80;
}
/**
* Checks if device has security concerns
*
* @return true if risk level is HIGH
*/
public boolean hasSecurityConcerns() {
return "HIGH".equals(riskLevel);
}
/**
* Gets days until expiration
*
* @return days until device trust expires, null if no expiration
*/
public Long getDaysUntilExpiration() {
if (expiresAt == null) return null;
return java.time.temporal.ChronoUnit.DAYS.between(LocalDateTime.now(), expiresAt);
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getOperatingSystem() {
return operatingSystem;
}
public void setOperatingSystem(String operatingSystem) {
this.operatingSystem = operatingSystem;
}
public String getBrowser() {
return browser;
}
public void setBrowser(String browser) {
this.browser = browser;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getLastIpAddress() {
return lastIpAddress;
}
public void setLastIpAddress(String lastIpAddress) {
this.lastIpAddress = lastIpAddress;
}
public String getTrustStatus() {
return trustStatus;
}
public void setTrustStatus(String trustStatus) {
this.trustStatus = trustStatus;
}
public Integer getTrustLevel() {
return trustLevel;
}
public void setTrustLevel(Integer trustLevel) {
this.trustLevel = trustLevel;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public Boolean getIsCurrent() {
return isCurrent;
}
public void setIsCurrent(Boolean isCurrent) {
this.isCurrent = isCurrent;
}
public LocalDateTime getTrustedAt() {
return trustedAt;
}
public void setTrustedAt(LocalDateTime trustedAt) {
this.trustedAt = trustedAt;
}
public LocalDateTime getLastSeenAt() {
return lastSeenAt;
}
public void setLastSeenAt(LocalDateTime lastSeenAt) {
this.lastSeenAt = lastSeenAt;
}
public LocalDateTime getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(LocalDateTime expiresAt) {
this.expiresAt = expiresAt;
}
public Integer getLoginCount() {
return loginCount;
}
public void setLoginCount(Integer loginCount) {
this.loginCount = loginCount;
}
public Integer getFailedAttempts() {
return failedAttempts;
}
public void setFailedAttempts(Integer failedAttempts) {
this.failedAttempts = failedAttempts;
}
public String getRiskLevel() {
return riskLevel;
}
public void setRiskLevel(String riskLevel) {
this.riskLevel = riskLevel;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
@Override
public String toString() {
return "DeviceResponse{" +
"id='" + id + '\'' +
", deviceName='" + deviceName + '\'' +
", deviceType='" + deviceType + '\'' +
", trustStatus='" + trustStatus + '\'' +
", isActive=" + isActive +
", trustLevel=" + trustLevel +
", riskLevel='" + riskLevel + '\'' +
", lastSeenAt=" + lastSeenAt +
'}';
}
}

View File

@@ -0,0 +1,74 @@
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.LocalDateTime;
@Schema(description = "Security status information response")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SecurityStatusResponse {
@Schema(description = "Overall security score (0-100)")
private Integer securityScore;
@Schema(description = "Whether 2FA is enabled")
private Boolean twoFactorEnabled;
@Schema(description = "Whether email is verified")
private Boolean emailVerified;
@Schema(description = "Whether phone is verified")
private Boolean phoneVerified;
@Schema(description = "Number of trusted devices")
private Integer trustedDevicesCount;
@Schema(description = "Number of active devices")
private Integer activeDevicesCount;
@Schema(description = "Last password change timestamp")
private LocalDateTime passwordChangedAt;
@Schema(description = "Last security update timestamp")
private LocalDateTime lastSecurityUpdate;
@Schema(description = "Account status")
private String accountStatus;
@Schema(description = "Risk level assessment")
private String riskLevel;
public SecurityStatusResponse() {}
// Getters and Setters
public Integer getSecurityScore() { return securityScore; }
public void setSecurityScore(Integer securityScore) { this.securityScore = securityScore; }
public Boolean getTwoFactorEnabled() { return twoFactorEnabled; }
public void setTwoFactorEnabled(Boolean twoFactorEnabled) { this.twoFactorEnabled = twoFactorEnabled; }
public Boolean getEmailVerified() { return emailVerified; }
public void setEmailVerified(Boolean emailVerified) { this.emailVerified = emailVerified; }
public Boolean getPhoneVerified() { return phoneVerified; }
public void setPhoneVerified(Boolean phoneVerified) { this.phoneVerified = phoneVerified; }
public Integer getTrustedDevicesCount() { return trustedDevicesCount; }
public void setTrustedDevicesCount(Integer trustedDevicesCount) { this.trustedDevicesCount = trustedDevicesCount; }
public Integer getActiveDevicesCount() { return activeDevicesCount; }
public void setActiveDevicesCount(Integer activeDevicesCount) { this.activeDevicesCount = activeDevicesCount; }
public LocalDateTime getPasswordChangedAt() { return passwordChangedAt; }
public void setPasswordChangedAt(LocalDateTime passwordChangedAt) { this.passwordChangedAt = passwordChangedAt; }
public LocalDateTime getLastSecurityUpdate() { return lastSecurityUpdate; }
public void setLastSecurityUpdate(LocalDateTime lastSecurityUpdate) { this.lastSecurityUpdate = lastSecurityUpdate; }
public String getAccountStatus() { return accountStatus; }
public void setAccountStatus(String accountStatus) { this.accountStatus = accountStatus; }
public String getRiskLevel() { return riskLevel; }
public void setRiskLevel(String riskLevel) { this.riskLevel = riskLevel; }
}

View File

@@ -0,0 +1,86 @@
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.LocalDateTime;
@Schema(description = "User profile information response")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserProfileResponse {
@Schema(description = "User's unique identifier")
private String id;
@Schema(description = "User's full name")
private String name;
@Schema(description = "User's email address")
private String email;
@Schema(description = "User's phone number")
private String phoneNumber;
@Schema(description = "User's preferred language")
private String language;
@Schema(description = "User's timezone")
private String timezone;
@Schema(description = "Whether email is verified")
private Boolean emailVerified;
@Schema(description = "Whether phone is verified")
private Boolean phoneVerified;
@Schema(description = "Whether 2FA is enabled")
private Boolean twoFactorEnabled;
@Schema(description = "Profile picture URL")
private String avatarUrl;
@Schema(description = "Marketing email preference")
private Boolean marketingOptIn;
@Schema(description = "Last profile update timestamp")
private LocalDateTime updatedAt;
public UserProfileResponse() {}
// Getters and Setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhoneNumber() { return phoneNumber; }
public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; }
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 Boolean getEmailVerified() { return emailVerified; }
public void setEmailVerified(Boolean emailVerified) { this.emailVerified = emailVerified; }
public Boolean getPhoneVerified() { return phoneVerified; }
public void setPhoneVerified(Boolean phoneVerified) { this.phoneVerified = phoneVerified; }
public Boolean getTwoFactorEnabled() { return twoFactorEnabled; }
public void setTwoFactorEnabled(Boolean twoFactorEnabled) { this.twoFactorEnabled = twoFactorEnabled; }
public String getAvatarUrl() { return avatarUrl; }
public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }
public Boolean getMarketingOptIn() { return marketingOptIn; }
public void setMarketingOptIn(Boolean marketingOptIn) { this.marketingOptIn = marketingOptIn; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@@ -0,0 +1,461 @@
/**
* User Response DTO
*
* Data transfer object for user information responses.
* Contains safe user data for client consumption,
* excluding sensitive information like passwords.
*
* @author David Valera Melendez <david@valera-melendez.de>
* @since February 2025
*/
package com.company.auth.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.company.auth.entity.User;
import java.time.LocalDateTime;
/**
* Response DTO for user information
*
* Provides safe user data for API responses,
* excluding sensitive fields like passwords and tokens.
*/
@Schema(description = "User information response data")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserResponse {
/**
* User's unique identifier
*/
@Schema(description = "User's unique identifier",
example = "123e4567-e89b-12d3-a456-426614174000")
private String id;
/**
* User's full name
*/
@Schema(description = "User's full name",
example = "John Doe")
private String name;
/**
* User's email address
*/
@Schema(description = "User's email address",
example = "john.doe@example.com")
private String email;
/**
* User's phone number
*/
@Schema(description = "User's phone number",
example = "+1234567890")
private String phoneNumber;
/**
* User's preferred language
*/
@Schema(description = "User's preferred language",
example = "en-US")
private String language;
/**
* User's timezone
*/
@Schema(description = "User's timezone",
example = "America/New_York")
private String timezone;
/**
* Whether user's email is verified
*/
@Schema(description = "Whether user's email is verified",
example = "true")
private Boolean emailVerified;
/**
* Whether user's phone is verified
*/
@Schema(description = "Whether user's phone is verified",
example = "false")
private Boolean phoneVerified;
/**
* Whether two-factor authentication is enabled
*/
@Schema(description = "Whether 2FA is enabled",
example = "true")
private Boolean twoFactorEnabled;
/**
* User's account status
*/
@Schema(description = "User's account status",
example = "ACTIVE")
private String status;
/**
* User's role in the system
*/
@Schema(description = "User's role",
example = "USER")
private String role;
/**
* Account creation timestamp
*/
@Schema(description = "Account creation timestamp")
private LocalDateTime createdAt;
/**
* Last profile update timestamp
*/
@Schema(description = "Last profile update timestamp")
private LocalDateTime updatedAt;
/**
* Last login timestamp
*/
@Schema(description = "Last login timestamp")
private LocalDateTime lastLoginAt;
/**
* Number of trusted devices
*/
@Schema(description = "Number of trusted devices",
example = "3")
private Integer trustedDevicesCount;
/**
* Security score (0-100)
*/
@Schema(description = "Account security score",
example = "85")
private Integer securityScore;
/**
* Whether marketing emails are accepted
*/
@Schema(description = "Marketing email preference",
example = "false")
private Boolean marketingOptIn;
/**
* Profile picture URL
*/
@Schema(description = "Profile picture URL")
private String avatarUrl;
/**
* User's registration source
*/
@Schema(description = "Registration source",
example = "web")
private String registrationSource;
/**
* Last password change timestamp
*/
@Schema(description = "Last password change timestamp")
private LocalDateTime passwordChangedAt;
/**
* Default constructor
*/
public UserResponse() {}
/**
* Constructor with basic user information
*
* @param id User ID
* @param name User name
* @param email User email
* @param emailVerified Email verification status
* @param twoFactorEnabled 2FA status
*/
public UserResponse(String id, String name, String email,
Boolean emailVerified, Boolean twoFactorEnabled) {
this.id = id;
this.name = name;
this.email = email;
this.emailVerified = emailVerified;
this.twoFactorEnabled = twoFactorEnabled;
}
/**
* Creates UserResponse from User entity
*
* @param user User entity
* @return UserResponse instance
*/
public static UserResponse fromEntity(User user) {
if (user == null) return null;
UserResponse response = new UserResponse();
response.setId(user.getId().toString());
response.setName(user.getName());
response.setEmail(user.getEmail());
response.setPhoneNumber(user.getPhoneNumber());
response.setLanguage(user.getLanguage());
response.setTimezone(user.getTimezone());
response.setEmailVerified(user.getEmailVerified());
response.setPhoneVerified(user.getPhoneVerified());
response.setTwoFactorEnabled(user.getTwoFactorEnabled());
response.setStatus(user.getStatus());
response.setRole(user.getRole());
response.setCreatedAt(user.getCreatedAt());
response.setUpdatedAt(user.getUpdatedAt());
response.setLastLoginAt(user.getLastLoginAt());
response.setMarketingOptIn(user.getMarketingOptIn());
response.setAvatarUrl(user.getAvatarUrl());
response.setRegistrationSource(user.getRegistrationSource());
response.setPasswordChangedAt(user.getPasswordChangedAt());
return response;
}
/**
* Creates a minimal UserResponse with basic information
*
* @param user User entity
* @return Minimal UserResponse instance
*/
public static UserResponse minimal(User user) {
if (user == null) return null;
UserResponse response = new UserResponse();
response.setId(user.getId().toString());
response.setName(user.getName());
response.setEmail(user.getEmail());
response.setEmailVerified(user.getEmailVerified());
response.setTwoFactorEnabled(user.getTwoFactorEnabled());
response.setStatus(user.getStatus());
response.setRole(user.getRole());
return response;
}
/**
* Creates a public UserResponse with limited information
*
* @param user User entity
* @return Public UserResponse instance
*/
public static UserResponse publicInfo(User user) {
if (user == null) return null;
UserResponse response = new UserResponse();
response.setId(user.getId().toString());
response.setName(user.getName());
response.setAvatarUrl(user.getAvatarUrl());
response.setCreatedAt(user.getCreatedAt());
return response;
}
/**
* Checks if the user account is fully verified
*
* @return true if both email and phone are verified
*/
public boolean isFullyVerified() {
return Boolean.TRUE.equals(emailVerified) && Boolean.TRUE.equals(phoneVerified);
}
/**
* Checks if the account is active
*
* @return true if status is ACTIVE
*/
public boolean isActive() {
return "ACTIVE".equals(status);
}
/**
* Checks if the account has good security
*
* @return true if security score is >= 70
*/
public boolean hasGoodSecurity() {
return securityScore != null && securityScore >= 70;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
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 Boolean getEmailVerified() {
return emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public Boolean getPhoneVerified() {
return phoneVerified;
}
public void setPhoneVerified(Boolean phoneVerified) {
this.phoneVerified = phoneVerified;
}
public Boolean getTwoFactorEnabled() {
return twoFactorEnabled;
}
public void setTwoFactorEnabled(Boolean twoFactorEnabled) {
this.twoFactorEnabled = twoFactorEnabled;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public LocalDateTime getLastLoginAt() {
return lastLoginAt;
}
public void setLastLoginAt(LocalDateTime lastLoginAt) {
this.lastLoginAt = lastLoginAt;
}
public Integer getTrustedDevicesCount() {
return trustedDevicesCount;
}
public void setTrustedDevicesCount(Integer trustedDevicesCount) {
this.trustedDevicesCount = trustedDevicesCount;
}
public Integer getSecurityScore() {
return securityScore;
}
public void setSecurityScore(Integer securityScore) {
this.securityScore = securityScore;
}
public Boolean getMarketingOptIn() {
return marketingOptIn;
}
public void setMarketingOptIn(Boolean marketingOptIn) {
this.marketingOptIn = marketingOptIn;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public String getRegistrationSource() {
return registrationSource;
}
public void setRegistrationSource(String registrationSource) {
this.registrationSource = registrationSource;
}
public LocalDateTime getPasswordChangedAt() {
return passwordChangedAt;
}
public void setPasswordChangedAt(LocalDateTime passwordChangedAt) {
this.passwordChangedAt = passwordChangedAt;
}
@Override
public String toString() {
return "UserResponse{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", email='" + email + '\'' +
", emailVerified=" + emailVerified +
", twoFactorEnabled=" + twoFactorEnabled +
", status='" + status + '\'' +
", role='" + role + '\'' +
", trustedDevicesCount=" + trustedDevicesCount +
", securityScore=" + securityScore +
'}';
}
}