diff --git a/.gitignore b/.gitignore index 9154f4c..e714e79 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,9 @@ hs_err_pid* replay_pid* + +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/config/log4j2.properties b/config/log4j2.properties new file mode 100644 index 0000000..af0c445 --- /dev/null +++ b/config/log4j2.properties @@ -0,0 +1,54 @@ +property.log.dir=logs/${spring:spring.application.name} +property.log.dir.info=${log.dir}/info +property.log.dir.error=${log.dir}/error +property.log.pattern=%d{yyyy-MM-dd HH:mm:ss} - [%t] - %p - %m%n + +# Console Logger +appender.Console.type=Console +appender.Console.name=Console +appender.Console.target=SYSTEM_OUT +appender.Console.layout.type=PatternLayout +appender.Console.layout.pattern=${log.pattern} + +# Info Log File - Rolling by Day +appender.InfoFile.type=RollingFile +appender.InfoFile.name=InfoFile +appender.InfoFile.fileName=${log.dir.info}/app-info.log +appender.InfoFile.filePattern=${log.dir.info}/app-info-%d{yyyy-MM-dd}.log.gz +appender.InfoFile.layout.type=PatternLayout +appender.InfoFile.layout.pattern=${log.pattern} + +appender.InfoFile.filter.0.type=ThresholdFilter +appender.InfoFile.filter.0.level=INFO +appender.InfoFile.filter.0.onMatch=ACCEPT +appender.InfoFile.filter.0.onMismatch=NEUTRAL + +appender.InfoFile.filter.1.type=ThresholdFilter +appender.InfoFile.filter.1.level=WARN +appender.InfoFile.filter.1.onMatch=ACCEPT +appender.InfoFile.filter.1.onMismatch=DENY + +appender.InfoFile.policies.type=Policies +appender.InfoFile.policies.timeBased.type=TimeBasedTriggeringPolicy +appender.InfoFile.policies.timeBased.interval=1 +appender.InfoFile.policies.timeBased.modulate=true + +# Error Log File - Rolling by Day +appender.ErrorFile.type=RollingFile +appender.ErrorFile.name=ErrorFile +appender.ErrorFile.fileName=${log.dir.error}/app-error.log +appender.ErrorFile.filePattern=${log.dir.error}/app-error-%d{yyyy-MM-dd}.log.gz +appender.ErrorFile.layout.type=PatternLayout +appender.ErrorFile.layout.pattern=${log.pattern} +appender.ErrorFile.filter.threshold.type=ThresholdFilter +appender.ErrorFile.filter.threshold.level=ERROR +appender.ErrorFile.policies.type=Policies +appender.ErrorFile.policies.timeBased.type=TimeBasedTriggeringPolicy +appender.ErrorFile.policies.timeBased.interval=1 +appender.ErrorFile.policies.timeBased.modulate=true + +# Root Logger +rootLogger.level=INFO +rootLogger.appenderRef.Console.ref=Console +rootLogger.appenderRef.InfoFile.ref=InfoFile +rootLogger.appenderRef.ErrorFile.ref=ErrorFile diff --git a/config/shared.properties b/config/shared.properties new file mode 100644 index 0000000..7f1a820 --- /dev/null +++ b/config/shared.properties @@ -0,0 +1,35 @@ +spring.jpa.open-in-view=false + +app.datasource.vega.url=jdbc:postgresql://103.166.141.147:5440/db_vega_hrm +app.datasource.vega.username=vega_hrm +app.datasource.vega.password=VegaHrm@2025 + +app.datasource.vega.hikari.idle-timeout=10000 +app.datasource.vega.hikari.maximum-pool-size=10 +app.datasource.vega.hikari.minimum-idle=5 +app.datasource.vega.hikari.pool-name=VEGA_POOL +app.datasource.vega.hibernate.default_schema=vega_hrm +# Hibernate PostgreSQL dialect +app.datasource.vega.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect + +app.datasource.vega.hibernate.format_sql=true +app.datasource.vega.hikari.show-sql=true + +app.datasource.vega.hikari.max-lifetime=1800000 +app.datasource.vega.hikari.connection-timeout=30000 +app.datasource.vega.hikari.validation-timeout=5000 +vega.hrm.postgre.enabled=true +#app.datasource.core.vcb.url=jdbc:oracle:thin:@//10.22.19.197:1521/DVNHTEST +#app.datasource.core.vcb.username=VCB_AIRPORT_LOUNGE +#app.datasource.core.vcb.password=TGwE247q0Hh7aZAAw6YDT1IP8f+z+SQINE4Gi8GgE48= +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true +logging.level.org.hibernate.SQL=DEBUG +logging.level.org.hibernate.type.descriptor.sql=TRACE +#spring.data.redis.sentinel.master=redismaster +#spring.data.redis.sentinel.nodes=10.22.18.138:26379,10.22.18.139:26379,10.22.18.140:26379 +#spring.data.redis.sentinel.password=dLF5ZnOeOHM6/pzTHezV+WNXU+F7ZBGu85f8bwzk +#spring.data.redis.sentinel.database=17 +cors.allowed-origins=http://localhost:4201,http://localhost:4202,http://localhost:4200,http://localhost:4203 +#vcb-lounge.redis.time-to-live=600 +#spring.cache.type=simple \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/configs/VegaDatabaseConfig.java b/vega-hrm-core/src/main/java/com/vega/hrm/configs/VegaDatabaseConfig.java new file mode 100644 index 0000000..e33fc2d --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/configs/VegaDatabaseConfig.java @@ -0,0 +1,162 @@ +package com.vega.hrm.configs; + +import com.zaxxer.hikari.HikariDataSource; +import java.sql.Connection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import javax.sql.DataSource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@Slf4j +@Order(2) +@EnableJpaRepositories( + basePackages = "${vega.jpa.repository.basePackage}", + entityManagerFactoryRef = "vegaHrmEntityManager", + transactionManagerRef = "vegaHrmTransactionManager" +) +@ConditionalOnProperty(name = "vega.hrm.postgre.enabled", havingValue = "true") +@EnableTransactionManagement +public class VegaDatabaseConfig { + + @Value("${vega.jpa.entity.basePackage:com.core.entity}") + private String entityBasePackage; + + @Value("${app.datasource.vega.hikari.maximum-pool-size:10}") + private Integer hikariMaximumPoolSize; + + @Value("${app.datasource.vega.hikari.minimum-idle:5}") + private Integer hikariMinimumIdle; + + @Value("${app.datasource.vega.hikari.connection-timeout:30000}") + private Long hikariConnectionTimeout; + + @Value("${app.datasource.vega.hikari.idle-timeout:10000}") + private Long hikariIdleTimeout; + + @Value("${app.datasource.vega.hikari.max-lifetime:1800000}") + private Long hikariMaxLifeTime; + + @Value("${app.datasource.vega.hikari.pool-name:VCB_LOUNGE_POOL}") + private String hikariPoolName; + + @Value("${app.datasource.vega.hikari.validation-timeout:5000}") + private Long validationTimeout; + + @Value("${app.datasource.vega.hibernate.default_schema:}") + private String hibernateDefaultSchema; + + @Bean + @ConfigurationProperties(prefix = "app.datasource.vega") + public DataSourceProperties vegaHrmDataSourceProperties() { + return new DataSourceProperties(); + } + + @Bean(name = "vegaDataSource") + public DataSource vegaDataSource() { + var dataSourceProperties = vegaHrmDataSourceProperties(); + return configureHikariDataSource(dataSourceProperties); + } + + private DataSource configureHikariDataSource(DataSourceProperties properties) { + var dataSource = properties + .initializeDataSourceBuilder() + .type(HikariDataSource.class) + .build(); + + // Hikari settings + if (hikariMaximumPoolSize != null) { + dataSource.setMaximumPoolSize(hikariMaximumPoolSize); + } + if (hikariMinimumIdle != null) { + dataSource.setMinimumIdle(hikariMinimumIdle); + } + if (hikariConnectionTimeout != null) { + dataSource.setConnectionTimeout(hikariConnectionTimeout); + } + if (hikariMaxLifeTime != null) { + dataSource.setMaxLifetime(hikariMaxLifeTime); + } + if (hikariIdleTimeout != null) { + dataSource.setIdleTimeout(hikariIdleTimeout); + } + if (hikariPoolName != null) { + dataSource.setPoolName(hikariPoolName); + } + if (validationTimeout != null) { + dataSource.setValidationTimeout(validationTimeout); + } + + // PostgreSQL driver + dataSource.setDriverClassName("org.postgresql.Driver"); + + log.info( + "HikariCP Pool Config: MaxPoolSize={}, MinIdle={}, IdleTimeout={}, MaxLifetime={}, ConnectionTimeout={}", + hikariMaximumPoolSize, hikariMinimumIdle, hikariIdleTimeout, hikariMaxLifeTime, + hikariConnectionTimeout); + + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean vegaHrmEntityManager( + @Qualifier("vegaDataSource") DataSource dataSource) { + + var em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource); + em.setPackagesToScan(entityBasePackage); + em.setPersistenceUnitName("db1"); + + var vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + Map jpaProps = new HashMap<>(); + jpaProps.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); + jpaProps.put("hibernate.format_sql", true); + jpaProps.put("hibernate.show_sql", false); + + if (hibernateDefaultSchema != null && !hibernateDefaultSchema.isBlank()) { + jpaProps.put("hibernate.default_schema", hibernateDefaultSchema.trim()); + } + + em.setJpaPropertyMap(jpaProps); + + loggingDatabaseSource(em); + return em; + } + + private void loggingDatabaseSource(LocalContainerEntityManagerFactoryBean em) { + log.info("vcbDatabaseSourceConfig entityBasePackage : {}", entityBasePackage); + + try (Connection connection = Objects.requireNonNull(em.getDataSource()).getConnection()) { + log.info("Database URL: {}", connection.getMetaData().getURL()); + log.info("Database Product: {} {}", connection.getMetaData().getDatabaseProductName(), + connection.getMetaData().getDatabaseProductVersion()); + } catch (Exception e) { + log.error("Error retrieving database URL", e); + } + } + + @Bean + public PlatformTransactionManager vegaHrmTransactionManager( + @Qualifier("vegaDataSource") DataSource dataSource) { + + var transactionManager = new JpaTransactionManager(); + transactionManager.setEntityManagerFactory(vegaHrmEntityManager(dataSource).getObject()); + return transactionManager; + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/constants/KeySecurityConst.java b/vega-hrm-core/src/main/java/com/vega/hrm/constants/KeySecurityConst.java new file mode 100644 index 0000000..95972cf --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/constants/KeySecurityConst.java @@ -0,0 +1,6 @@ +package com.vega.hrm.constants; + +public class KeySecurityConst { + public static String KEY_SECURITY_DATABASE = "lDCfYiZ5rxH1G1ElIth9ppqED6MgaLKZ"; + public static final String JWT_KEY = "e2)q2Nzc%MQz_i(EeUZMla^sW8LpSNRV"; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseCodeConst.java b/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseCodeConst.java new file mode 100644 index 0000000..965bdfe --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseCodeConst.java @@ -0,0 +1,8 @@ +package com.vega.hrm.constants; + +public class ResponseCodeConst { + public static final String SUCCESS = "00"; + public static final String INVALID = "01"; + public static final String NOT_FOUND = "02"; + public static final String INTERNAL_SYSTEM_ERROR = "99"; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseMessageConst.java b/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseMessageConst.java new file mode 100644 index 0000000..3c0e4aa --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/constants/ResponseMessageConst.java @@ -0,0 +1,5 @@ +package com.vega.hrm.constants; + +public class ResponseMessageConst { + public static final String INTERNAL_SYSTEM_ERROR = "Lỗi hệ thống"; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/constants/UserHistoryConstant.java b/vega-hrm-core/src/main/java/com/vega/hrm/constants/UserHistoryConstant.java new file mode 100644 index 0000000..ec4dfe6 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/constants/UserHistoryConstant.java @@ -0,0 +1,37 @@ +package com.vega.hrm.constants; + +import java.util.HashMap; + +public class UserHistoryConstant { + public static final String ACTION_TYPE_CREATE = "CREATE"; + public static final String ACTION_TYPE_SEARCH = "SEARCH"; + public static final String ACTION_TYPE_VIEW = "VIEW"; + public static final String ACTION_TYPE_UPDATE = "UPDATE"; + public static final String ACTION_TYPE_DELETE = "DELETE"; + public static final String ACTION_TYPE_LOGIN = "LOGIN"; + public static final String ACTION_TYPE_LOGOUT = "LOGOUT"; + public static final String ACTION_TYPE_CHANGE_STATUS = "CHANGE_STATUS"; + public static final String ACTION_TYPE_CHANGE_STATUS_MOBILE = "CHANGE_STATUS_MOBILE"; + public static final String ACTION_TYPE_APPROVE = "APPROVE"; + public static final String ACTION_TYPE_EXPORT = "EXPORT"; + public static final String ACTION_TYPE_DOWNLOAD = "DOWNLOAD"; + public static final String ACTION_TYPE_RESET_PASSWORD = "RESET_PASSWORD"; + public static final String ACTION_DESC_TEMPLATE = "IP: %s - %s bởi %s"; + public static final HashMap ACTION_TYPE_NAMES = new HashMap<>() { + { + put(ACTION_TYPE_CREATE, "Thêm mới"); + put(ACTION_TYPE_SEARCH, "Truy vấn"); + put(ACTION_TYPE_VIEW, "Xem chi tiết"); + put(ACTION_TYPE_UPDATE, "Cập nhật"); + put(ACTION_TYPE_DELETE, "Xóa"); + put(ACTION_TYPE_LOGIN, "Đăng nhập"); + put(ACTION_TYPE_LOGOUT, "Đăng xuất"); + put(ACTION_TYPE_CHANGE_STATUS, "Đổi trạng thái"); + put(ACTION_TYPE_CHANGE_STATUS_MOBILE, "Đổi trạng thái SĐT"); + put(ACTION_TYPE_APPROVE, "Phê duyệt"); + put(ACTION_TYPE_EXPORT, "Kết xuất"); + put(ACTION_TYPE_DOWNLOAD, "Tải file"); + put(ACTION_TYPE_RESET_PASSWORD,"Reset password"); + } + }; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoFunction.java b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoFunction.java new file mode 100644 index 0000000..a4b29fa --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoFunction.java @@ -0,0 +1,62 @@ +package com.vega.hrm.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.Instant; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "bo_function") +public class BoFunction { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "function_id", nullable = false) + private UUID id; + + @Size(max = 200) + @NotNull + @Column(name = "function_name", nullable = false, length = 200) + private String functionName; + + @NotNull + @Column(name = "function_level", nullable = false) + private Long functionLevel; + + @Size(max = 100) + @Column(name = "function_url", length = 100) + private String functionUrl; + + @NotNull + @Column(name = "function_order", nullable = false) + private Long functionOrder; + + @NotNull + @Column(name = "parent_id", nullable = false) + private Long parentId; + + @Size(max = 20) + @NotNull + @Column(name = "created_by", nullable = false, length = 20) + private String createdBy; + + @NotNull + @ColumnDefault("now()") + @Column(name = "create_time", nullable = false) + private Instant createTime; + + @Size(max = 20) + @NotNull + @Column(name = "function_display", nullable = false, length = 20) + private String functionDisplay; + +} \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoNewFuncAuth.java b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoNewFuncAuth.java new file mode 100644 index 0000000..5c48bae --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoNewFuncAuth.java @@ -0,0 +1,35 @@ +package com.vega.hrm.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "bo_new_func_auth") +public class BoNewFuncAuth { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "id", nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "func_id") + private BoFunction func; + + @Size(max = 255) + @Column(name = "api_endpoint") + private String apiEndpoint; + +} \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRole.java b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRole.java new file mode 100644 index 0000000..2ef49ba --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRole.java @@ -0,0 +1,49 @@ +package com.vega.hrm.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.Instant; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "bo_role") +public class BoRole { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "role_id", nullable = false) + private UUID id; + + @Size(max = 200) + @NotNull + @Column(name = "role_name", nullable = false, length = 200) + private String roleName; + + @Size(max = 100) + @NotNull + @Column(name = "created_by", nullable = false, length = 100) + private String createdBy; + + @NotNull + @Column(name = "create_time", nullable = false) + private Instant createTime; + + @Size(max = 1000) + @Column(name = "description", length = 1000) + private String description; + + @Size(max = 1) + @NotNull + @Column(name = "status", nullable = false, length = 1) + private String status; + +} \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRoleFunc.java b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRoleFunc.java new file mode 100644 index 0000000..9bdf6d6 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoRoleFunc.java @@ -0,0 +1,48 @@ +package com.vega.hrm.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.Instant; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "bo_role_func") +public class BoRoleFunc { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "id", nullable = false) + private UUID id; + + @NotNull + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "function_id", nullable = false) + private BoFunction function; + + @NotNull + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "role_id", nullable = false) + private BoRole role; + + @NotNull + @Column(name = "create_time", nullable = false) + private Instant createTime; + + @Size(max = 30) + @NotNull + @Column(name = "create_user", nullable = false, length = 30) + private String createUser; + +} \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoUser.java b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoUser.java new file mode 100644 index 0000000..90501c3 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/entity/BoUser.java @@ -0,0 +1,89 @@ +package com.vega.hrm.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.Instant; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "bo_user") +public class BoUser { + + @Id + @ColumnDefault("gen_random_uuid()") + @Column(name = "user_id", nullable = false) + private UUID id; + + @Size(max = 200) + @NotNull + @Column(name = "user_name", nullable = false, length = 200) + private String userName; + + @Size(max = 200) + @NotNull + @Column(name = "full_name", nullable = false, length = 200) + private String fullName; + + @Size(max = 50) + @NotNull + @Column(name = "status", nullable = false, length = 50) + private String status; + + @Size(max = 200) + @NotNull + @Column(name = "password", nullable = false, length = 200) + private String password; + + @Column(name = "pwd_expire_date") + private Instant pwdExpireDate; + + @NotNull + @Column(name = "created_date", nullable = false) + private Instant createdDate; + + @Size(max = 200) + @NotNull + @Column(name = "created_user", nullable = false, length = 200) + private String createdUser; + + @Column(name = "role_id") + private Long roleId; + + @NotNull + @ColumnDefault("0") + @Column(name = "is_password_changed", nullable = false) + private Long isPasswordChanged; + + @NotNull + @ColumnDefault("0") + @Column(name = "number_of_failed_logins", nullable = false) + private Long numberOfFailedLogins; + + @Column(name = "last_login_time") + private Instant lastLoginTime; + + @Column(name = "updated_date") + private Instant updatedDate; + + @Size(max = 20) + @Column(name = "updated_user", length = 20) + private String updatedUser; + + @Size(max = 100) + @Column(name = "uuid", length = 100) + private String uuid; + + @Size(max = 255) + @Column(name = "email") + private String email; + +} \ No newline at end of file diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/exceptions/GlobalExceptionHandler.java b/vega-hrm-core/src/main/java/com/vega/hrm/exceptions/GlobalExceptionHandler.java new file mode 100644 index 0000000..7e9d863 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/exceptions/GlobalExceptionHandler.java @@ -0,0 +1,55 @@ +package com.vega.hrm.exceptions; + + + +import com.vega.hrm.constants.ResponseCodeConst; +import com.vega.hrm.constants.ResponseMessageConst; +import com.vega.hrm.models.responses.BaseResponse; +import java.util.HashMap; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleValidationExceptions(MethodArgumentNotValidException ex) { + var messageValid = new StringBuilder(); + + Map errors = new HashMap<>(); + ex.getBindingResult() + .getFieldErrors() + .forEach( + error -> { + messageValid.append(error.getField()).append(":").append(error.getDefaultMessage()).append(";"); + errors.put(error.getField(), error.getDefaultMessage()); + }); + + return ResponseEntity.ok( + BaseResponse.>builder() + .code(ResponseCodeConst.INVALID) + .message(messageValid.substring(0, messageValid.length() - 1)) + .data(errors) + .build() + ); + } + + @ExceptionHandler({Exception.class}) + public ResponseEntity handleExceptions(Exception ex) { + log.error(ex.getMessage(), ex); + + return new ResponseEntity<>( + BaseResponse.>builder() + .code(ResponseCodeConst.INTERNAL_SYSTEM_ERROR) + .message(ResponseMessageConst.INTERNAL_SYSTEM_ERROR) + .build(), + HttpStatus.INTERNAL_SERVER_ERROR + ); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/filters/AuthorizationFilter.java b/vega-hrm-core/src/main/java/com/vega/hrm/filters/AuthorizationFilter.java new file mode 100644 index 0000000..2500c45 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/filters/AuthorizationFilter.java @@ -0,0 +1,30 @@ +package com.vega.hrm.filters; + + +import io.jsonwebtoken.ExpiredJwtException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.apache.logging.log4j.ThreadContext; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + + + +@Component +@Order(2) +@RequiredArgsConstructor +public class AuthorizationFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + filterChain.doFilter(request, response); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/filters/CorsFilter.java b/vega-hrm-core/src/main/java/com/vega/hrm/filters/CorsFilter.java new file mode 100644 index 0000000..ea46f4b --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/filters/CorsFilter.java @@ -0,0 +1,68 @@ +package com.vega.hrm.filters; + + +import com.vega.hrm.helpers.LogHelper; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.time.Instant; +import java.util.Arrays; +import java.util.UUID; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.util.Strings; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + + +@Component +@Slf4j +@Order(1) +public class CorsFilter extends OncePerRequestFilter { + + @Value("${cors.allowed-origins:*}") + private String[] allowedOrigins; + @Override + protected void doFilterInternal( + @NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain + ) { + try { + var startTime = Instant.now(); + var origin = request.getHeader("Origin"); + if (Strings.isNotBlank(origin) && Arrays.stream(allowedOrigins).toList() + .contains(origin)) { + response.setHeader("Access-Control-Allow-Origin", origin); + } + response.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, b"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setCharacterEncoding("UTF-8"); + if (request.getMethod().equalsIgnoreCase("OPTIONS")) { + response.setStatus(HttpServletResponse.SC_OK); + return; + } + var clientIp = request.getHeader("X-Forwarded-For"); + if (Strings.isBlank(clientIp)) { + clientIp = request.getRemoteAddr(); + } else { + clientIp = clientIp.split(",")[0]; + } + ThreadContext.put("ip", clientIp); + ThreadContext.put("uri", request.getRequestURI()); + var traceId = UUID.randomUUID().toString(); + ThreadContext.put("traceId", traceId); + LogHelper.info("Request start"); + filterChain.doFilter(request, response); + var duration = Instant.now().toEpochMilli() - startTime.toEpochMilli(); + LogHelper.info("Request end - Duration: " + duration + "ms"); + } catch (Exception e) { + LogHelper.error(e); + } + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CommonHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CommonHelper.java new file mode 100644 index 0000000..fb06741 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CommonHelper.java @@ -0,0 +1,117 @@ +package com.vega.hrm.helpers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; +import org.modelmapper.ModelMapper; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +public class CommonHelper { + + private static ModelMapper modelMapper = new ModelMapper(); + public static List mapList(List source, Class targetClass) { + return source + .stream() + .map(element -> modelMapper.map(element, targetClass)) + .collect(Collectors.toList()); + } + + public static Long convertStringToLong(String str) { + if (str == null || str.trim().isEmpty()) { + return null; + } + try { + return Long.parseLong(str.trim()); + } catch (NumberFormatException e) { + return null; + } + } + + public static String getClientIp(HttpServletRequest request) { + if (request == null) { + return "Unknown"; + } + + String ip = request.getHeader("X-Forwarded-For"); // Header used by proxies/load balancers + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); // Direct IP + } + if (ip != null && ip.contains(",")) { + ip = ip.split(",")[0].trim(); + } + return ip; + } + + public static String getClientIp() { + HttpServletRequest request = getCurrentHttpRequest(); + if (request == null) { + return "Unknown"; + } + return getClientIp(request); + } + + private static HttpServletRequest getCurrentHttpRequest() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes == null) { + return null; + } + return ((ServletRequestAttributes) requestAttributes).getRequest(); + } + + public static String convertObjectToCommaSeparated(T object){ + if (object == null) { + return ""; + } + + if (object instanceof List list) { + return list.stream() + .map(CommonHelper::convertObjectToCommaSeparated) + .collect(Collectors.joining("\n")); + } + + StringBuilder result = new StringBuilder(); + Field[] fields = object.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); // Cho phép truy cập vào các trường private + try { + Object value = field.get(object); + result.append(value).append(","); + } catch (IllegalAccessException e) { + LogHelper.error(e.getMessage()); + } + } + if (!result.isEmpty()) { + result.deleteCharAt(result.length() - 1); + } + return result.toString(); + } + + public static String convertObjectToString(Object object) { + try{ + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(object); + } + catch (Exception e) { + LogHelper.error(e.getMessage()); + return ""; + } + + } + +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CryptoHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CryptoHelper.java new file mode 100644 index 0000000..cb07b08 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/CryptoHelper.java @@ -0,0 +1,36 @@ +package com.vega.hrm.helpers; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class CryptoHelper { + + public static String hashSHA256(String input) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(hash); + } catch (NoSuchAlgorithmException ex) { + + log.error(ex.getMessage()); + return ""; + } + } + + private static String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(2 * hash.length); + for (int i = 0; i < hash.length; i++) { + String hex = Integer.toHexString(0xff & hash[i]); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/DateHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/DateHelper.java new file mode 100644 index 0000000..88d246f --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/DateHelper.java @@ -0,0 +1,111 @@ +package com.vega.hrm.helpers; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DateHelper { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + + public static Date convertStringToDate(String dateString) { + SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); + formatter.setLenient(false); + try { + return formatter.parse(dateString); + } catch (ParseException e) { + log.error("convertStringToDate Lỗi format dd/MM/yyyy"); + return null; + } + } + + public static Instant convertStringToInstant(String dateString, String pattern) { + try { + if (dateString == null || dateString.isEmpty()) { + pattern = "dd/MM/yyyy"; + } + if (dateString == null || dateString.isEmpty()) { + return null; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + LocalDateTime localDateTime; + if (pattern.equals("dd/MM/yyyy")) { + LocalDate localDate = LocalDate.parse(dateString, formatter); + LocalTime now = LocalTime.now(); + + localDateTime = LocalDateTime.of(localDate, now); + } else { + + localDateTime = LocalDateTime.parse(dateString, formatter); + } + + return localDateTime.toInstant(ZoneOffset.UTC); + } catch (Exception e) { + return null; + } + + } + + public static String convertDateToString(Date date, String format) { + if (date == null) { + return null; + } + SimpleDateFormat formatter = new SimpleDateFormat(format); + return formatter.format(date); + } + + public static String convertLocalDateToString(LocalDateTime date, String format) { + if (date == null) { + return null; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + return date.format(formatter); + } + + public static Date getStartOfDay(String dateStr) { + LocalDate localDate = LocalDate.parse(dateStr, FORMATTER); + LocalDateTime startOfDay = localDate.atStartOfDay().plusSeconds(1); // 00:00:01 + return Date.from(startOfDay.atZone(ZoneId.of("UTC")).toInstant()); + } + + public static Date convertDateZone(String dateStr,String pattern) { + DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern); + LocalDate localDate = LocalDate.parse(dateStr, format); + LocalDateTime startOfDay = localDate.atStartOfDay().plusSeconds(1); // 00:00:01 + return Date.from(startOfDay.atZone(ZoneId.of("UTC")).toInstant()); + } + + public static LocalDateTime getStartOfDayLocalDate(String dateStr) { + LocalDate localDate = LocalDate.parse(dateStr, FORMATTER); + LocalDateTime startOfDay = localDate.atStartOfDay().plusSeconds(1); // 00:00:01 + return startOfDay.atZone(ZoneId.of("UTC")).toLocalDateTime(); + } + + public static LocalDateTime convertDateZoneLocalDate(String dateStr,String pattern) { + DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern); + LocalDate localDate = LocalDate.parse(dateStr, format); + LocalDateTime startOfDay = localDate.atStartOfDay().plusSeconds(1); // 00:00:01 + return LocalDateTime.from(startOfDay.atZone(ZoneId.of("UTC")).toInstant()); + } + + public static LocalDateTime getEndOfDayLocalDate(String dateStr) { + LocalDate localDate = LocalDate.parse(dateStr, FORMATTER); + LocalDateTime endOfDay = localDate.atTime(23, 59, 59); // 00:00:01 + return endOfDay.atZone(ZoneId.of("UTC")).toLocalDateTime(); + } + + public static Date getEndOfDay(String dateStr) { + LocalDate localDate = LocalDate.parse(dateStr, FORMATTER); + LocalDateTime endOfDay = localDate.atTime(23, 59, 59); // 23:59:59 + return Date.from(endOfDay.atZone(ZoneId.of("UTC")).toInstant()); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JsonConvertHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JsonConvertHelper.java new file mode 100644 index 0000000..5687c5d --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JsonConvertHelper.java @@ -0,0 +1,38 @@ +package com.vega.hrm.helpers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class JsonConvertHelper { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static String toJsonString(Object object) { + try { + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(LocalDateTime.class, + new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"))); + objectMapper.registerModule(javaTimeModule); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.findAndRegisterModules(); + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + LogHelper.error(e); + return ""; + } + } + + + public static T convertStringToObject(String text,Class clazz) { + try { + return objectMapper.readValue(text,clazz); + } catch (JsonProcessingException e) { + LogHelper.error(e); + return null; + } + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JwtHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JwtHelper.java new file mode 100644 index 0000000..c99605c --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/JwtHelper.java @@ -0,0 +1,79 @@ +package com.vega.hrm.helpers; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.UnsupportedJwtException; +import io.jsonwebtoken.security.Keys; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Date; +import java.util.Map; +import javax.crypto.spec.SecretKeySpec; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class JwtHelper { + + private static final String SECRET_KEY = "b05f17acb2d09f123a472406051512ca08b"; + private static final long EXPIRATION_TIME_MS = 600_000; // 10 phut + private static final Key SIGNING_KEY = generateSigningKey(); + + public static String generateToken(String username, Long userId, Long roleId) { + return Jwts.builder() + .claims(Map.of( + "userId", userId, + "roleId", roleId, + "userName", username + )) + .subject(username) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME_MS)) + .signWith(SIGNING_KEY) + .compact(); + } + + private static Key generateSigningKey() { + return Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8)); + } + + public static Long getUserId(String token) { + Claims claims = extractUsername(token); + return Long.parseLong(claims.get("userId").toString()); + } + + public static Long getRoleId(String token) { + Claims claims = extractUsername(token); + return Long.parseLong(claims.get("roleId").toString()); + } + + public static String getDataByKey(String token, String key) { + Claims claims = extractUsername(token); + return claims.get(key).toString(); + } + + public static Claims extractUsername(String token) { + return Jwts.parser() + .verifyWith(new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256")) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + public static boolean validateToken(String authToken) { + try { + extractUsername(authToken); + return true; + } catch (MalformedJwtException ex) { + log.error("Invalid JWT token"); + } catch (ExpiredJwtException ex) { + log.error("Expired JWT token"); + } catch (UnsupportedJwtException ex) { + log.error("Unsupported JWT token"); + } catch (IllegalArgumentException ex) { + log.error("JWT claims string is empty."); + } + return false; + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHelper.java new file mode 100644 index 0000000..f96f9f4 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHelper.java @@ -0,0 +1,45 @@ +package com.vega.hrm.helpers; + +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.ThreadContext; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class LogHelper { + + public static void info(String message) { + log.info("{}", getLogContent(message)); + } + + public static void error(String message) { + log.error("{}", getLogContent(message)); + } + + public static void error(Exception e) { + var traceBuilder = new StringBuilder(); + + for (var stackTraceElement : e.getStackTrace()) { + traceBuilder.append(String.format( + "\n at %s.%s (%s:%s)", + stackTraceElement.getClassName(), + stackTraceElement.getMethodName(), + stackTraceElement.getFileName(), + stackTraceElement.getLineNumber() + )); + } + + log.error("{}", getLogContent(String.format("%s: %s%s", e.getClass().getName(), e.getMessage(), traceBuilder))); + } + + private static String getLogContent(String message) { + return String.format( + "[ip - %s] [path - %s] [req - %s] [user - %s] - %s", + ThreadContext.get("ip"), + ThreadContext.get("uri"), + ThreadContext.get("traceId"), + ThreadContext.get("userName"), + message + ); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHisTemplateHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHisTemplateHelper.java new file mode 100644 index 0000000..a5dae2e --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/LogHisTemplateHelper.java @@ -0,0 +1,30 @@ +package com.vega.hrm.helpers; + +import java.util.HashMap; +import org.apache.logging.log4j.ThreadContext; + +public class LogHisTemplateHelper { + + public static String logContent(String actionType, String feature, T dataOld, T dataNew) { + return String.format( + "[ip - %s] [Thao tác - %s - %s] [user - %s] - %s
---------->>>
%s", + ThreadContext.get("ip"), + feature, + actionUserDir.get(actionType), + ThreadContext.get("userName"), CommonHelper.convertObjectToCommaSeparated(dataOld), + CommonHelper.convertObjectToCommaSeparated(dataNew) + ); + } + + public static HashMap actionUserDir = + new HashMap<>() { + { + put("0", "Query"); + put("1", "AddNew"); + put("2", "Update"); + put("3", "Delete"); + put("4", "ChangeStatus"); + put("5", "Others"); + } + }; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/helpers/StringHelper.java b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/StringHelper.java new file mode 100644 index 0000000..19bc422 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/helpers/StringHelper.java @@ -0,0 +1,29 @@ +package com.vega.hrm.helpers; + +import java.security.SecureRandom; + +public class StringHelper { + + public static String PW_CHARS = "abcdefghjkmnpqrstuvwxyz"; + public static String PW_NUMBERS = "123456789"; + public static String PW_SPECIAL_CHARS = "!#$%&()*+,-./:;<=>?@[]^_{}~"; + + private static final SecureRandom RANDOM = new SecureRandom(); + + public static String randomStr(String str, int length) { + if (str == null || str.isBlank()) { + return ""; + } + + length = Math.min(length, str.length()); + StringBuilder stringBuilder = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + int index = RANDOM.nextInt(str.length()); + + stringBuilder.append(str.charAt(index)); + } + + return stringBuilder.toString(); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/RedisEccKeyPair.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/RedisEccKeyPair.java new file mode 100644 index 0000000..df89cb9 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/RedisEccKeyPair.java @@ -0,0 +1,18 @@ +package com.vega.hrm.models; + +import java.time.Instant; +import lombok.Getter; +import lombok.NoArgsConstructor; +import vn.vnpay.dvnh.backoffice.core.common.utility.DateTimeUtils; +@Getter +@NoArgsConstructor +public class RedisEccKeyPair { + private String privateKey; + private String expiration; + + public RedisEccKeyPair(String privateKey, Instant expiration) { + this.privateKey = privateKey; + this.expiration = DateTimeUtils.format(expiration); + } + +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseDecryptedRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseDecryptedRequest.java new file mode 100644 index 0000000..b7322c4 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseDecryptedRequest.java @@ -0,0 +1,13 @@ +package com.vega.hrm.models.requests; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class BaseDecryptedRequest { + + private String request; + private String key; + private String p; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseRequest.java new file mode 100644 index 0000000..d363f4f --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/BaseRequest.java @@ -0,0 +1,8 @@ +package com.vega.hrm.models.requests; + +import lombok.Getter; + +@Getter +public class BaseRequest { + +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/ChangeStatusRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/ChangeStatusRequest.java new file mode 100644 index 0000000..014f69d --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/ChangeStatusRequest.java @@ -0,0 +1,11 @@ +package com.vega.hrm.models.requests; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ChangeStatusRequest extends BaseRequest { + private T id; + private String status; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/CreateUserHistoryRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/CreateUserHistoryRequest.java new file mode 100644 index 0000000..0a596f6 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/CreateUserHistoryRequest.java @@ -0,0 +1,19 @@ +package com.vega.hrm.models.requests; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Builder +@Setter +@AllArgsConstructor +public class CreateUserHistoryRequest { + private String funcName; + private String actionType; + private String action; + private String oldValue; + private String newValue; + private String editTable; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/GetByIdRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/GetByIdRequest.java new file mode 100644 index 0000000..cbf9fb5 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/GetByIdRequest.java @@ -0,0 +1,11 @@ +package com.vega.hrm.models.requests; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class GetByIdRequest extends BaseRequest { + private T id; +} + diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/PagingRequest.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/PagingRequest.java new file mode 100644 index 0000000..c572c80 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/requests/PagingRequest.java @@ -0,0 +1,29 @@ +package com.vega.hrm.models.requests; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Positive; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +@Getter +@Setter +public class PagingRequest { + @Min(1) + private int pageIndex; + + @Positive + private int pageSize; + + private T filter; + + public Pageable toPageable(){ + return PageRequest.of(this.pageIndex - 1, this.pageSize, Sort.unsorted()); + } + + public Pageable toPageable(Sort sort){ + return PageRequest.of(this.pageIndex - 1, this.pageSize, sort); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseEncryptedResponse.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseEncryptedResponse.java new file mode 100644 index 0000000..322b5b9 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseEncryptedResponse.java @@ -0,0 +1,5 @@ +package com.vega.hrm.models.responses; + +public record BaseEncryptedResponse(String key, String response) { +} + diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseResponse.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseResponse.java new file mode 100644 index 0000000..c664309 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/BaseResponse.java @@ -0,0 +1,57 @@ +package com.vega.hrm.models.responses; + + + +import com.vega.hrm.constants.ResponseCodeConst; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.apache.logging.log4j.ThreadContext; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Accessors(chain = true) +public class BaseResponse { + @Builder.Default + private String traceId = ThreadContext.get("traceId"); + + @Builder.Default + private String code = ResponseCodeConst.SUCCESS; + + private String message; + private T data; + + public static BaseResponse Success(String msg) { + return BaseResponse.builder() + .code(ResponseCodeConst.SUCCESS) + .message(msg) + .build(); + } + + public static BaseResponse Invalid(String msg) { + return BaseResponse.builder() + .code(ResponseCodeConst.INVALID) + .message(msg) + .build(); + } + + public static BaseResponse NotFound(String msg) { + return BaseResponse.builder() + .code(ResponseCodeConst.NOT_FOUND) + .message(msg) + .build(); + } + + public static BaseResponse InternalSystemError() { + return BaseResponse.builder() + .code(ResponseCodeConst.INTERNAL_SYSTEM_ERROR) + .message("Internal System Error") + .build(); + } +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedList.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedList.java new file mode 100644 index 0000000..f7c66c3 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedList.java @@ -0,0 +1,21 @@ +package com.vega.hrm.models.responses; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Accessors(chain = true) +public class PagedList { + private int pageCount; + private long totalItemCount; + private List items; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedListResponse.java b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedListResponse.java new file mode 100644 index 0000000..5abe019 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/models/responses/PagedListResponse.java @@ -0,0 +1,29 @@ +package com.vega.hrm.models.responses; + + +import com.vega.hrm.constants.ResponseCodeConst; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.apache.logging.log4j.ThreadContext; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Accessors(chain = true) +public class PagedListResponse { + + @Builder.Default + private String traceId = ThreadContext.get("traceId"); + + @Builder.Default + private String code = ResponseCodeConst.SUCCESS; + + private String message; + private PagedList data; +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomRequestWrapper.java b/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomRequestWrapper.java new file mode 100644 index 0000000..a5b6928 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomRequestWrapper.java @@ -0,0 +1,57 @@ +package com.vega.hrm.wrapper; + +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CustomRequestWrapper extends HttpServletRequestWrapper { + + private final byte[] body; + + public CustomRequestWrapper(HttpServletRequest request, String bodyString) { + super(request); + this.body = bodyString.getBytes(StandardCharsets.UTF_8); + } + + @Override + public ServletInputStream getInputStream() { + return new ServletInputStream() { + private final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body); + + @Override + public int read() { + return byteArrayInputStream.read(); + } + + @Override + public boolean isFinished() { + return byteArrayInputStream.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8)); + } + +} diff --git a/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomResponseWrapper.java b/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomResponseWrapper.java new file mode 100644 index 0000000..bab8c42 --- /dev/null +++ b/vega-hrm-core/src/main/java/com/vega/hrm/wrapper/CustomResponseWrapper.java @@ -0,0 +1,50 @@ +package com.vega.hrm.wrapper; + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; + +public class CustomResponseWrapper extends HttpServletResponseWrapper { + + private final ByteArrayOutputStream byteArrayOutputStream; + private final PrintWriter printWriter; + + public CustomResponseWrapper(HttpServletResponse response) { + super(response); + this.byteArrayOutputStream = new ByteArrayOutputStream(); + this.printWriter = new PrintWriter(byteArrayOutputStream); + } + + @Override + public ServletOutputStream getOutputStream() { + return new ServletOutputStream() { + @Override + public void write(int b) { + byteArrayOutputStream.write(b); + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + + } + }; + } + + @Override + public PrintWriter getWriter() { + return printWriter; + } + + public String getContent() { + return byteArrayOutputStream.toString(StandardCharsets.UTF_8); + } +}