mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2026-01-21 01:01:05 -05:00
adding comments
This commit is contained in:
@@ -1,31 +1,70 @@
|
|||||||
package group.goforward.battlbuilder.dto;
|
package group.goforward.battlbuilder.dto;
|
||||||
|
|
||||||
// DTO for request
|
/**
|
||||||
|
* Data Transfer Object (DTO) for email request operations.
|
||||||
|
* This class encapsulates the data required to send an email, including
|
||||||
|
* the recipient address, subject line, and message body.
|
||||||
|
*/
|
||||||
public class EmailRequestDto {
|
public class EmailRequestDto {
|
||||||
|
/** The email address of the recipient. */
|
||||||
private String recipient;
|
private String recipient;
|
||||||
|
|
||||||
|
/** The subject line of the email. */
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
|
/** The body content of the email message. */
|
||||||
private String body;
|
private String body;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the recipient email address.
|
||||||
|
*
|
||||||
|
* @return the recipient email address
|
||||||
|
*/
|
||||||
public String getRecipient() {
|
public String getRecipient() {
|
||||||
return recipient;
|
return recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the recipient email address.
|
||||||
|
*
|
||||||
|
* @param recipient the recipient email address to set
|
||||||
|
*/
|
||||||
public void setRecipient(String recipient) {
|
public void setRecipient(String recipient) {
|
||||||
this.recipient = recipient;
|
this.recipient = recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email subject line.
|
||||||
|
*
|
||||||
|
* @return the email subject line
|
||||||
|
*/
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email subject line.
|
||||||
|
*
|
||||||
|
* @param subject the email subject line to set
|
||||||
|
*/
|
||||||
public void setSubject(String subject) {
|
public void setSubject(String subject) {
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email body content.
|
||||||
|
*
|
||||||
|
* @return the email body content
|
||||||
|
*/
|
||||||
public String getBody() {
|
public String getBody() {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email body content.
|
||||||
|
*
|
||||||
|
* @param body the email body content to set
|
||||||
|
*/
|
||||||
public void setBody(String body) {
|
public void setBody(String body) {
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,184 +9,368 @@ import org.hibernate.annotations.ColumnDefault;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing an OAuth account linked to a user.
|
||||||
|
* This class stores authentication and authorization information for third-party
|
||||||
|
* OAuth providers (e.g., Google, Facebook, GitHub) including access tokens,
|
||||||
|
* refresh tokens, and session state.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "accounts")
|
@Table(name = "accounts")
|
||||||
public class Account {
|
public class Account {
|
||||||
|
/** The primary key identifier for the account. */
|
||||||
@Id
|
@Id
|
||||||
@ColumnDefault("gen_random_uuid()")
|
@ColumnDefault("gen_random_uuid()")
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the account. */
|
||||||
@ColumnDefault("gen_random_uuid()")
|
@ColumnDefault("gen_random_uuid()")
|
||||||
@Column(name = "uuid")
|
@Column(name = "uuid")
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
|
/** The UUID of the user this account belongs to. */
|
||||||
@Column(name = "user_id", nullable = false)
|
@Column(name = "user_id", nullable = false)
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
|
||||||
|
/** The type of OAuth account (e.g., "oauth", "oidc"). */
|
||||||
@Column(name = "type", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "type", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
/** The OAuth provider name (e.g., "google", "github", "facebook"). */
|
||||||
@Column(name = "provider", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "provider", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String provider;
|
private String provider;
|
||||||
|
|
||||||
|
/** The account ID from the OAuth provider. */
|
||||||
@Column(name = "provider_account_id", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "provider_account_id", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String providerAccountId;
|
private String providerAccountId;
|
||||||
|
|
||||||
|
/** The OAuth refresh token used to obtain new access tokens. */
|
||||||
@Column(name = "refresh_token", length = Integer.MAX_VALUE)
|
@Column(name = "refresh_token", length = Integer.MAX_VALUE)
|
||||||
private String refreshToken;
|
private String refreshToken;
|
||||||
|
|
||||||
|
/** The OAuth access token for API requests to the provider. */
|
||||||
@Column(name = "access_token", length = Integer.MAX_VALUE)
|
@Column(name = "access_token", length = Integer.MAX_VALUE)
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
|
|
||||||
|
/** The expiration timestamp of the access token (Unix timestamp). */
|
||||||
@Column(name = "expires_at")
|
@Column(name = "expires_at")
|
||||||
private Integer expiresAt;
|
private Integer expiresAt;
|
||||||
|
|
||||||
|
/** The type of token (e.g., "Bearer"). */
|
||||||
@Column(name = "token_type", length = Integer.MAX_VALUE)
|
@Column(name = "token_type", length = Integer.MAX_VALUE)
|
||||||
private String tokenType;
|
private String tokenType;
|
||||||
|
|
||||||
|
/** The OpenID Connect ID token (if applicable). */
|
||||||
@Column(name = "id_token", length = Integer.MAX_VALUE)
|
@Column(name = "id_token", length = Integer.MAX_VALUE)
|
||||||
private String idToken;
|
private String idToken;
|
||||||
|
|
||||||
|
/** The OAuth session state for maintaining session continuity. */
|
||||||
@Column(name = "session_state", length = Integer.MAX_VALUE)
|
@Column(name = "session_state", length = Integer.MAX_VALUE)
|
||||||
private String sessionState;
|
private String sessionState;
|
||||||
|
|
||||||
|
/** The OAuth scopes granted to this account. */
|
||||||
@Column(name = "scope", length = Integer.MAX_VALUE)
|
@Column(name = "scope", length = Integer.MAX_VALUE)
|
||||||
private String scope;
|
private String scope;
|
||||||
|
|
||||||
|
/** The timestamp when this account was created. */
|
||||||
@Column(name = "created_at")
|
@Column(name = "created_at")
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this account was last updated. */
|
||||||
@Column(name = "updated_at")
|
@Column(name = "updated_at")
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this account was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private OffsetDateTime deletedAt;
|
private OffsetDateTime deletedAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the account.
|
||||||
|
*
|
||||||
|
* @return the account ID
|
||||||
|
*/
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the account.
|
||||||
|
*
|
||||||
|
* @param id the account ID to set
|
||||||
|
*/
|
||||||
public void setId(UUID id) {
|
public void setId(UUID id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the account.
|
||||||
|
*
|
||||||
|
* @return the account UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the account.
|
||||||
|
*
|
||||||
|
* @param uuid the account UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) {
|
public void setUuid(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UUID of the user this account belongs to.
|
||||||
|
*
|
||||||
|
* @return the user UUID
|
||||||
|
*/
|
||||||
public UUID getUserId() {
|
public UUID getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the UUID of the user this account belongs to.
|
||||||
|
*
|
||||||
|
* @param userId the user UUID to set
|
||||||
|
*/
|
||||||
public void setUserId(UUID userId) {
|
public void setUserId(UUID userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of OAuth account.
|
||||||
|
*
|
||||||
|
* @return the account type (e.g., "oauth", "oidc")
|
||||||
|
*/
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of OAuth account.
|
||||||
|
*
|
||||||
|
* @param type the account type to set
|
||||||
|
*/
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OAuth provider name.
|
||||||
|
*
|
||||||
|
* @return the provider name (e.g., "google", "github", "facebook")
|
||||||
|
*/
|
||||||
public String getProvider() {
|
public String getProvider() {
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OAuth provider name.
|
||||||
|
*
|
||||||
|
* @param provider the provider name to set
|
||||||
|
*/
|
||||||
public void setProvider(String provider) {
|
public void setProvider(String provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the account ID from the OAuth provider.
|
||||||
|
*
|
||||||
|
* @return the provider account ID
|
||||||
|
*/
|
||||||
public String getProviderAccountId() {
|
public String getProviderAccountId() {
|
||||||
return providerAccountId;
|
return providerAccountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the account ID from the OAuth provider.
|
||||||
|
*
|
||||||
|
* @param providerAccountId the provider account ID to set
|
||||||
|
*/
|
||||||
public void setProviderAccountId(String providerAccountId) {
|
public void setProviderAccountId(String providerAccountId) {
|
||||||
this.providerAccountId = providerAccountId;
|
this.providerAccountId = providerAccountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OAuth refresh token.
|
||||||
|
*
|
||||||
|
* @return the refresh token, or null if not available
|
||||||
|
*/
|
||||||
public String getRefreshToken() {
|
public String getRefreshToken() {
|
||||||
return refreshToken;
|
return refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OAuth refresh token.
|
||||||
|
*
|
||||||
|
* @param refreshToken the refresh token to set
|
||||||
|
*/
|
||||||
public void setRefreshToken(String refreshToken) {
|
public void setRefreshToken(String refreshToken) {
|
||||||
this.refreshToken = refreshToken;
|
this.refreshToken = refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OAuth access token.
|
||||||
|
*
|
||||||
|
* @return the access token, or null if not available
|
||||||
|
*/
|
||||||
public String getAccessToken() {
|
public String getAccessToken() {
|
||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OAuth access token.
|
||||||
|
*
|
||||||
|
* @param accessToken the access token to set
|
||||||
|
*/
|
||||||
public void setAccessToken(String accessToken) {
|
public void setAccessToken(String accessToken) {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the expiration timestamp of the access token.
|
||||||
|
*
|
||||||
|
* @return the expiration timestamp as a Unix timestamp, or null if not set
|
||||||
|
*/
|
||||||
public Integer getExpiresAt() {
|
public Integer getExpiresAt() {
|
||||||
return expiresAt;
|
return expiresAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the expiration timestamp of the access token.
|
||||||
|
*
|
||||||
|
* @param expiresAt the expiration timestamp as a Unix timestamp
|
||||||
|
*/
|
||||||
public void setExpiresAt(Integer expiresAt) {
|
public void setExpiresAt(Integer expiresAt) {
|
||||||
this.expiresAt = expiresAt;
|
this.expiresAt = expiresAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the token type.
|
||||||
|
*
|
||||||
|
* @return the token type (e.g., "Bearer"), or null if not set
|
||||||
|
*/
|
||||||
public String getTokenType() {
|
public String getTokenType() {
|
||||||
return tokenType;
|
return tokenType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the token type.
|
||||||
|
*
|
||||||
|
* @param tokenType the token type to set
|
||||||
|
*/
|
||||||
public void setTokenType(String tokenType) {
|
public void setTokenType(String tokenType) {
|
||||||
this.tokenType = tokenType;
|
this.tokenType = tokenType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OpenID Connect ID token.
|
||||||
|
*
|
||||||
|
* @return the ID token, or null if not available
|
||||||
|
*/
|
||||||
public String getIdToken() {
|
public String getIdToken() {
|
||||||
return idToken;
|
return idToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OpenID Connect ID token.
|
||||||
|
*
|
||||||
|
* @param idToken the ID token to set
|
||||||
|
*/
|
||||||
public void setIdToken(String idToken) {
|
public void setIdToken(String idToken) {
|
||||||
this.idToken = idToken;
|
this.idToken = idToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OAuth session state.
|
||||||
|
*
|
||||||
|
* @return the session state, or null if not set
|
||||||
|
*/
|
||||||
public String getSessionState() {
|
public String getSessionState() {
|
||||||
return sessionState;
|
return sessionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OAuth session state.
|
||||||
|
*
|
||||||
|
* @param sessionState the session state to set
|
||||||
|
*/
|
||||||
public void setSessionState(String sessionState) {
|
public void setSessionState(String sessionState) {
|
||||||
this.sessionState = sessionState;
|
this.sessionState = sessionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the OAuth scopes granted to this account.
|
||||||
|
*
|
||||||
|
* @return the scopes, or null if not set
|
||||||
|
*/
|
||||||
public String getScope() {
|
public String getScope() {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the OAuth scopes granted to this account.
|
||||||
|
*
|
||||||
|
* @param scope the scopes to set
|
||||||
|
*/
|
||||||
public void setScope(String scope) {
|
public void setScope(String scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this account was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() {
|
public OffsetDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this account was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this account was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() {
|
public OffsetDateTime getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this account was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this account was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the account is not deleted
|
||||||
|
*/
|
||||||
public OffsetDateTime getDeletedAt() {
|
public OffsetDateTime getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this account was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(OffsetDateTime deletedAt) {
|
public void setDeletedAt(OffsetDateTime deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,13 @@ package group.goforward.battlbuilder.model;
|
|||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing an authentication token.
|
||||||
|
* Tokens are used for beta verification, magic login links, and password resets.
|
||||||
|
* Tokens are hashed before storage and can be consumed and expired.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(
|
@Table(
|
||||||
name = "auth_tokens",
|
name = "auth_tokens",
|
||||||
@@ -13,60 +20,155 @@ import java.time.OffsetDateTime;
|
|||||||
)
|
)
|
||||||
public class AuthToken {
|
public class AuthToken {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of token types.
|
||||||
|
*/
|
||||||
public enum TokenType {
|
public enum TokenType {
|
||||||
|
/** Token for beta access verification. */
|
||||||
BETA_VERIFY,
|
BETA_VERIFY,
|
||||||
|
/** Token for magic link login. */
|
||||||
MAGIC_LOGIN,
|
MAGIC_LOGIN,
|
||||||
|
/** Token for password reset. */
|
||||||
PASSWORD_RESET
|
PASSWORD_RESET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The primary key identifier for the token. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/** The email address associated with this token. */
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
|
/** The type of token. */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(nullable = false, length = 32)
|
@Column(nullable = false, length = 32)
|
||||||
private TokenType type;
|
private TokenType type;
|
||||||
|
|
||||||
|
/** The hashed token value. */
|
||||||
@Column(name = "token_hash", nullable = false, length = 64)
|
@Column(name = "token_hash", nullable = false, length = 64)
|
||||||
private String tokenHash;
|
private String tokenHash;
|
||||||
|
|
||||||
|
/** The timestamp when this token expires. */
|
||||||
@Column(name = "expires_at", nullable = false)
|
@Column(name = "expires_at", nullable = false)
|
||||||
private OffsetDateTime expiresAt;
|
private OffsetDateTime expiresAt;
|
||||||
|
|
||||||
|
/** The timestamp when this token was consumed/used. */
|
||||||
@Column(name = "consumed_at")
|
@Column(name = "consumed_at")
|
||||||
private OffsetDateTime consumedAt;
|
private OffsetDateTime consumedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this token was created. */
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
// getters/setters
|
// getters/setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the token.
|
||||||
|
*
|
||||||
|
* @return the token ID
|
||||||
|
*/
|
||||||
public Long getId() { return id; }
|
public Long getId() { return id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email address associated with this token.
|
||||||
|
*
|
||||||
|
* @return the email address
|
||||||
|
*/
|
||||||
public String getEmail() { return email; }
|
public String getEmail() { return email; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email address associated with this token.
|
||||||
|
*
|
||||||
|
* @param email the email address to set
|
||||||
|
*/
|
||||||
public void setEmail(String email) { this.email = email; }
|
public void setEmail(String email) { this.email = email; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of token.
|
||||||
|
*
|
||||||
|
* @return the token type
|
||||||
|
*/
|
||||||
public TokenType getType() { return type; }
|
public TokenType getType() { return type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of token.
|
||||||
|
*
|
||||||
|
* @param type the token type to set
|
||||||
|
*/
|
||||||
public void setType(TokenType type) { this.type = type; }
|
public void setType(TokenType type) { this.type = type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hashed token value.
|
||||||
|
*
|
||||||
|
* @return the token hash
|
||||||
|
*/
|
||||||
public String getTokenHash() { return tokenHash; }
|
public String getTokenHash() { return tokenHash; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hashed token value.
|
||||||
|
*
|
||||||
|
* @param tokenHash the token hash to set
|
||||||
|
*/
|
||||||
public void setTokenHash(String tokenHash) { this.tokenHash = tokenHash; }
|
public void setTokenHash(String tokenHash) { this.tokenHash = tokenHash; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this token expires.
|
||||||
|
*
|
||||||
|
* @return the expiration timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getExpiresAt() { return expiresAt; }
|
public OffsetDateTime getExpiresAt() { return expiresAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this token expires.
|
||||||
|
*
|
||||||
|
* @param expiresAt the expiration timestamp to set
|
||||||
|
*/
|
||||||
public void setExpiresAt(OffsetDateTime expiresAt) { this.expiresAt = expiresAt; }
|
public void setExpiresAt(OffsetDateTime expiresAt) { this.expiresAt = expiresAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this token was consumed/used.
|
||||||
|
*
|
||||||
|
* @return the consumed timestamp, or null if not yet consumed
|
||||||
|
*/
|
||||||
public OffsetDateTime getConsumedAt() { return consumedAt; }
|
public OffsetDateTime getConsumedAt() { return consumedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this token was consumed/used.
|
||||||
|
*
|
||||||
|
* @param consumedAt the consumed timestamp to set
|
||||||
|
*/
|
||||||
public void setConsumedAt(OffsetDateTime consumedAt) { this.consumedAt = consumedAt; }
|
public void setConsumedAt(OffsetDateTime consumedAt) { this.consumedAt = consumedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this token was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this token was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this token has been consumed/used.
|
||||||
|
*
|
||||||
|
* @return true if the token has been consumed, false otherwise
|
||||||
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isConsumed() { return consumedAt != null; }
|
public boolean isConsumed() { return consumedAt != null; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this token has expired at the given time.
|
||||||
|
*
|
||||||
|
* @param now the current time to check against
|
||||||
|
* @return true if the token has expired, false otherwise
|
||||||
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isExpired(OffsetDateTime now) { return expiresAt.isBefore(now); }
|
public boolean isExpired(OffsetDateTime now) { return expiresAt.isBefore(now); }
|
||||||
}
|
}
|
||||||
@@ -7,40 +7,59 @@ import org.hibernate.annotations.UpdateTimestamp;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a brand/manufacturer of products.
|
||||||
|
* Brands are associated with products and contain information such as name, website, and logo.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "brands")
|
@Table(name = "brands")
|
||||||
public class Brand {
|
public class Brand {
|
||||||
|
|
||||||
|
/** The primary key identifier for the brand. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** The brand name. Must be unique. */
|
||||||
@Column(nullable = false, unique = true)
|
@Column(nullable = false, unique = true)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the brand. */
|
||||||
@Column(nullable = false, unique = true)
|
@Column(nullable = false, unique = true)
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
|
/** The URL-friendly slug for the brand. Must be unique. */
|
||||||
@Column(unique = true)
|
@Column(unique = true)
|
||||||
private String slug;
|
private String slug;
|
||||||
|
|
||||||
|
/** The brand's website URL. */
|
||||||
@Column(name = "website")
|
@Column(name = "website")
|
||||||
private String website;
|
private String website;
|
||||||
|
|
||||||
|
/** The URL of the brand's logo image. */
|
||||||
@Column(name = "logo_url")
|
@Column(name = "logo_url")
|
||||||
private String logoUrl;
|
private String logoUrl;
|
||||||
|
|
||||||
|
/** The timestamp when this brand was created. */
|
||||||
@CreationTimestamp
|
@CreationTimestamp
|
||||||
@Column(name = "created_at", nullable = false, updatable = false)
|
@Column(name = "created_at", nullable = false, updatable = false)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this brand was last updated. */
|
||||||
@UpdateTimestamp
|
@UpdateTimestamp
|
||||||
@Column(name = "updated_at", nullable = false)
|
@Column(name = "updated_at", nullable = false)
|
||||||
private Instant updatedAt;
|
private Instant updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this brand was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private Instant deletedAt;
|
private Instant deletedAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before persisting a new entity.
|
||||||
|
* Initializes the UUID and generates a slug from the name if not already set.
|
||||||
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
@@ -52,74 +71,165 @@ public class Brand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the brand.
|
||||||
|
*
|
||||||
|
* @return the brand ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the brand.
|
||||||
|
*
|
||||||
|
* @param id the brand ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the brand name.
|
||||||
|
*
|
||||||
|
* @return the brand name
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the brand name.
|
||||||
|
*
|
||||||
|
* @param name the brand name to set
|
||||||
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the brand.
|
||||||
|
*
|
||||||
|
* @return the brand UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the brand.
|
||||||
|
*
|
||||||
|
* @param uuid the brand UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) {
|
public void setUuid(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL-friendly slug for the brand.
|
||||||
|
*
|
||||||
|
* @return the slug
|
||||||
|
*/
|
||||||
public String getSlug() {
|
public String getSlug() {
|
||||||
return slug;
|
return slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL-friendly slug for the brand.
|
||||||
|
*
|
||||||
|
* @param slug the slug to set
|
||||||
|
*/
|
||||||
public void setSlug(String slug) {
|
public void setSlug(String slug) {
|
||||||
this.slug = slug;
|
this.slug = slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the brand's website URL.
|
||||||
|
*
|
||||||
|
* @return the website URL, or null if not set
|
||||||
|
*/
|
||||||
public String getWebsite() {
|
public String getWebsite() {
|
||||||
return website;
|
return website;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the brand's website URL.
|
||||||
|
*
|
||||||
|
* @param website the website URL to set
|
||||||
|
*/
|
||||||
public void setWebsite(String website) {
|
public void setWebsite(String website) {
|
||||||
this.website = website;
|
this.website = website;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL of the brand's logo image.
|
||||||
|
*
|
||||||
|
* @return the logo URL, or null if not set
|
||||||
|
*/
|
||||||
public String getLogoUrl() {
|
public String getLogoUrl() {
|
||||||
return logoUrl;
|
return logoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the brand's logo image.
|
||||||
|
*
|
||||||
|
* @param logoUrl the logo URL to set
|
||||||
|
*/
|
||||||
public void setLogoUrl(String logoUrl) {
|
public void setLogoUrl(String logoUrl) {
|
||||||
this.logoUrl = logoUrl;
|
this.logoUrl = logoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this brand was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public Instant getCreatedAt() {
|
public Instant getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this brand was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(Instant createdAt) {
|
public void setCreatedAt(Instant createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this brand was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp
|
||||||
|
*/
|
||||||
public Instant getUpdatedAt() {
|
public Instant getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this brand was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
public void setUpdatedAt(Instant updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this brand was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the brand is not deleted
|
||||||
|
*/
|
||||||
public Instant getDeletedAt() {
|
public Instant getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this brand was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(Instant deletedAt) {
|
public void setDeletedAt(Instant deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import org.hibernate.annotations.ColumnDefault;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a build (firearm configuration) created by a user.
|
||||||
|
* A build contains a collection of parts and can be public or private.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "builds")
|
@Table(name = "builds")
|
||||||
public class Build {
|
public class Build {
|
||||||
@@ -14,6 +20,8 @@ public class Build {
|
|||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Primary key (Postgres GENERATED ALWAYS AS IDENTITY)
|
// Primary key (Postgres GENERATED ALWAYS AS IDENTITY)
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/** The primary key identifier for the build. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
@@ -22,6 +30,8 @@ public class Build {
|
|||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// UUID (DB default gen_random_uuid())
|
// UUID (DB default gen_random_uuid())
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the build. */
|
||||||
@ColumnDefault("gen_random_uuid()")
|
@ColumnDefault("gen_random_uuid()")
|
||||||
@Column(name = "uuid", nullable = false)
|
@Column(name = "uuid", nullable = false)
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
@@ -30,18 +40,24 @@ public class Build {
|
|||||||
// Ownership (nullable; ON DELETE SET NULL)
|
// Ownership (nullable; ON DELETE SET NULL)
|
||||||
// NOTE: Keeping this as Integer for now to avoid forcing a User entity relationship
|
// NOTE: Keeping this as Integer for now to avoid forcing a User entity relationship
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/** The ID of the user who owns this build. Can be null if the user is deleted. */
|
||||||
@Column(name = "user_id")
|
@Column(name = "user_id")
|
||||||
private Integer userId;
|
private Integer userId;
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Main fields
|
// Main fields
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/** The title of the build. */
|
||||||
@Column(name = "title", nullable = false)
|
@Column(name = "title", nullable = false)
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
/** A description of the build. */
|
||||||
@Column(name = "description")
|
@Column(name = "description")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
/** Whether this build is publicly visible. Defaults to false. */
|
||||||
@ColumnDefault("false")
|
@ColumnDefault("false")
|
||||||
@Column(name = "is_public", nullable = false)
|
@Column(name = "is_public", nullable = false)
|
||||||
private Boolean isPublic = false;
|
private Boolean isPublic = false;
|
||||||
@@ -49,20 +65,29 @@ public class Build {
|
|||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Timestamps
|
// Timestamps
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/** The timestamp when this build was created. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this build was last updated. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "updated_at", nullable = false)
|
@Column(name = "updated_at", nullable = false)
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this build was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private OffsetDateTime deletedAt;
|
private OffsetDateTime deletedAt;
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Hibernate lifecycle
|
// Hibernate lifecycle
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before persisting a new entity.
|
||||||
|
* Initializes the UUID and timestamps if not already set.
|
||||||
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
if (uuid == null) uuid = UUID.randomUUID();
|
if (uuid == null) uuid = UUID.randomUUID();
|
||||||
@@ -72,6 +97,10 @@ public class Build {
|
|||||||
if (isPublic == null) isPublic = false;
|
if (isPublic == null) isPublic = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before updating an existing entity.
|
||||||
|
* Updates the updatedAt timestamp.
|
||||||
|
*/
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
public void preUpdate() {
|
public void preUpdate() {
|
||||||
updatedAt = OffsetDateTime.now();
|
updatedAt = OffsetDateTime.now();
|
||||||
@@ -80,30 +109,130 @@ public class Build {
|
|||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Getters / Setters
|
// Getters / Setters
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the build.
|
||||||
|
*
|
||||||
|
* @return the build ID
|
||||||
|
*/
|
||||||
public Integer getId() { return id; }
|
public Integer getId() { return id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the build.
|
||||||
|
*
|
||||||
|
* @param id the build ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) { this.id = id; }
|
public void setId(Integer id) { this.id = id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the build.
|
||||||
|
*
|
||||||
|
* @return the build UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() { return uuid; }
|
public UUID getUuid() { return uuid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the build.
|
||||||
|
*
|
||||||
|
* @param uuid the build UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) { this.uuid = uuid; }
|
public void setUuid(UUID uuid) { this.uuid = uuid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID of the user who owns this build.
|
||||||
|
*
|
||||||
|
* @return the user ID, or null if the user has been deleted
|
||||||
|
*/
|
||||||
public Integer getUserId() { return userId; }
|
public Integer getUserId() { return userId; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ID of the user who owns this build.
|
||||||
|
*
|
||||||
|
* @param userId the user ID to set
|
||||||
|
*/
|
||||||
public void setUserId(Integer userId) { this.userId = userId; }
|
public void setUserId(Integer userId) { this.userId = userId; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the title of the build.
|
||||||
|
*
|
||||||
|
* @return the title
|
||||||
|
*/
|
||||||
public String getTitle() { return title; }
|
public String getTitle() { return title; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the title of the build.
|
||||||
|
*
|
||||||
|
* @param title the title to set
|
||||||
|
*/
|
||||||
public void setTitle(String title) { this.title = title; }
|
public void setTitle(String title) { this.title = title; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of the build.
|
||||||
|
*
|
||||||
|
* @return the description, or null if not set
|
||||||
|
*/
|
||||||
public String getDescription() { return description; }
|
public String getDescription() { return description; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the description of the build.
|
||||||
|
*
|
||||||
|
* @param description the description to set
|
||||||
|
*/
|
||||||
public void setDescription(String description) { this.description = description; }
|
public void setDescription(String description) { this.description = description; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this build is publicly visible.
|
||||||
|
*
|
||||||
|
* @return true if the build is public, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getIsPublic() { return isPublic; }
|
public Boolean getIsPublic() { return isPublic; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this build is publicly visible.
|
||||||
|
*
|
||||||
|
* @param isPublic true to make the build public, false to make it private
|
||||||
|
*/
|
||||||
public void setIsPublic(Boolean isPublic) { this.isPublic = isPublic; }
|
public void setIsPublic(Boolean isPublic) { this.isPublic = isPublic; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the build is not deleted
|
||||||
|
*/
|
||||||
public OffsetDateTime getDeletedAt() { return deletedAt; }
|
public OffsetDateTime getDeletedAt() { return deletedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(OffsetDateTime deletedAt) { this.deletedAt = deletedAt; }
|
public void setDeletedAt(OffsetDateTime deletedAt) { this.deletedAt = deletedAt; }
|
||||||
}
|
}
|
||||||
@@ -9,57 +9,77 @@ import org.hibernate.annotations.OnDeleteAction;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing an item (product) in a build.
|
||||||
|
* A build item links a product to a build, specifying the slot, position, and quantity.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "build_items")
|
@Table(name = "build_items")
|
||||||
public class BuildItem {
|
public class BuildItem {
|
||||||
|
/** The primary key identifier for the build item. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the build item. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("gen_random_uuid()")
|
@ColumnDefault("gen_random_uuid()")
|
||||||
@Column(name = "uuid", nullable = false)
|
@Column(name = "uuid", nullable = false)
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
|
/** The build this item belongs to. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
@JoinColumn(name = "build_id", nullable = false)
|
@JoinColumn(name = "build_id", nullable = false)
|
||||||
private Build build;
|
private Build build;
|
||||||
|
|
||||||
|
/** The product used in this build item. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
@JoinColumn(name = "product_id", nullable = false)
|
@JoinColumn(name = "product_id", nullable = false)
|
||||||
private Product product;
|
private Product product;
|
||||||
|
|
||||||
|
/** The slot/role this product fills in the build (e.g., "upper_receiver", "barrel"). */
|
||||||
@NotNull
|
@NotNull
|
||||||
@Column(name = "slot", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "slot", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String slot;
|
private String slot;
|
||||||
|
|
||||||
|
/** The position/order of this item within the slot. Defaults to 0. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("0")
|
@ColumnDefault("0")
|
||||||
@Column(name = "\"position\"", nullable = false)
|
@Column(name = "\"position\"", nullable = false)
|
||||||
private Integer position;
|
private Integer position;
|
||||||
|
|
||||||
|
/** The quantity of this product in the build. Defaults to 1. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("1")
|
@ColumnDefault("1")
|
||||||
@Column(name = "quantity", nullable = false)
|
@Column(name = "quantity", nullable = false)
|
||||||
private Integer quantity;
|
private Integer quantity;
|
||||||
|
|
||||||
|
/** The timestamp when this build item was created. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this build item was last updated. */
|
||||||
@ColumnDefault("CURRENT_TIMESTAMP")
|
@ColumnDefault("CURRENT_TIMESTAMP")
|
||||||
@Column(name = "updated_at")
|
@Column(name = "updated_at")
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this build item was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private OffsetDateTime deletedAt;
|
private OffsetDateTime deletedAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before persisting a new entity.
|
||||||
|
* Initializes the UUID and timestamps if not already set.
|
||||||
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
protected void onCreate() {
|
protected void onCreate() {
|
||||||
if (this.uuid == null) this.uuid = java.util.UUID.randomUUID();
|
if (this.uuid == null) this.uuid = java.util.UUID.randomUUID();
|
||||||
@@ -67,87 +87,191 @@ public class BuildItem {
|
|||||||
if (this.updatedAt == null) this.updatedAt = this.createdAt;
|
if (this.updatedAt == null) this.updatedAt = this.createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before updating an existing entity.
|
||||||
|
* Updates the updatedAt timestamp.
|
||||||
|
*/
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
protected void onUpdate() {
|
protected void onUpdate() {
|
||||||
this.updatedAt = OffsetDateTime.now();
|
this.updatedAt = OffsetDateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the build item.
|
||||||
|
*
|
||||||
|
* @return the build item ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the build item.
|
||||||
|
*
|
||||||
|
* @param id the build item ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the build item.
|
||||||
|
*
|
||||||
|
* @return the build item UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the build item.
|
||||||
|
*
|
||||||
|
* @param uuid the build item UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) {
|
public void setUuid(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the build this item belongs to.
|
||||||
|
*
|
||||||
|
* @return the build
|
||||||
|
*/
|
||||||
public Build getBuild() {
|
public Build getBuild() {
|
||||||
return build;
|
return build;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the build this item belongs to.
|
||||||
|
*
|
||||||
|
* @param build the build to set
|
||||||
|
*/
|
||||||
public void setBuild(Build build) {
|
public void setBuild(Build build) {
|
||||||
this.build = build;
|
this.build = build;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the product used in this build item.
|
||||||
|
*
|
||||||
|
* @return the product
|
||||||
|
*/
|
||||||
public Product getProduct() {
|
public Product getProduct() {
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product used in this build item.
|
||||||
|
*
|
||||||
|
* @param product the product to set
|
||||||
|
*/
|
||||||
public void setProduct(Product product) {
|
public void setProduct(Product product) {
|
||||||
this.product = product;
|
this.product = product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the slot/role this product fills in the build.
|
||||||
|
*
|
||||||
|
* @return the slot (e.g., "upper_receiver", "barrel")
|
||||||
|
*/
|
||||||
public String getSlot() {
|
public String getSlot() {
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the slot/role this product fills in the build.
|
||||||
|
*
|
||||||
|
* @param slot the slot to set
|
||||||
|
*/
|
||||||
public void setSlot(String slot) {
|
public void setSlot(String slot) {
|
||||||
this.slot = slot;
|
this.slot = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the position/order of this item within the slot.
|
||||||
|
*
|
||||||
|
* @return the position
|
||||||
|
*/
|
||||||
public Integer getPosition() {
|
public Integer getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the position/order of this item within the slot.
|
||||||
|
*
|
||||||
|
* @param position the position to set
|
||||||
|
*/
|
||||||
public void setPosition(Integer position) {
|
public void setPosition(Integer position) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the quantity of this product in the build.
|
||||||
|
*
|
||||||
|
* @return the quantity
|
||||||
|
*/
|
||||||
public Integer getQuantity() {
|
public Integer getQuantity() {
|
||||||
return quantity;
|
return quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the quantity of this product in the build.
|
||||||
|
*
|
||||||
|
* @param quantity the quantity to set
|
||||||
|
*/
|
||||||
public void setQuantity(Integer quantity) {
|
public void setQuantity(Integer quantity) {
|
||||||
this.quantity = quantity;
|
this.quantity = quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build item was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() {
|
public OffsetDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build item was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build item was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() {
|
public OffsetDateTime getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build item was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this build item was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the build item is not deleted
|
||||||
|
*/
|
||||||
public OffsetDateTime getDeletedAt() {
|
public OffsetDateTime getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this build item was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(OffsetDateTime deletedAt) {
|
public void setDeletedAt(OffsetDateTime deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ import jakarta.persistence.*;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing an email request/queue entry.
|
||||||
|
* Tracks email sending status, delivery, and engagement metrics (opens, clicks).
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "email_requests")
|
@Table(name = "email_requests")
|
||||||
@NamedQueries({
|
@NamedQueries({
|
||||||
@@ -22,51 +28,68 @@ import java.time.LocalDateTime;
|
|||||||
})
|
})
|
||||||
public class EmailRequest {
|
public class EmailRequest {
|
||||||
|
|
||||||
|
/** The primary key identifier for the email request. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/** The email address of the recipient. */
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String recipient;
|
private String recipient;
|
||||||
|
|
||||||
|
/** The email subject line. */
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
|
/** The email body content. */
|
||||||
@Column(columnDefinition = "TEXT")
|
@Column(columnDefinition = "TEXT")
|
||||||
private String body;
|
private String body;
|
||||||
|
|
||||||
|
/** The template key used to generate this email (if applicable). */
|
||||||
@Column(name = "template_key", length = 100)
|
@Column(name = "template_key", length = 100)
|
||||||
private String templateKey;
|
private String templateKey;
|
||||||
|
|
||||||
|
/** The status of the email (PENDING, SENT, FAILED). */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private EmailStatus status; // PENDING, SENT, FAILED
|
private EmailStatus status; // PENDING, SENT, FAILED
|
||||||
|
|
||||||
|
/** The timestamp when the email was sent. */
|
||||||
@Column(name = "sent_at")
|
@Column(name = "sent_at")
|
||||||
private LocalDateTime sentAt;
|
private LocalDateTime sentAt;
|
||||||
|
|
||||||
|
/** The error message if the email failed to send. */
|
||||||
@Column(name = "error_message")
|
@Column(name = "error_message")
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|
||||||
|
/** The timestamp when the email was first opened. */
|
||||||
@Column(name = "opened_at")
|
@Column(name = "opened_at")
|
||||||
private LocalDateTime openedAt;
|
private LocalDateTime openedAt;
|
||||||
|
|
||||||
|
/** The number of times the email has been opened. Defaults to 0. */
|
||||||
@Column(name = "open_count", nullable = false)
|
@Column(name = "open_count", nullable = false)
|
||||||
private Integer openCount = 0;
|
private Integer openCount = 0;
|
||||||
|
|
||||||
|
/** The timestamp when a link in the email was first clicked. */
|
||||||
@Column(name = "clicked_at")
|
@Column(name = "clicked_at")
|
||||||
private LocalDateTime clickedAt;
|
private LocalDateTime clickedAt;
|
||||||
|
|
||||||
|
/** The number of times links in the email have been clicked. Defaults to 0. */
|
||||||
@Column(name = "click_count", nullable = false)
|
@Column(name = "click_count", nullable = false)
|
||||||
private Integer clickCount = 0;
|
private Integer clickCount = 0;
|
||||||
|
|
||||||
|
/** The timestamp when this email request was created. */
|
||||||
@Column(name = "created_at", nullable = false, updatable = false)
|
@Column(name = "created_at", nullable = false, updatable = false)
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
// ✅ should be updatable
|
/** The timestamp when this email request was last updated. */
|
||||||
@Column(name = "updated_at", nullable = false)
|
@Column(name = "updated_at", nullable = false)
|
||||||
private LocalDateTime updatedAt;
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before persisting a new entity.
|
||||||
|
* Initializes timestamps and default values.
|
||||||
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
protected void onCreate() {
|
protected void onCreate() {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
@@ -78,6 +101,10 @@ public class EmailRequest {
|
|||||||
if (clickCount == null) clickCount = 0;
|
if (clickCount == null) clickCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before updating an existing entity.
|
||||||
|
* Updates the updatedAt timestamp.
|
||||||
|
*/
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
protected void onUpdate() {
|
protected void onUpdate() {
|
||||||
updatedAt = LocalDateTime.now();
|
updatedAt = LocalDateTime.now();
|
||||||
@@ -85,45 +112,199 @@ public class EmailRequest {
|
|||||||
|
|
||||||
// ===== Getters / Setters =====
|
// ===== Getters / Setters =====
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the email request.
|
||||||
|
*
|
||||||
|
* @return the email request ID
|
||||||
|
*/
|
||||||
public Long getId() { return id; }
|
public Long getId() { return id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the email request.
|
||||||
|
*
|
||||||
|
* @param id the email request ID to set
|
||||||
|
*/
|
||||||
public void setId(Long id) { this.id = id; }
|
public void setId(Long id) { this.id = id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email address of the recipient.
|
||||||
|
*
|
||||||
|
* @return the recipient email address
|
||||||
|
*/
|
||||||
public String getRecipient() { return recipient; }
|
public String getRecipient() { return recipient; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email address of the recipient.
|
||||||
|
*
|
||||||
|
* @param recipient the recipient email address to set
|
||||||
|
*/
|
||||||
public void setRecipient(String recipient) { this.recipient = recipient; }
|
public void setRecipient(String recipient) { this.recipient = recipient; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email subject line.
|
||||||
|
*
|
||||||
|
* @return the subject
|
||||||
|
*/
|
||||||
public String getSubject() { return subject; }
|
public String getSubject() { return subject; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email subject line.
|
||||||
|
*
|
||||||
|
* @param subject the subject to set
|
||||||
|
*/
|
||||||
public void setSubject(String subject) { this.subject = subject; }
|
public void setSubject(String subject) { this.subject = subject; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the email body content.
|
||||||
|
*
|
||||||
|
* @return the body, or null if not set
|
||||||
|
*/
|
||||||
public String getBody() { return body; }
|
public String getBody() { return body; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the email body content.
|
||||||
|
*
|
||||||
|
* @param body the body to set
|
||||||
|
*/
|
||||||
public void setBody(String body) { this.body = body; }
|
public void setBody(String body) { this.body = body; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the template key used to generate this email.
|
||||||
|
*
|
||||||
|
* @return the template key, or null if not set
|
||||||
|
*/
|
||||||
public String getTemplateKey() { return templateKey; }
|
public String getTemplateKey() { return templateKey; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the template key used to generate this email.
|
||||||
|
*
|
||||||
|
* @param templateKey the template key to set
|
||||||
|
*/
|
||||||
public void setTemplateKey(String templateKey) { this.templateKey = templateKey; }
|
public void setTemplateKey(String templateKey) { this.templateKey = templateKey; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of the email.
|
||||||
|
*
|
||||||
|
* @return the email status (PENDING, SENT, FAILED)
|
||||||
|
*/
|
||||||
public EmailStatus getStatus() { return status; }
|
public EmailStatus getStatus() { return status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of the email.
|
||||||
|
*
|
||||||
|
* @param status the email status to set
|
||||||
|
*/
|
||||||
public void setStatus(EmailStatus status) { this.status = status; }
|
public void setStatus(EmailStatus status) { this.status = status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the email was sent.
|
||||||
|
*
|
||||||
|
* @return the sent timestamp, or null if not yet sent
|
||||||
|
*/
|
||||||
public LocalDateTime getSentAt() { return sentAt; }
|
public LocalDateTime getSentAt() { return sentAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the email was sent.
|
||||||
|
*
|
||||||
|
* @param sentAt the sent timestamp to set
|
||||||
|
*/
|
||||||
public void setSentAt(LocalDateTime sentAt) { this.sentAt = sentAt; }
|
public void setSentAt(LocalDateTime sentAt) { this.sentAt = sentAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the error message if the email failed to send.
|
||||||
|
*
|
||||||
|
* @return the error message, or null if no error
|
||||||
|
*/
|
||||||
public String getErrorMessage() { return errorMessage; }
|
public String getErrorMessage() { return errorMessage; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the error message if the email failed to send.
|
||||||
|
*
|
||||||
|
* @param errorMessage the error message to set
|
||||||
|
*/
|
||||||
public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
|
public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the email was first opened.
|
||||||
|
*
|
||||||
|
* @return the opened timestamp, or null if never opened
|
||||||
|
*/
|
||||||
public LocalDateTime getOpenedAt() { return openedAt; }
|
public LocalDateTime getOpenedAt() { return openedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the email was first opened.
|
||||||
|
*
|
||||||
|
* @param openedAt the opened timestamp to set
|
||||||
|
*/
|
||||||
public void setOpenedAt(LocalDateTime openedAt) { this.openedAt = openedAt; }
|
public void setOpenedAt(LocalDateTime openedAt) { this.openedAt = openedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of times the email has been opened.
|
||||||
|
*
|
||||||
|
* @return the open count
|
||||||
|
*/
|
||||||
public Integer getOpenCount() { return openCount; }
|
public Integer getOpenCount() { return openCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of times the email has been opened.
|
||||||
|
*
|
||||||
|
* @param openCount the open count to set
|
||||||
|
*/
|
||||||
public void setOpenCount(Integer openCount) { this.openCount = openCount; }
|
public void setOpenCount(Integer openCount) { this.openCount = openCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when a link in the email was first clicked.
|
||||||
|
*
|
||||||
|
* @return the clicked timestamp, or null if never clicked
|
||||||
|
*/
|
||||||
public LocalDateTime getClickedAt() { return clickedAt; }
|
public LocalDateTime getClickedAt() { return clickedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when a link in the email was first clicked.
|
||||||
|
*
|
||||||
|
* @param clickedAt the clicked timestamp to set
|
||||||
|
*/
|
||||||
public void setClickedAt(LocalDateTime clickedAt) { this.clickedAt = clickedAt; }
|
public void setClickedAt(LocalDateTime clickedAt) { this.clickedAt = clickedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of times links in the email have been clicked.
|
||||||
|
*
|
||||||
|
* @return the click count
|
||||||
|
*/
|
||||||
public Integer getClickCount() { return clickCount; }
|
public Integer getClickCount() { return clickCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of times links in the email have been clicked.
|
||||||
|
*
|
||||||
|
* @param clickCount the click count to set
|
||||||
|
*/
|
||||||
public void setClickCount(Integer clickCount) { this.clickCount = clickCount; }
|
public void setClickCount(Integer clickCount) { this.clickCount = clickCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this email request was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public LocalDateTime getCreatedAt() { return createdAt; }
|
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this email request was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this email request was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp
|
||||||
|
*/
|
||||||
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
public LocalDateTime getUpdatedAt() { return updatedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this email request was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||||
}
|
}
|
||||||
@@ -5,41 +5,58 @@ import org.hibernate.annotations.ColumnDefault;
|
|||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a merchant/retailer that offers products.
|
||||||
|
* Merchants are integrated via AvantLink and have product feeds that are imported
|
||||||
|
* to create product offers.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "merchants")
|
@Table(name = "merchants")
|
||||||
public class Merchant {
|
public class Merchant {
|
||||||
|
|
||||||
|
/** The primary key identifier for the merchant. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** The merchant name. */
|
||||||
@Column(name = "name", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "name", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/** The AvantLink merchant ID. */
|
||||||
@Column(name = "avantlink_mid", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "avantlink_mid", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String avantlinkMid;
|
private String avantlinkMid;
|
||||||
|
|
||||||
|
/** The URL of the product feed for full imports. */
|
||||||
@Column(name = "feed_url", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "feed_url", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String feedUrl;
|
private String feedUrl;
|
||||||
|
|
||||||
|
/** The URL of the offer feed for price/availability updates. */
|
||||||
@Column(name = "offer_feed_url")
|
@Column(name = "offer_feed_url")
|
||||||
private String offerFeedUrl;
|
private String offerFeedUrl;
|
||||||
|
|
||||||
|
/** The timestamp when the last full product import was completed. */
|
||||||
@Column(name = "last_full_import_at")
|
@Column(name = "last_full_import_at")
|
||||||
private OffsetDateTime lastFullImportAt;
|
private OffsetDateTime lastFullImportAt;
|
||||||
|
|
||||||
|
/** The timestamp when the last offer sync was completed. */
|
||||||
@Column(name = "last_offer_sync_at")
|
@Column(name = "last_offer_sync_at")
|
||||||
private OffsetDateTime lastOfferSyncAt;
|
private OffsetDateTime lastOfferSyncAt;
|
||||||
|
|
||||||
|
/** Whether this merchant is active. Defaults to true. */
|
||||||
@ColumnDefault("true")
|
@ColumnDefault("true")
|
||||||
@Column(name = "is_active", nullable = false)
|
@Column(name = "is_active", nullable = false)
|
||||||
private Boolean isActive = true;
|
private Boolean isActive = true;
|
||||||
|
|
||||||
|
/** The timestamp when this merchant was created. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this merchant was last updated. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "updated_at", nullable = false)
|
@Column(name = "updated_at", nullable = false)
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
@@ -48,82 +65,182 @@ public class Merchant {
|
|||||||
// GETTERS & SETTERS
|
// GETTERS & SETTERS
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the merchant.
|
||||||
|
*
|
||||||
|
* @return the merchant ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the merchant.
|
||||||
|
*
|
||||||
|
* @param id the merchant ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the merchant name.
|
||||||
|
*
|
||||||
|
* @return the merchant name
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the merchant name.
|
||||||
|
*
|
||||||
|
* @param name the merchant name to set
|
||||||
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the AvantLink merchant ID.
|
||||||
|
*
|
||||||
|
* @return the AvantLink merchant ID
|
||||||
|
*/
|
||||||
public String getAvantlinkMid() {
|
public String getAvantlinkMid() {
|
||||||
return avantlinkMid;
|
return avantlinkMid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the AvantLink merchant ID.
|
||||||
|
*
|
||||||
|
* @param avantlinkMid the AvantLink merchant ID to set
|
||||||
|
*/
|
||||||
public void setAvantlinkMid(String avantlinkMid) {
|
public void setAvantlinkMid(String avantlinkMid) {
|
||||||
this.avantlinkMid = avantlinkMid;
|
this.avantlinkMid = avantlinkMid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL of the product feed for full imports.
|
||||||
|
*
|
||||||
|
* @return the feed URL
|
||||||
|
*/
|
||||||
public String getFeedUrl() {
|
public String getFeedUrl() {
|
||||||
return feedUrl;
|
return feedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the product feed for full imports.
|
||||||
|
*
|
||||||
|
* @param feedUrl the feed URL to set
|
||||||
|
*/
|
||||||
public void setFeedUrl(String feedUrl) {
|
public void setFeedUrl(String feedUrl) {
|
||||||
this.feedUrl = feedUrl;
|
this.feedUrl = feedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL of the offer feed for price/availability updates.
|
||||||
|
*
|
||||||
|
* @return the offer feed URL, or null if not set
|
||||||
|
*/
|
||||||
public String getOfferFeedUrl() {
|
public String getOfferFeedUrl() {
|
||||||
return offerFeedUrl;
|
return offerFeedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the offer feed for price/availability updates.
|
||||||
|
*
|
||||||
|
* @param offerFeedUrl the offer feed URL to set
|
||||||
|
*/
|
||||||
public void setOfferFeedUrl(String offerFeedUrl) {
|
public void setOfferFeedUrl(String offerFeedUrl) {
|
||||||
this.offerFeedUrl = offerFeedUrl;
|
this.offerFeedUrl = offerFeedUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the last full product import was completed.
|
||||||
|
*
|
||||||
|
* @return the last full import timestamp, or null if never imported
|
||||||
|
*/
|
||||||
public OffsetDateTime getLastFullImportAt() {
|
public OffsetDateTime getLastFullImportAt() {
|
||||||
return lastFullImportAt;
|
return lastFullImportAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the last full product import was completed.
|
||||||
|
*
|
||||||
|
* @param lastFullImportAt the last full import timestamp to set
|
||||||
|
*/
|
||||||
public void setLastFullImportAt(OffsetDateTime lastFullImportAt) {
|
public void setLastFullImportAt(OffsetDateTime lastFullImportAt) {
|
||||||
this.lastFullImportAt = lastFullImportAt;
|
this.lastFullImportAt = lastFullImportAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the last offer sync was completed.
|
||||||
|
*
|
||||||
|
* @return the last offer sync timestamp, or null if never synced
|
||||||
|
*/
|
||||||
public OffsetDateTime getLastOfferSyncAt() {
|
public OffsetDateTime getLastOfferSyncAt() {
|
||||||
return lastOfferSyncAt;
|
return lastOfferSyncAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the last offer sync was completed.
|
||||||
|
*
|
||||||
|
* @param lastOfferSyncAt the last offer sync timestamp to set
|
||||||
|
*/
|
||||||
public void setLastOfferSyncAt(OffsetDateTime lastOfferSyncAt) {
|
public void setLastOfferSyncAt(OffsetDateTime lastOfferSyncAt) {
|
||||||
this.lastOfferSyncAt = lastOfferSyncAt;
|
this.lastOfferSyncAt = lastOfferSyncAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this merchant is active.
|
||||||
|
*
|
||||||
|
* @return true if active, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getIsActive() {
|
public Boolean getIsActive() {
|
||||||
return isActive;
|
return isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this merchant is active.
|
||||||
|
*
|
||||||
|
* @param active true to activate the merchant, false to deactivate
|
||||||
|
*/
|
||||||
public void setIsActive(Boolean active) {
|
public void setIsActive(Boolean active) {
|
||||||
this.isActive = active;
|
this.isActive = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this merchant was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() {
|
public OffsetDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this merchant was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this merchant was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() {
|
public OffsetDateTime getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this merchant was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,89 +6,172 @@ import org.hibernate.annotations.ColumnDefault;
|
|||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a firearm platform (e.g., AR-15, AK-47).
|
||||||
|
* Platforms are used to categorize products and builds.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "platforms")
|
@Table(name = "platforms")
|
||||||
public class Platform {
|
public class Platform {
|
||||||
|
/** The primary key identifier for the platform. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** The unique key/identifier for the platform (e.g., "ar-15", "ak-47"). */
|
||||||
@NotNull
|
@NotNull
|
||||||
@Column(name = "key", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "key", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String key;
|
private String key;
|
||||||
|
|
||||||
|
/** The display label for the platform (e.g., "AR-15", "AK-47"). */
|
||||||
@NotNull
|
@NotNull
|
||||||
@Column(name = "label", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "label", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
|
/** The timestamp when this platform was created. */
|
||||||
@ColumnDefault("CURRENT_TIMESTAMP")
|
@ColumnDefault("CURRENT_TIMESTAMP")
|
||||||
@Column(name = "created_at")
|
@Column(name = "created_at")
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this platform was last updated. */
|
||||||
@ColumnDefault("CURRENT_TIMESTAMP")
|
@ColumnDefault("CURRENT_TIMESTAMP")
|
||||||
@Column(name = "updated_at")
|
@Column(name = "updated_at")
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this platform was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private OffsetDateTime deletedAt;
|
private OffsetDateTime deletedAt;
|
||||||
|
|
||||||
|
/** Whether this platform is active. Defaults to true. */
|
||||||
@ColumnDefault("true")
|
@ColumnDefault("true")
|
||||||
@Column(name = "is_active", nullable = false)
|
@Column(name = "is_active", nullable = false)
|
||||||
private Boolean isActive = true;
|
private Boolean isActive = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the platform.
|
||||||
|
*
|
||||||
|
* @return the platform ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the platform.
|
||||||
|
*
|
||||||
|
* @param id the platform ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique key/identifier for the platform.
|
||||||
|
*
|
||||||
|
* @return the platform key (e.g., "ar-15", "ak-47")
|
||||||
|
*/
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique key/identifier for the platform.
|
||||||
|
*
|
||||||
|
* @param key the platform key to set
|
||||||
|
*/
|
||||||
public void setKey(String key) {
|
public void setKey(String key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the display label for the platform.
|
||||||
|
*
|
||||||
|
* @return the platform label (e.g., "AR-15", "AK-47")
|
||||||
|
*/
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the display label for the platform.
|
||||||
|
*
|
||||||
|
* @param label the platform label to set
|
||||||
|
*/
|
||||||
public void setLabel(String label) {
|
public void setLabel(String label) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this platform was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() {
|
public OffsetDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this platform was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this platform was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() {
|
public OffsetDateTime getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this platform was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this platform was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the platform is not deleted
|
||||||
|
*/
|
||||||
public OffsetDateTime getDeletedAt() {
|
public OffsetDateTime getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this platform was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(OffsetDateTime deletedAt) {
|
public void setDeletedAt(OffsetDateTime deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this platform is active.
|
||||||
|
*
|
||||||
|
* @return true if active, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getIsActive() {
|
public Boolean getIsActive() {
|
||||||
return isActive;
|
return isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this platform is active.
|
||||||
|
*
|
||||||
|
* @param active true to activate the platform, false to deactivate
|
||||||
|
*/
|
||||||
public void setIsActive(Boolean active) {
|
public void setIsActive(Boolean active) {
|
||||||
this.isActive = active;
|
this.isActive = active;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,125 +29,194 @@ import java.util.HashSet;
|
|||||||
" LEFT JOIN FETCH p.offers o" +
|
" LEFT JOIN FETCH p.offers o" +
|
||||||
" WHERE p.platform = :platform" +
|
" WHERE p.platform = :platform" +
|
||||||
" AND p.deletedAt IS NULL")
|
" AND p.deletedAt IS NULL")
|
||||||
|
/**
|
||||||
|
* Entity representing a product in the system.
|
||||||
|
* This class stores product information including brand, classification, pricing,
|
||||||
|
* images, and administrative settings. Products can be associated with multiple
|
||||||
|
* offers from different merchants.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
public class Product {
|
public class Product {
|
||||||
|
|
||||||
|
/** The primary key identifier for the product. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the product. */
|
||||||
@Column(name = "uuid", nullable = false, updatable = false)
|
@Column(name = "uuid", nullable = false, updatable = false)
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
|
/** The brand that manufactures this product. */
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "brand_id", nullable = false)
|
@JoinColumn(name = "brand_id", nullable = false)
|
||||||
private Brand brand;
|
private Brand brand;
|
||||||
|
|
||||||
|
/** The product name. */
|
||||||
@Column(name = "name", nullable = false)
|
@Column(name = "name", nullable = false)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/** The URL-friendly slug for the product. */
|
||||||
@Column(name = "slug", nullable = false)
|
@Column(name = "slug", nullable = false)
|
||||||
private String slug;
|
private String slug;
|
||||||
|
|
||||||
|
/** The Manufacturer Part Number (MPN). */
|
||||||
@Column(name = "mpn")
|
@Column(name = "mpn")
|
||||||
private String mpn;
|
private String mpn;
|
||||||
|
|
||||||
|
/** The Universal Product Code (UPC). */
|
||||||
@Column(name = "upc")
|
@Column(name = "upc")
|
||||||
private String upc;
|
private String upc;
|
||||||
|
|
||||||
|
/** The platform this product is designed for (e.g., "AR-15", "AK-47"). */
|
||||||
@Column(name = "platform")
|
@Column(name = "platform")
|
||||||
private String platform;
|
private String platform;
|
||||||
|
|
||||||
|
/** The role/function of this part in a build (e.g., "upper_receiver", "barrel"). */
|
||||||
@Column(name = "part_role")
|
@Column(name = "part_role")
|
||||||
private String partRole;
|
private String partRole;
|
||||||
|
|
||||||
// --- classification provenance ---
|
// --- classification provenance ---
|
||||||
|
|
||||||
|
/** The source of the part role classification. */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "part_role_source", nullable = false)
|
@Column(name = "part_role_source", nullable = false)
|
||||||
private PartRoleSource partRoleSource = PartRoleSource.UNKNOWN;
|
private PartRoleSource partRoleSource = PartRoleSource.UNKNOWN;
|
||||||
|
|
||||||
|
/** The version of the classifier used to classify this product. */
|
||||||
@Column(name = "classifier_version", length = 32)
|
@Column(name = "classifier_version", length = 32)
|
||||||
private String classifierVersion;
|
private String classifierVersion;
|
||||||
|
|
||||||
|
/** The reason for the classification decision. */
|
||||||
@Column(name = "classification_reason", length = 512)
|
@Column(name = "classification_reason", length = 512)
|
||||||
private String classificationReason;
|
private String classificationReason;
|
||||||
|
|
||||||
|
/** The timestamp when this product was classified. */
|
||||||
@Column(name = "classified_at")
|
@Column(name = "classified_at")
|
||||||
private Instant classifiedAt;
|
private Instant classifiedAt;
|
||||||
|
|
||||||
|
/** Whether the part role is locked from automatic reclassification. */
|
||||||
@Column(name = "part_role_locked", nullable = false)
|
@Column(name = "part_role_locked", nullable = false)
|
||||||
private Boolean partRoleLocked = false;
|
private Boolean partRoleLocked = false;
|
||||||
|
|
||||||
|
/** The product configuration type. */
|
||||||
@Column(name = "configuration")
|
@Column(name = "configuration")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private ProductConfiguration configuration;
|
private ProductConfiguration configuration;
|
||||||
|
|
||||||
|
/** A short description of the product. */
|
||||||
@Column(name = "short_description")
|
@Column(name = "short_description")
|
||||||
private String shortDescription;
|
private String shortDescription;
|
||||||
|
|
||||||
|
/** A detailed description of the product. */
|
||||||
@Column(name = "description")
|
@Column(name = "description")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
/** The URL of the main product image. */
|
||||||
@Column(name = "main_image_url")
|
@Column(name = "main_image_url")
|
||||||
private String mainImageUrl;
|
private String mainImageUrl;
|
||||||
|
|
||||||
|
/** The URL of the BattlBuilder-hosted image. */
|
||||||
@Column(name = "battl_image_url")
|
@Column(name = "battl_image_url")
|
||||||
private String battlImageUrl;
|
private String battlImageUrl;
|
||||||
|
|
||||||
|
/** The timestamp when this product was created. */
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private Instant createdAt;
|
private Instant createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when this product was last updated. */
|
||||||
@Column(name = "updated_at")
|
@Column(name = "updated_at")
|
||||||
private Instant updatedAt;
|
private Instant updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when this product was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private Instant deletedAt;
|
private Instant deletedAt;
|
||||||
|
|
||||||
|
/** The raw category key from the import source. */
|
||||||
@Column(name = "raw_category_key")
|
@Column(name = "raw_category_key")
|
||||||
private String rawCategoryKey;
|
private String rawCategoryKey;
|
||||||
|
|
||||||
|
/** Whether the platform assignment is locked from automatic changes. */
|
||||||
@Column(name = "platform_locked", nullable = false)
|
@Column(name = "platform_locked", nullable = false)
|
||||||
private Boolean platformLocked = false;
|
private Boolean platformLocked = false;
|
||||||
|
|
||||||
|
/** The import status of this product. */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "import_status", nullable = false)
|
@Column(name = "import_status", nullable = false)
|
||||||
private ImportStatus importStatus = ImportStatus.MAPPED;
|
private ImportStatus importStatus = ImportStatus.MAPPED;
|
||||||
|
|
||||||
|
/** The set of offers available for this product from various merchants. */
|
||||||
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
|
||||||
private Set<ProductOffer> offers = new HashSet<>();
|
private Set<ProductOffer> offers = new HashSet<>();
|
||||||
|
|
||||||
|
/** The caliber this product is designed for. */
|
||||||
@Column(name = "caliber")
|
@Column(name = "caliber")
|
||||||
private String caliber;
|
private String caliber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the caliber this product is designed for.
|
||||||
|
*
|
||||||
|
* @return the caliber, or null if not set
|
||||||
|
*/
|
||||||
public String getCaliber() { return caliber; }
|
public String getCaliber() { return caliber; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the caliber this product is designed for.
|
||||||
|
*
|
||||||
|
* @param caliber the caliber to set
|
||||||
|
*/
|
||||||
public void setCaliber(String caliber) { this.caliber = caliber; }
|
public void setCaliber(String caliber) { this.caliber = caliber; }
|
||||||
|
|
||||||
|
/** The caliber group this product belongs to. */
|
||||||
@Column(name = "caliber_group")
|
@Column(name = "caliber_group")
|
||||||
private String caliberGroup;
|
private String caliberGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the caliber group this product belongs to.
|
||||||
|
*
|
||||||
|
* @return the caliber group, or null if not set
|
||||||
|
*/
|
||||||
public String getCaliberGroup() { return caliberGroup; }
|
public String getCaliberGroup() { return caliberGroup; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the caliber group this product belongs to.
|
||||||
|
*
|
||||||
|
* @param caliberGroup the caliber group to set
|
||||||
|
*/
|
||||||
public void setCaliberGroup(String caliberGroup) { this.caliberGroup = caliberGroup; }
|
public void setCaliberGroup(String caliberGroup) { this.caliberGroup = caliberGroup; }
|
||||||
|
|
||||||
/* Admin Management */
|
/* Admin Management */
|
||||||
|
|
||||||
|
/** The visibility status of this product. */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "visibility", nullable = false)
|
@Column(name = "visibility", nullable = false)
|
||||||
private ProductVisibility visibility = ProductVisibility.PUBLIC;
|
private ProductVisibility visibility = ProductVisibility.PUBLIC;
|
||||||
|
|
||||||
|
/** Whether this product is eligible to be used in the builder. */
|
||||||
@Column(name = "builder_eligible", nullable = false)
|
@Column(name = "builder_eligible", nullable = false)
|
||||||
private Boolean builderEligible = true;
|
private Boolean builderEligible = true;
|
||||||
|
|
||||||
|
/** Whether this product is locked by an administrator. */
|
||||||
@Column(name = "admin_locked", nullable = false)
|
@Column(name = "admin_locked", nullable = false)
|
||||||
private Boolean adminLocked = false;
|
private Boolean adminLocked = false;
|
||||||
|
|
||||||
|
/** The status of this product. */
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "status", nullable = false)
|
@Column(name = "status", nullable = false)
|
||||||
private ProductStatus status = ProductStatus.ACTIVE;
|
private ProductStatus status = ProductStatus.ACTIVE;
|
||||||
|
|
||||||
|
/** Administrative notes about this product. */
|
||||||
@Column(name = "admin_note")
|
@Column(name = "admin_note")
|
||||||
private String adminNote;
|
private String adminNote;
|
||||||
|
|
||||||
// --- lifecycle hooks ---
|
// --- lifecycle hooks ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before persisting a new entity.
|
||||||
|
* Initializes the UUID and timestamps if not already set.
|
||||||
|
*/
|
||||||
@PrePersist
|
@PrePersist
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
if (uuid == null) uuid = UUID.randomUUID();
|
if (uuid == null) uuid = UUID.randomUUID();
|
||||||
@@ -156,122 +225,476 @@ public class Product {
|
|||||||
if (updatedAt == null) updatedAt = now;
|
if (updatedAt == null) updatedAt = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle hook called before updating an existing entity.
|
||||||
|
* Updates the updatedAt timestamp.
|
||||||
|
*/
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
public void preUpdate() {
|
public void preUpdate() {
|
||||||
updatedAt = Instant.now();
|
updatedAt = Instant.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- getters & setters ---
|
// --- getters & setters ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the product.
|
||||||
|
*
|
||||||
|
* @return the product ID
|
||||||
|
*/
|
||||||
public Integer getId() { return id; }
|
public Integer getId() { return id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the product.
|
||||||
|
*
|
||||||
|
* @param id the product ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) { this.id = id; }
|
public void setId(Integer id) { this.id = id; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the product.
|
||||||
|
*
|
||||||
|
* @return the product UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() { return uuid; }
|
public UUID getUuid() { return uuid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the product.
|
||||||
|
*
|
||||||
|
* @param uuid the product UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) { this.uuid = uuid; }
|
public void setUuid(UUID uuid) { this.uuid = uuid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the brand that manufactures this product.
|
||||||
|
*
|
||||||
|
* @return the brand
|
||||||
|
*/
|
||||||
public Brand getBrand() { return brand; }
|
public Brand getBrand() { return brand; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the brand that manufactures this product.
|
||||||
|
*
|
||||||
|
* @param brand the brand to set
|
||||||
|
*/
|
||||||
public void setBrand(Brand brand) { this.brand = brand; }
|
public void setBrand(Brand brand) { this.brand = brand; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the product name.
|
||||||
|
*
|
||||||
|
* @return the product name
|
||||||
|
*/
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product name.
|
||||||
|
*
|
||||||
|
* @param name the product name to set
|
||||||
|
*/
|
||||||
public void setName(String name) { this.name = name; }
|
public void setName(String name) { this.name = name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL-friendly slug for the product.
|
||||||
|
*
|
||||||
|
* @return the slug
|
||||||
|
*/
|
||||||
public String getSlug() { return slug; }
|
public String getSlug() { return slug; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL-friendly slug for the product.
|
||||||
|
*
|
||||||
|
* @param slug the slug to set
|
||||||
|
*/
|
||||||
public void setSlug(String slug) { this.slug = slug; }
|
public void setSlug(String slug) { this.slug = slug; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Manufacturer Part Number (MPN).
|
||||||
|
*
|
||||||
|
* @return the MPN, or null if not set
|
||||||
|
*/
|
||||||
public String getMpn() { return mpn; }
|
public String getMpn() { return mpn; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Manufacturer Part Number (MPN).
|
||||||
|
*
|
||||||
|
* @param mpn the MPN to set
|
||||||
|
*/
|
||||||
public void setMpn(String mpn) { this.mpn = mpn; }
|
public void setMpn(String mpn) { this.mpn = mpn; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Universal Product Code (UPC).
|
||||||
|
*
|
||||||
|
* @return the UPC, or null if not set
|
||||||
|
*/
|
||||||
public String getUpc() { return upc; }
|
public String getUpc() { return upc; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Universal Product Code (UPC).
|
||||||
|
*
|
||||||
|
* @param upc the UPC to set
|
||||||
|
*/
|
||||||
public void setUpc(String upc) { this.upc = upc; }
|
public void setUpc(String upc) { this.upc = upc; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the platform this product is designed for.
|
||||||
|
*
|
||||||
|
* @return the platform (e.g., "AR-15", "AK-47"), or null if not set
|
||||||
|
*/
|
||||||
public String getPlatform() { return platform; }
|
public String getPlatform() { return platform; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the platform this product is designed for.
|
||||||
|
*
|
||||||
|
* @param platform the platform to set
|
||||||
|
*/
|
||||||
public void setPlatform(String platform) { this.platform = platform; }
|
public void setPlatform(String platform) { this.platform = platform; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the role/function of this part in a build.
|
||||||
|
*
|
||||||
|
* @return the part role (e.g., "upper_receiver", "barrel"), or null if not set
|
||||||
|
*/
|
||||||
public String getPartRole() { return partRole; }
|
public String getPartRole() { return partRole; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the role/function of this part in a build.
|
||||||
|
*
|
||||||
|
* @param partRole the part role to set
|
||||||
|
*/
|
||||||
public void setPartRole(String partRole) { this.partRole = partRole; }
|
public void setPartRole(String partRole) { this.partRole = partRole; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the product configuration type.
|
||||||
|
*
|
||||||
|
* @return the configuration, or null if not set
|
||||||
|
*/
|
||||||
public ProductConfiguration getConfiguration() { return configuration; }
|
public ProductConfiguration getConfiguration() { return configuration; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product configuration type.
|
||||||
|
*
|
||||||
|
* @param configuration the configuration to set
|
||||||
|
*/
|
||||||
public void setConfiguration(ProductConfiguration configuration) {
|
public void setConfiguration(ProductConfiguration configuration) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the short description of the product.
|
||||||
|
*
|
||||||
|
* @return the short description, or null if not set
|
||||||
|
*/
|
||||||
public String getShortDescription() { return shortDescription; }
|
public String getShortDescription() { return shortDescription; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the short description of the product.
|
||||||
|
*
|
||||||
|
* @param shortDescription the short description to set
|
||||||
|
*/
|
||||||
public void setShortDescription(String shortDescription) {
|
public void setShortDescription(String shortDescription) {
|
||||||
this.shortDescription = shortDescription;
|
this.shortDescription = shortDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the detailed description of the product.
|
||||||
|
*
|
||||||
|
* @return the description, or null if not set
|
||||||
|
*/
|
||||||
public String getDescription() { return description; }
|
public String getDescription() { return description; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the detailed description of the product.
|
||||||
|
*
|
||||||
|
* @param description the description to set
|
||||||
|
*/
|
||||||
public void setDescription(String description) {
|
public void setDescription(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL of the main product image.
|
||||||
|
*
|
||||||
|
* @return the main image URL, or null if not set
|
||||||
|
*/
|
||||||
public String getMainImageUrl() { return mainImageUrl; }
|
public String getMainImageUrl() { return mainImageUrl; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the main product image.
|
||||||
|
*
|
||||||
|
* @param mainImageUrl the main image URL to set
|
||||||
|
*/
|
||||||
public void setMainImageUrl(String mainImageUrl) {
|
public void setMainImageUrl(String mainImageUrl) {
|
||||||
this.mainImageUrl = mainImageUrl;
|
this.mainImageUrl = mainImageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL of the BattlBuilder-hosted image.
|
||||||
|
*
|
||||||
|
* @return the Battl image URL, or null if not set
|
||||||
|
*/
|
||||||
public String getBattlImageUrl() {return battlImageUrl; }
|
public String getBattlImageUrl() {return battlImageUrl; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL of the BattlBuilder-hosted image.
|
||||||
|
*
|
||||||
|
* @param battlImageUrl the Battl image URL to set
|
||||||
|
*/
|
||||||
public void setBattlImageUrl(String battlImageUrl) {this.battlImageUrl = battlImageUrl; }
|
public void setBattlImageUrl(String battlImageUrl) {this.battlImageUrl = battlImageUrl; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this product was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public Instant getCreatedAt() { return createdAt; }
|
public Instant getCreatedAt() { return createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this product was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; }
|
public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this product was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp, or null if not set
|
||||||
|
*/
|
||||||
public Instant getUpdatedAt() { return updatedAt; }
|
public Instant getUpdatedAt() { return updatedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this product was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; }
|
public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this product was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the product is not deleted
|
||||||
|
*/
|
||||||
public Instant getDeletedAt() { return deletedAt; }
|
public Instant getDeletedAt() { return deletedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this product was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(Instant deletedAt) { this.deletedAt = deletedAt; }
|
public void setDeletedAt(Instant deletedAt) { this.deletedAt = deletedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the platform assignment is locked.
|
||||||
|
*
|
||||||
|
* @return true if the platform is locked, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getPlatformLocked() { return platformLocked; }
|
public Boolean getPlatformLocked() { return platformLocked; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the platform assignment is locked.
|
||||||
|
*
|
||||||
|
* @param platformLocked true to lock the platform, false to unlock
|
||||||
|
*/
|
||||||
public void setPlatformLocked(Boolean platformLocked) {
|
public void setPlatformLocked(Boolean platformLocked) {
|
||||||
this.platformLocked = platformLocked;
|
this.platformLocked = platformLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw category key from the import source.
|
||||||
|
*
|
||||||
|
* @return the raw category key, or null if not set
|
||||||
|
*/
|
||||||
public String getRawCategoryKey() { return rawCategoryKey; }
|
public String getRawCategoryKey() { return rawCategoryKey; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the raw category key from the import source.
|
||||||
|
*
|
||||||
|
* @param rawCategoryKey the raw category key to set
|
||||||
|
*/
|
||||||
public void setRawCategoryKey(String rawCategoryKey) {
|
public void setRawCategoryKey(String rawCategoryKey) {
|
||||||
this.rawCategoryKey = rawCategoryKey;
|
this.rawCategoryKey = rawCategoryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the import status of this product.
|
||||||
|
*
|
||||||
|
* @return the import status
|
||||||
|
*/
|
||||||
public ImportStatus getImportStatus() { return importStatus; }
|
public ImportStatus getImportStatus() { return importStatus; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the import status of this product.
|
||||||
|
*
|
||||||
|
* @param importStatus the import status to set
|
||||||
|
*/
|
||||||
public void setImportStatus(ImportStatus importStatus) {
|
public void setImportStatus(ImportStatus importStatus) {
|
||||||
this.importStatus = importStatus;
|
this.importStatus = importStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of offers available for this product.
|
||||||
|
*
|
||||||
|
* @return the set of product offers
|
||||||
|
*/
|
||||||
public Set<ProductOffer> getOffers() { return offers; }
|
public Set<ProductOffer> getOffers() { return offers; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the set of offers available for this product.
|
||||||
|
*
|
||||||
|
* @param offers the set of product offers to set
|
||||||
|
*/
|
||||||
public void setOffers(Set<ProductOffer> offers) { this.offers = offers; }
|
public void setOffers(Set<ProductOffer> offers) { this.offers = offers; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the source of the part role classification.
|
||||||
|
*
|
||||||
|
* @return the part role source
|
||||||
|
*/
|
||||||
public PartRoleSource getPartRoleSource() { return partRoleSource; }
|
public PartRoleSource getPartRoleSource() { return partRoleSource; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the source of the part role classification.
|
||||||
|
*
|
||||||
|
* @param partRoleSource the part role source to set
|
||||||
|
*/
|
||||||
public void setPartRoleSource(PartRoleSource partRoleSource) { this.partRoleSource = partRoleSource; }
|
public void setPartRoleSource(PartRoleSource partRoleSource) { this.partRoleSource = partRoleSource; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the classifier used to classify this product.
|
||||||
|
*
|
||||||
|
* @return the classifier version, or null if not set
|
||||||
|
*/
|
||||||
public String getClassifierVersion() { return classifierVersion; }
|
public String getClassifierVersion() { return classifierVersion; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the version of the classifier used to classify this product.
|
||||||
|
*
|
||||||
|
* @param classifierVersion the classifier version to set
|
||||||
|
*/
|
||||||
public void setClassifierVersion(String classifierVersion) { this.classifierVersion = classifierVersion; }
|
public void setClassifierVersion(String classifierVersion) { this.classifierVersion = classifierVersion; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the reason for the classification decision.
|
||||||
|
*
|
||||||
|
* @return the classification reason, or null if not set
|
||||||
|
*/
|
||||||
public String getClassificationReason() { return classificationReason; }
|
public String getClassificationReason() { return classificationReason; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reason for the classification decision.
|
||||||
|
*
|
||||||
|
* @param classificationReason the classification reason to set
|
||||||
|
*/
|
||||||
public void setClassificationReason(String classificationReason) { this.classificationReason = classificationReason; }
|
public void setClassificationReason(String classificationReason) { this.classificationReason = classificationReason; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this product was classified.
|
||||||
|
*
|
||||||
|
* @return the classification timestamp, or null if not set
|
||||||
|
*/
|
||||||
public Instant getClassifiedAt() { return classifiedAt; }
|
public Instant getClassifiedAt() { return classifiedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this product was classified.
|
||||||
|
*
|
||||||
|
* @param classifiedAt the classification timestamp to set
|
||||||
|
*/
|
||||||
public void setClassifiedAt(Instant classifiedAt) { this.classifiedAt = classifiedAt; }
|
public void setClassifiedAt(Instant classifiedAt) { this.classifiedAt = classifiedAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the part role is locked from automatic reclassification.
|
||||||
|
*
|
||||||
|
* @return true if the part role is locked, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getPartRoleLocked() { return partRoleLocked; }
|
public Boolean getPartRoleLocked() { return partRoleLocked; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the part role is locked from automatic reclassification.
|
||||||
|
*
|
||||||
|
* @param partRoleLocked true to lock the part role, false to unlock
|
||||||
|
*/
|
||||||
public void setPartRoleLocked(Boolean partRoleLocked) { this.partRoleLocked = partRoleLocked; }
|
public void setPartRoleLocked(Boolean partRoleLocked) { this.partRoleLocked = partRoleLocked; }
|
||||||
|
|
||||||
|
|
||||||
// --- Admin Getters/setters
|
// --- Admin Getters/setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the visibility status of this product.
|
||||||
|
*
|
||||||
|
* @return the visibility status
|
||||||
|
*/
|
||||||
public ProductVisibility getVisibility() { return visibility; }
|
public ProductVisibility getVisibility() { return visibility; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the visibility status of this product.
|
||||||
|
*
|
||||||
|
* @param visibility the visibility status to set
|
||||||
|
*/
|
||||||
public void setVisibility(ProductVisibility visibility) { this.visibility = visibility; }
|
public void setVisibility(ProductVisibility visibility) { this.visibility = visibility; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this product is eligible to be used in the builder.
|
||||||
|
*
|
||||||
|
* @return true if builder eligible, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getBuilderEligible() { return builderEligible; }
|
public Boolean getBuilderEligible() { return builderEligible; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this product is eligible to be used in the builder.
|
||||||
|
*
|
||||||
|
* @param builderEligible true to make builder eligible, false otherwise
|
||||||
|
*/
|
||||||
public void setBuilderEligible(Boolean builderEligible) { this.builderEligible = builderEligible; }
|
public void setBuilderEligible(Boolean builderEligible) { this.builderEligible = builderEligible; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this product is locked by an administrator.
|
||||||
|
*
|
||||||
|
* @return true if admin locked, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getAdminLocked() { return adminLocked; }
|
public Boolean getAdminLocked() { return adminLocked; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this product is locked by an administrator.
|
||||||
|
*
|
||||||
|
* @param adminLocked true to lock the product, false to unlock
|
||||||
|
*/
|
||||||
public void setAdminLocked(Boolean adminLocked) { this.adminLocked = adminLocked; }
|
public void setAdminLocked(Boolean adminLocked) { this.adminLocked = adminLocked; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of this product.
|
||||||
|
*
|
||||||
|
* @return the product status
|
||||||
|
*/
|
||||||
public ProductStatus getStatus() { return status; }
|
public ProductStatus getStatus() { return status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of this product.
|
||||||
|
*
|
||||||
|
* @param status the product status to set
|
||||||
|
*/
|
||||||
public void setStatus(ProductStatus status) { this.status = status; }
|
public void setStatus(ProductStatus status) { this.status = status; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the administrative notes about this product.
|
||||||
|
*
|
||||||
|
* @return the admin note, or null if not set
|
||||||
|
*/
|
||||||
public String getAdminNote() { return adminNote; }
|
public String getAdminNote() { return adminNote; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the administrative notes about this product.
|
||||||
|
*
|
||||||
|
* @param adminNote the admin note to set
|
||||||
|
*/
|
||||||
public void setAdminNote(String adminNote) { this.adminNote = adminNote; }
|
public void setAdminNote(String adminNote) { this.adminNote = adminNote; }
|
||||||
|
|
||||||
// --- computed helpers ---
|
// --- computed helpers ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the best (lowest) offer price for this product.
|
||||||
|
* Compares sale prices first, then retail prices if sale price is not available.
|
||||||
|
*
|
||||||
|
* @return the best offer price, or BigDecimal.ZERO if no offers are available
|
||||||
|
*/
|
||||||
public BigDecimal getBestOfferPrice() {
|
public BigDecimal getBestOfferPrice() {
|
||||||
if (offers == null || offers.isEmpty()) return BigDecimal.ZERO;
|
if (offers == null || offers.isEmpty()) return BigDecimal.ZERO;
|
||||||
|
|
||||||
@@ -284,6 +707,12 @@ public class Product {
|
|||||||
.orElse(BigDecimal.ZERO);
|
.orElse(BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the affiliate URL for the best (lowest priced) offer.
|
||||||
|
* Compares sale prices first, then retail prices if sale price is not available.
|
||||||
|
*
|
||||||
|
* @return the affiliate URL for the best offer, or null if no offers are available
|
||||||
|
*/
|
||||||
public String getBestOfferBuyUrl() {
|
public String getBestOfferBuyUrl() {
|
||||||
if (offers == null || offers.isEmpty()) return null;
|
if (offers == null || offers.isEmpty()) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -8,54 +8,74 @@ import org.hibernate.annotations.OnDeleteAction;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a product offer from a merchant.
|
||||||
|
* An offer contains pricing information, availability, and purchase URL for a product
|
||||||
|
* from a specific merchant. Products can have multiple offers from different merchants.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "product_offers")
|
@Table(name = "product_offers")
|
||||||
public class ProductOffer {
|
public class ProductOffer {
|
||||||
|
|
||||||
|
/** The primary key identifier for the offer. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** The product this offer is for. */
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
@JoinColumn(name = "product_id", nullable = false)
|
@JoinColumn(name = "product_id", nullable = false)
|
||||||
private Product product;
|
private Product product;
|
||||||
|
|
||||||
|
/** The merchant offering this product. */
|
||||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
@JoinColumn(name = "merchant_id", nullable = false)
|
@JoinColumn(name = "merchant_id", nullable = false)
|
||||||
private Merchant merchant;
|
private Merchant merchant;
|
||||||
|
|
||||||
|
/** The AvantLink product ID for this offer. */
|
||||||
@Column(name = "avantlink_product_id", nullable = false)
|
@Column(name = "avantlink_product_id", nullable = false)
|
||||||
private String avantlinkProductId;
|
private String avantlinkProductId;
|
||||||
|
|
||||||
|
/** The SKU (Stock Keeping Unit) for this offer. */
|
||||||
@Column(name = "sku")
|
@Column(name = "sku")
|
||||||
private String sku;
|
private String sku;
|
||||||
|
|
||||||
|
/** The UPC (Universal Product Code) for this offer. */
|
||||||
@Column(name = "upc")
|
@Column(name = "upc")
|
||||||
private String upc;
|
private String upc;
|
||||||
|
|
||||||
|
/** The URL to purchase this product from the merchant. */
|
||||||
@Column(name = "buy_url", nullable = false)
|
@Column(name = "buy_url", nullable = false)
|
||||||
private String buyUrl;
|
private String buyUrl;
|
||||||
|
|
||||||
|
/** The current price of the product. */
|
||||||
@Column(name = "price", nullable = false, precision = 10, scale = 2)
|
@Column(name = "price", nullable = false, precision = 10, scale = 2)
|
||||||
private BigDecimal price;
|
private BigDecimal price;
|
||||||
|
|
||||||
|
/** The original/retail price before any discounts. */
|
||||||
@Column(name = "original_price", precision = 10, scale = 2)
|
@Column(name = "original_price", precision = 10, scale = 2)
|
||||||
private BigDecimal originalPrice;
|
private BigDecimal originalPrice;
|
||||||
|
|
||||||
|
/** The currency code (e.g., "USD"). Defaults to "USD". */
|
||||||
@ColumnDefault("'USD'")
|
@ColumnDefault("'USD'")
|
||||||
@Column(name = "currency", nullable = false)
|
@Column(name = "currency", nullable = false)
|
||||||
private String currency;
|
private String currency;
|
||||||
|
|
||||||
|
/** Whether the product is currently in stock. Defaults to false. */
|
||||||
@ColumnDefault("true")
|
@ColumnDefault("true")
|
||||||
@Column(name = "in_stock", nullable = false)
|
@Column(name = "in_stock", nullable = false)
|
||||||
private Boolean inStock = false;
|
private Boolean inStock = false;
|
||||||
|
|
||||||
|
/** The timestamp when this offer was last seen/updated. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "last_seen_at", nullable = false)
|
@Column(name = "last_seen_at", nullable = false)
|
||||||
private OffsetDateTime lastSeenAt;
|
private OffsetDateTime lastSeenAt;
|
||||||
|
|
||||||
|
/** The timestamp when this offer was first seen/created. */
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "first_seen_at", nullable = false)
|
@Column(name = "first_seen_at", nullable = false)
|
||||||
private OffsetDateTime firstSeenAt;
|
private OffsetDateTime firstSeenAt;
|
||||||
@@ -64,106 +84,236 @@ public class ProductOffer {
|
|||||||
// Getters & setters
|
// Getters & setters
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the offer.
|
||||||
|
*
|
||||||
|
* @return the offer ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the offer.
|
||||||
|
*
|
||||||
|
* @param id the offer ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the product this offer is for.
|
||||||
|
*
|
||||||
|
* @return the product
|
||||||
|
*/
|
||||||
public Product getProduct() {
|
public Product getProduct() {
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the product this offer is for.
|
||||||
|
*
|
||||||
|
* @param product the product to set
|
||||||
|
*/
|
||||||
public void setProduct(Product product) {
|
public void setProduct(Product product) {
|
||||||
this.product = product;
|
this.product = product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the merchant offering this product.
|
||||||
|
*
|
||||||
|
* @return the merchant
|
||||||
|
*/
|
||||||
public Merchant getMerchant() {
|
public Merchant getMerchant() {
|
||||||
return merchant;
|
return merchant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the merchant offering this product.
|
||||||
|
*
|
||||||
|
* @param merchant the merchant to set
|
||||||
|
*/
|
||||||
public void setMerchant(Merchant merchant) {
|
public void setMerchant(Merchant merchant) {
|
||||||
this.merchant = merchant;
|
this.merchant = merchant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the AvantLink product ID for this offer.
|
||||||
|
*
|
||||||
|
* @return the AvantLink product ID
|
||||||
|
*/
|
||||||
public String getAvantlinkProductId() {
|
public String getAvantlinkProductId() {
|
||||||
return avantlinkProductId;
|
return avantlinkProductId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the AvantLink product ID for this offer.
|
||||||
|
*
|
||||||
|
* @param avantlinkProductId the AvantLink product ID to set
|
||||||
|
*/
|
||||||
public void setAvantlinkProductId(String avantlinkProductId) {
|
public void setAvantlinkProductId(String avantlinkProductId) {
|
||||||
this.avantlinkProductId = avantlinkProductId;
|
this.avantlinkProductId = avantlinkProductId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the SKU (Stock Keeping Unit) for this offer.
|
||||||
|
*
|
||||||
|
* @return the SKU, or null if not set
|
||||||
|
*/
|
||||||
public String getSku() {
|
public String getSku() {
|
||||||
return sku;
|
return sku;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the SKU (Stock Keeping Unit) for this offer.
|
||||||
|
*
|
||||||
|
* @param sku the SKU to set
|
||||||
|
*/
|
||||||
public void setSku(String sku) {
|
public void setSku(String sku) {
|
||||||
this.sku = sku;
|
this.sku = sku;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UPC (Universal Product Code) for this offer.
|
||||||
|
*
|
||||||
|
* @return the UPC, or null if not set
|
||||||
|
*/
|
||||||
public String getUpc() {
|
public String getUpc() {
|
||||||
return upc;
|
return upc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the UPC (Universal Product Code) for this offer.
|
||||||
|
*
|
||||||
|
* @param upc the UPC to set
|
||||||
|
*/
|
||||||
public void setUpc(String upc) {
|
public void setUpc(String upc) {
|
||||||
this.upc = upc;
|
this.upc = upc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the URL to purchase this product from the merchant.
|
||||||
|
*
|
||||||
|
* @return the buy URL
|
||||||
|
*/
|
||||||
public String getBuyUrl() {
|
public String getBuyUrl() {
|
||||||
return buyUrl;
|
return buyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the URL to purchase this product from the merchant.
|
||||||
|
*
|
||||||
|
* @param buyUrl the buy URL to set
|
||||||
|
*/
|
||||||
public void setBuyUrl(String buyUrl) {
|
public void setBuyUrl(String buyUrl) {
|
||||||
this.buyUrl = buyUrl;
|
this.buyUrl = buyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current price of the product.
|
||||||
|
*
|
||||||
|
* @return the price
|
||||||
|
*/
|
||||||
public BigDecimal getPrice() {
|
public BigDecimal getPrice() {
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current price of the product.
|
||||||
|
*
|
||||||
|
* @param price the price to set
|
||||||
|
*/
|
||||||
public void setPrice(BigDecimal price) {
|
public void setPrice(BigDecimal price) {
|
||||||
this.price = price;
|
this.price = price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the original/retail price before any discounts.
|
||||||
|
*
|
||||||
|
* @return the original price, or null if not set
|
||||||
|
*/
|
||||||
public BigDecimal getOriginalPrice() {
|
public BigDecimal getOriginalPrice() {
|
||||||
return originalPrice;
|
return originalPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the original/retail price before any discounts.
|
||||||
|
*
|
||||||
|
* @param originalPrice the original price to set
|
||||||
|
*/
|
||||||
public void setOriginalPrice(BigDecimal originalPrice) {
|
public void setOriginalPrice(BigDecimal originalPrice) {
|
||||||
this.originalPrice = originalPrice;
|
this.originalPrice = originalPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currency code.
|
||||||
|
*
|
||||||
|
* @return the currency code (e.g., "USD")
|
||||||
|
*/
|
||||||
public String getCurrency() {
|
public String getCurrency() {
|
||||||
return currency;
|
return currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the currency code.
|
||||||
|
*
|
||||||
|
* @param currency the currency code to set
|
||||||
|
*/
|
||||||
public void setCurrency(String currency) {
|
public void setCurrency(String currency) {
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the product is currently in stock.
|
||||||
|
*
|
||||||
|
* @return true if in stock, false otherwise
|
||||||
|
*/
|
||||||
public Boolean getInStock() {
|
public Boolean getInStock() {
|
||||||
return inStock;
|
return inStock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the product is currently in stock.
|
||||||
|
*
|
||||||
|
* @param inStock true if in stock, false otherwise
|
||||||
|
*/
|
||||||
public void setInStock(Boolean inStock) {
|
public void setInStock(Boolean inStock) {
|
||||||
this.inStock = inStock;
|
this.inStock = inStock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this offer was last seen/updated.
|
||||||
|
*
|
||||||
|
* @return the last seen timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getLastSeenAt() {
|
public OffsetDateTime getLastSeenAt() {
|
||||||
return lastSeenAt;
|
return lastSeenAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this offer was last seen/updated.
|
||||||
|
*
|
||||||
|
* @param lastSeenAt the last seen timestamp to set
|
||||||
|
*/
|
||||||
public void setLastSeenAt(OffsetDateTime lastSeenAt) {
|
public void setLastSeenAt(OffsetDateTime lastSeenAt) {
|
||||||
this.lastSeenAt = lastSeenAt;
|
this.lastSeenAt = lastSeenAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when this offer was first seen/created.
|
||||||
|
*
|
||||||
|
* @return the first seen timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getFirstSeenAt() {
|
public OffsetDateTime getFirstSeenAt() {
|
||||||
return firstSeenAt;
|
return firstSeenAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when this offer was first seen/created.
|
||||||
|
*
|
||||||
|
* @param firstSeenAt the first seen timestamp to set
|
||||||
|
*/
|
||||||
public void setFirstSeenAt(OffsetDateTime firstSeenAt) {
|
public void setFirstSeenAt(OffsetDateTime firstSeenAt) {
|
||||||
this.firstSeenAt = firstSeenAt;
|
this.firstSeenAt = firstSeenAt;
|
||||||
}
|
}
|
||||||
@@ -172,18 +322,38 @@ public class ProductOffer {
|
|||||||
// Helper Methods (used by Product entity)
|
// Helper Methods (used by Product entity)
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sale price (current price).
|
||||||
|
*
|
||||||
|
* @return the sale price
|
||||||
|
*/
|
||||||
public BigDecimal getSalePrice() {
|
public BigDecimal getSalePrice() {
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the retail price (original price if available, otherwise current price).
|
||||||
|
*
|
||||||
|
* @return the retail price
|
||||||
|
*/
|
||||||
public BigDecimal getRetailPrice() {
|
public BigDecimal getRetailPrice() {
|
||||||
return originalPrice != null ? originalPrice : price;
|
return originalPrice != null ? originalPrice : price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the affiliate URL for purchasing this product.
|
||||||
|
*
|
||||||
|
* @return the affiliate URL (same as buy URL)
|
||||||
|
*/
|
||||||
public String getAffiliateUrl() {
|
public String getAffiliateUrl() {
|
||||||
return buyUrl;
|
return buyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the effective price (sale price if lower than original, otherwise current price).
|
||||||
|
*
|
||||||
|
* @return the effective price
|
||||||
|
*/
|
||||||
public BigDecimal getEffectivePrice() {
|
public BigDecimal getEffectivePrice() {
|
||||||
if (price != null && originalPrice != null && price.compareTo(originalPrice) < 0) {
|
if (price != null && originalPrice != null && price.compareTo(originalPrice) < 0) {
|
||||||
return price;
|
return price;
|
||||||
|
|||||||
@@ -7,90 +7,116 @@ import org.hibernate.annotations.ColumnDefault;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity representing a user in the system.
|
||||||
|
* This class stores user authentication, profile, and account management information
|
||||||
|
* including email verification, password reset tokens, login tracking, and Terms of Service acceptance.
|
||||||
|
*
|
||||||
|
* @see jakarta.persistence.Entity
|
||||||
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "users")
|
@Table(name = "users")
|
||||||
public class User {
|
public class User {
|
||||||
|
|
||||||
|
/** The primary key identifier for the user. */
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
|
/** A unique identifier (UUID) for the user. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("gen_random_uuid()")
|
@ColumnDefault("gen_random_uuid()")
|
||||||
@Column(name = "uuid", nullable = false)
|
@Column(name = "uuid", nullable = false)
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
|
/** The user's email address. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@Column(name = "email", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "email", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
// password can be null for magic-link / beta users
|
/** The hashed password. Can be null for magic-link or beta users. */
|
||||||
@Column(name = "password_hash", length = Integer.MAX_VALUE, nullable = true)
|
@Column(name = "password_hash", length = Integer.MAX_VALUE, nullable = true)
|
||||||
private String passwordHash;
|
private String passwordHash;
|
||||||
|
|
||||||
|
/** The user's display name. */
|
||||||
@Column(name = "display_name", length = Integer.MAX_VALUE)
|
@Column(name = "display_name", length = Integer.MAX_VALUE)
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
|
||||||
|
/** The user's role (e.g., "USER", "ADMIN"). Defaults to "USER". */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("'USER'")
|
@ColumnDefault("'USER'")
|
||||||
@Column(name = "role", nullable = false, length = Integer.MAX_VALUE)
|
@Column(name = "role", nullable = false, length = Integer.MAX_VALUE)
|
||||||
private String role;
|
private String role;
|
||||||
|
|
||||||
|
/** Whether the user account is active. Defaults to true. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("true")
|
@ColumnDefault("true")
|
||||||
@Column(name = "is_active", nullable = false)
|
@Column(name = "is_active", nullable = false)
|
||||||
private boolean isActive = true;
|
private boolean isActive = true;
|
||||||
|
|
||||||
|
/** The timestamp when the user account was created. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "created_at", nullable = false)
|
@Column(name = "created_at", nullable = false)
|
||||||
private OffsetDateTime createdAt;
|
private OffsetDateTime createdAt;
|
||||||
|
|
||||||
|
/** The timestamp when the user account was last updated. */
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
@Column(name = "updated_at", nullable = false)
|
@Column(name = "updated_at", nullable = false)
|
||||||
private OffsetDateTime updatedAt;
|
private OffsetDateTime updatedAt;
|
||||||
|
|
||||||
|
/** The timestamp when the user account was soft-deleted (null if not deleted). */
|
||||||
@Column(name = "deleted_at")
|
@Column(name = "deleted_at")
|
||||||
private OffsetDateTime deletedAt;
|
private OffsetDateTime deletedAt;
|
||||||
|
|
||||||
// NEW FIELDS
|
/** The timestamp when the user's email was verified. */
|
||||||
|
|
||||||
@Column(name = "email_verified_at")
|
@Column(name = "email_verified_at")
|
||||||
private OffsetDateTime emailVerifiedAt;
|
private OffsetDateTime emailVerifiedAt;
|
||||||
|
|
||||||
|
/** The token used for email verification. */
|
||||||
@Column(name = "verification_token", length = Integer.MAX_VALUE)
|
@Column(name = "verification_token", length = Integer.MAX_VALUE)
|
||||||
private String verificationToken;
|
private String verificationToken;
|
||||||
|
|
||||||
|
/** The token used for password reset. */
|
||||||
@Column(name = "reset_password_token", length = Integer.MAX_VALUE)
|
@Column(name = "reset_password_token", length = Integer.MAX_VALUE)
|
||||||
private String resetPasswordToken;
|
private String resetPasswordToken;
|
||||||
|
|
||||||
|
/** The expiration timestamp for the password reset token. */
|
||||||
@Column(name = "reset_password_expires_at")
|
@Column(name = "reset_password_expires_at")
|
||||||
private OffsetDateTime resetPasswordExpiresAt;
|
private OffsetDateTime resetPasswordExpiresAt;
|
||||||
|
|
||||||
|
/** The timestamp of the user's last login. */
|
||||||
@Column(name = "last_login_at")
|
@Column(name = "last_login_at")
|
||||||
private OffsetDateTime lastLoginAt;
|
private OffsetDateTime lastLoginAt;
|
||||||
|
|
||||||
|
/** The total number of times the user has logged in. Defaults to 0. */
|
||||||
@ColumnDefault("0")
|
@ColumnDefault("0")
|
||||||
@Column(name = "login_count", nullable = false)
|
@Column(name = "login_count", nullable = false)
|
||||||
private Integer loginCount = 0;
|
private Integer loginCount = 0;
|
||||||
|
|
||||||
|
/** The timestamp when the user accepted the Terms of Service. */
|
||||||
@Column(name = "tos_accepted_at")
|
@Column(name = "tos_accepted_at")
|
||||||
private OffsetDateTime tosAcceptedAt;
|
private OffsetDateTime tosAcceptedAt;
|
||||||
|
|
||||||
|
/** The version of the Terms of Service that was accepted. */
|
||||||
@Column(name = "tos_version", length = 32)
|
@Column(name = "tos_version", length = 32)
|
||||||
private String tosVersion;
|
private String tosVersion;
|
||||||
|
|
||||||
|
/** The IP address from which the Terms of Service were accepted. */
|
||||||
@Column(name = "tos_ip", length = 64)
|
@Column(name = "tos_ip", length = 64)
|
||||||
private String tosIp;
|
private String tosIp;
|
||||||
|
|
||||||
|
/** The user agent string from when the Terms of Service were accepted. */
|
||||||
@Column(name = "tos_user_agent", columnDefinition = "TEXT")
|
@Column(name = "tos_user_agent", columnDefinition = "TEXT")
|
||||||
private String tosUserAgent;
|
private String tosUserAgent;
|
||||||
|
|
||||||
|
/** The user's username. */
|
||||||
@Column(name = "username", length = 32)
|
@Column(name = "username", length = 32)
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
|
/** The timestamp when the user's password was last set. */
|
||||||
@Column(name = "password_set_at")
|
@Column(name = "password_set_at")
|
||||||
private OffsetDateTime passwordSetAt;
|
private OffsetDateTime passwordSetAt;
|
||||||
|
|
||||||
@@ -98,179 +124,410 @@ public class User {
|
|||||||
|
|
||||||
// --- Getters / setters ---
|
// --- Getters / setters ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary key identifier for the user.
|
||||||
|
*
|
||||||
|
* @return the user ID
|
||||||
|
*/
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the primary key identifier for the user.
|
||||||
|
*
|
||||||
|
* @param id the user ID to set
|
||||||
|
*/
|
||||||
public void setId(Integer id) {
|
public void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier (UUID) for the user.
|
||||||
|
*
|
||||||
|
* @return the user UUID
|
||||||
|
*/
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unique identifier (UUID) for the user.
|
||||||
|
*
|
||||||
|
* @param uuid the user UUID to set
|
||||||
|
*/
|
||||||
public void setUuid(UUID uuid) {
|
public void setUuid(UUID uuid) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user's email address.
|
||||||
|
*
|
||||||
|
* @return the email address
|
||||||
|
*/
|
||||||
public String getEmail() {
|
public String getEmail() {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user's email address.
|
||||||
|
*
|
||||||
|
* @param email the email address to set
|
||||||
|
*/
|
||||||
public void setEmail(String email) {
|
public void setEmail(String email) {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hashed password.
|
||||||
|
*
|
||||||
|
* @return the password hash, or null if not set (e.g., for magic-link users)
|
||||||
|
*/
|
||||||
public String getPasswordHash() {
|
public String getPasswordHash() {
|
||||||
return passwordHash;
|
return passwordHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hashed password.
|
||||||
|
*
|
||||||
|
* @param passwordHash the password hash to set
|
||||||
|
*/
|
||||||
public void setPasswordHash(String passwordHash) {
|
public void setPasswordHash(String passwordHash) {
|
||||||
this.passwordHash = passwordHash;
|
this.passwordHash = passwordHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user's display name.
|
||||||
|
*
|
||||||
|
* @return the display name, or null if not set
|
||||||
|
*/
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user's display name.
|
||||||
|
*
|
||||||
|
* @param displayName the display name to set
|
||||||
|
*/
|
||||||
public void setDisplayName(String displayName) {
|
public void setDisplayName(String displayName) {
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user's role.
|
||||||
|
*
|
||||||
|
* @return the role (e.g., "USER", "ADMIN")
|
||||||
|
*/
|
||||||
public String getRole() {
|
public String getRole() {
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user's role.
|
||||||
|
*
|
||||||
|
* @param role the role to set
|
||||||
|
*/
|
||||||
public void setRole(String role) {
|
public void setRole(String role) {
|
||||||
this.role = role;
|
this.role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the user account is active.
|
||||||
|
*
|
||||||
|
* @return true if the account is active, false otherwise
|
||||||
|
*/
|
||||||
public boolean isActive() { return isActive; }
|
public boolean isActive() { return isActive; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the user account is active.
|
||||||
|
*
|
||||||
|
* @param active true to activate the account, false to deactivate
|
||||||
|
*/
|
||||||
public void setActive(boolean active) { this.isActive = active; }
|
public void setActive(boolean active) { this.isActive = active; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user account was created.
|
||||||
|
*
|
||||||
|
* @return the creation timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getCreatedAt() {
|
public OffsetDateTime getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user account was created.
|
||||||
|
*
|
||||||
|
* @param createdAt the creation timestamp to set
|
||||||
|
*/
|
||||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user account was last updated.
|
||||||
|
*
|
||||||
|
* @return the last update timestamp
|
||||||
|
*/
|
||||||
public OffsetDateTime getUpdatedAt() {
|
public OffsetDateTime getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user account was last updated.
|
||||||
|
*
|
||||||
|
* @param updatedAt the last update timestamp to set
|
||||||
|
*/
|
||||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||||
this.updatedAt = updatedAt;
|
this.updatedAt = updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user account was soft-deleted.
|
||||||
|
*
|
||||||
|
* @return the deletion timestamp, or null if the account is not deleted
|
||||||
|
*/
|
||||||
public OffsetDateTime getDeletedAt() {
|
public OffsetDateTime getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user account was soft-deleted.
|
||||||
|
*
|
||||||
|
* @param deletedAt the deletion timestamp to set (null to mark as not deleted)
|
||||||
|
*/
|
||||||
public void setDeletedAt(OffsetDateTime deletedAt) {
|
public void setDeletedAt(OffsetDateTime deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user's email was verified.
|
||||||
|
*
|
||||||
|
* @return the email verification timestamp, or null if not verified
|
||||||
|
*/
|
||||||
public OffsetDateTime getEmailVerifiedAt() {
|
public OffsetDateTime getEmailVerifiedAt() {
|
||||||
return emailVerifiedAt;
|
return emailVerifiedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user's email was verified.
|
||||||
|
*
|
||||||
|
* @param emailVerifiedAt the email verification timestamp to set
|
||||||
|
*/
|
||||||
public void setEmailVerifiedAt(OffsetDateTime emailVerifiedAt) {
|
public void setEmailVerifiedAt(OffsetDateTime emailVerifiedAt) {
|
||||||
this.emailVerifiedAt = emailVerifiedAt;
|
this.emailVerifiedAt = emailVerifiedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the token used for email verification.
|
||||||
|
*
|
||||||
|
* @return the verification token, or null if not set
|
||||||
|
*/
|
||||||
public String getVerificationToken() {
|
public String getVerificationToken() {
|
||||||
return verificationToken;
|
return verificationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the token used for email verification.
|
||||||
|
*
|
||||||
|
* @param verificationToken the verification token to set
|
||||||
|
*/
|
||||||
public void setVerificationToken(String verificationToken) {
|
public void setVerificationToken(String verificationToken) {
|
||||||
this.verificationToken = verificationToken;
|
this.verificationToken = verificationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the token used for password reset.
|
||||||
|
*
|
||||||
|
* @return the password reset token, or null if not set
|
||||||
|
*/
|
||||||
public String getResetPasswordToken() {
|
public String getResetPasswordToken() {
|
||||||
return resetPasswordToken;
|
return resetPasswordToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the token used for password reset.
|
||||||
|
*
|
||||||
|
* @param resetPasswordToken the password reset token to set
|
||||||
|
*/
|
||||||
public void setResetPasswordToken(String resetPasswordToken) {
|
public void setResetPasswordToken(String resetPasswordToken) {
|
||||||
this.resetPasswordToken = resetPasswordToken;
|
this.resetPasswordToken = resetPasswordToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the expiration timestamp for the password reset token.
|
||||||
|
*
|
||||||
|
* @return the expiration timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getResetPasswordExpiresAt() {
|
public OffsetDateTime getResetPasswordExpiresAt() {
|
||||||
return resetPasswordExpiresAt;
|
return resetPasswordExpiresAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the expiration timestamp for the password reset token.
|
||||||
|
*
|
||||||
|
* @param resetPasswordExpiresAt the expiration timestamp to set
|
||||||
|
*/
|
||||||
public void setResetPasswordExpiresAt(OffsetDateTime resetPasswordExpiresAt) {
|
public void setResetPasswordExpiresAt(OffsetDateTime resetPasswordExpiresAt) {
|
||||||
this.resetPasswordExpiresAt = resetPasswordExpiresAt;
|
this.resetPasswordExpiresAt = resetPasswordExpiresAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp of the user's last login.
|
||||||
|
*
|
||||||
|
* @return the last login timestamp, or null if the user has never logged in
|
||||||
|
*/
|
||||||
public OffsetDateTime getLastLoginAt() {
|
public OffsetDateTime getLastLoginAt() {
|
||||||
return lastLoginAt;
|
return lastLoginAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp of the user's last login.
|
||||||
|
*
|
||||||
|
* @param lastLoginAt the last login timestamp to set
|
||||||
|
*/
|
||||||
public void setLastLoginAt(OffsetDateTime lastLoginAt) {
|
public void setLastLoginAt(OffsetDateTime lastLoginAt) {
|
||||||
this.lastLoginAt = lastLoginAt;
|
this.lastLoginAt = lastLoginAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total number of times the user has logged in.
|
||||||
|
*
|
||||||
|
* @return the login count
|
||||||
|
*/
|
||||||
public Integer getLoginCount() {
|
public Integer getLoginCount() {
|
||||||
return loginCount;
|
return loginCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the total number of times the user has logged in.
|
||||||
|
*
|
||||||
|
* @param loginCount the login count to set
|
||||||
|
*/
|
||||||
public void setLoginCount(Integer loginCount) {
|
public void setLoginCount(Integer loginCount) {
|
||||||
this.loginCount = loginCount;
|
this.loginCount = loginCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user's username.
|
||||||
|
*
|
||||||
|
* @return the username, or null if not set
|
||||||
|
*/
|
||||||
public String getUsername() { return username; }
|
public String getUsername() { return username; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user's username.
|
||||||
|
*
|
||||||
|
* @param username the username to set
|
||||||
|
*/
|
||||||
public void setUsername(String username) { this.username = username; }
|
public void setUsername(String username) { this.username = username; }
|
||||||
|
|
||||||
|
|
||||||
// --- ToS acceptance ---
|
// --- ToS acceptance ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user accepted the Terms of Service.
|
||||||
|
*
|
||||||
|
* @return the ToS acceptance timestamp, or null if not accepted
|
||||||
|
*/
|
||||||
public OffsetDateTime getTosAcceptedAt() {
|
public OffsetDateTime getTosAcceptedAt() {
|
||||||
return tosAcceptedAt;
|
return tosAcceptedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user accepted the Terms of Service.
|
||||||
|
*
|
||||||
|
* @param tosAcceptedAt the ToS acceptance timestamp to set
|
||||||
|
*/
|
||||||
public void setTosAcceptedAt(OffsetDateTime tosAcceptedAt) {
|
public void setTosAcceptedAt(OffsetDateTime tosAcceptedAt) {
|
||||||
this.tosAcceptedAt = tosAcceptedAt;
|
this.tosAcceptedAt = tosAcceptedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the Terms of Service that was accepted.
|
||||||
|
*
|
||||||
|
* @return the ToS version, or null if not set
|
||||||
|
*/
|
||||||
public String getTosVersion() {
|
public String getTosVersion() {
|
||||||
return tosVersion;
|
return tosVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the version of the Terms of Service that was accepted.
|
||||||
|
*
|
||||||
|
* @param tosVersion the ToS version to set
|
||||||
|
*/
|
||||||
public void setTosVersion(String tosVersion) {
|
public void setTosVersion(String tosVersion) {
|
||||||
this.tosVersion = tosVersion;
|
this.tosVersion = tosVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the IP address from which the Terms of Service were accepted.
|
||||||
|
*
|
||||||
|
* @return the IP address, or null if not set
|
||||||
|
*/
|
||||||
public String getTosIp() {
|
public String getTosIp() {
|
||||||
return tosIp;
|
return tosIp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the IP address from which the Terms of Service were accepted.
|
||||||
|
*
|
||||||
|
* @param tosIp the IP address to set
|
||||||
|
*/
|
||||||
public void setTosIp(String tosIp) {
|
public void setTosIp(String tosIp) {
|
||||||
this.tosIp = tosIp;
|
this.tosIp = tosIp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user agent string from when the Terms of Service were accepted.
|
||||||
|
*
|
||||||
|
* @return the user agent string, or null if not set
|
||||||
|
*/
|
||||||
public String getTosUserAgent() {
|
public String getTosUserAgent() {
|
||||||
return tosUserAgent;
|
return tosUserAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user agent string from when the Terms of Service were accepted.
|
||||||
|
*
|
||||||
|
* @param tosUserAgent the user agent string to set
|
||||||
|
*/
|
||||||
public void setTosUserAgent(String tosUserAgent) {
|
public void setTosUserAgent(String tosUserAgent) {
|
||||||
this.tosUserAgent = tosUserAgent;
|
this.tosUserAgent = tosUserAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp when the user's password was last set.
|
||||||
|
*
|
||||||
|
* @return the password set timestamp, or null if not set
|
||||||
|
*/
|
||||||
public OffsetDateTime getPasswordSetAt() { return passwordSetAt; }
|
public OffsetDateTime getPasswordSetAt() { return passwordSetAt; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timestamp when the user's password was last set.
|
||||||
|
*
|
||||||
|
* @param passwordSetAt the password set timestamp to set
|
||||||
|
*/
|
||||||
public void setPasswordSetAt(OffsetDateTime passwordSetAt) { this.passwordSetAt = passwordSetAt; }
|
public void setPasswordSetAt(OffsetDateTime passwordSetAt) { this.passwordSetAt = passwordSetAt; }
|
||||||
|
|
||||||
|
|
||||||
// convenience helpers
|
// convenience helpers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the user's email has been verified.
|
||||||
|
*
|
||||||
|
* @return true if the email is verified (emailVerifiedAt is not null), false otherwise
|
||||||
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isEmailVerified() {
|
public boolean isEmailVerified() {
|
||||||
return emailVerifiedAt != null;
|
return emailVerifiedAt != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the login count by one.
|
||||||
|
* If the login count is null, it is initialized to 0 before incrementing.
|
||||||
|
*/
|
||||||
public void incrementLoginCount() {
|
public void incrementLoginCount() {
|
||||||
if (loginCount == null) {
|
if (loginCount == null) {
|
||||||
loginCount = 0;
|
loginCount = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user