diff --git a/pom.xml b/pom.xml index e0214c39a60bbab4441036ca9f80289dd052d647..0bc83f38e08b35b340128847d505da6f15fecd7a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.boot @@ -34,6 +35,10 @@ org.springframework.boot spring-boot-starter-data-jpa --> + + org.mariadb.jdbc + mariadb-java-client + org.springframework.boot spring-boot-starter-validation diff --git a/src/main/java/com/attendenceSystem/constant/Routes.java b/src/main/java/com/attendenceSystem/constant/Routes.java new file mode 100644 index 0000000000000000000000000000000000000000..020d19e5dbb36541a1fe6692393228b5b5c0ecc2 --- /dev/null +++ b/src/main/java/com/attendenceSystem/constant/Routes.java @@ -0,0 +1,13 @@ +package com.attendenceSystem.constant; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class Routes { + public static final class Auth { + public static final String ROOT = "/auth"; + public static final String LOGIN = "/login"; + public static final String REGISTER = "/register"; + } +} diff --git a/src/main/java/com/attendenceSystem/exception/GlobalExceptionHandler.java b/src/main/java/com/attendenceSystem/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..910317cb08d372229975c0fb31952a3edac76247 --- /dev/null +++ b/src/main/java/com/attendenceSystem/exception/GlobalExceptionHandler.java @@ -0,0 +1,41 @@ +// package com.attendenceSystem.exception; + +// import org.springframework.http.HttpStatus; +// import org.springframework.security.access.AccessDeniedException; +// import org.springframework.web.bind.annotation.ControllerAdvice; +// import org.springframework.web.bind.annotation.ExceptionHandler; +// import org.springframework.web.bind.annotation.ResponseStatus; + +// import com.attendenceSystem.exception.custom.BadRequestException; +// import com.attendenceSystem.exception.custom.ResourceNotFoundException; + +// @ControllerAdvice +// public class GlobalExceptionHandler { +// @ExceptionHandler(ResourceNotFoundException.class) +// @ResponseStatus(HttpStatus.NOT_FOUND) +// public String notFound() { +// return "error/404"; +// } + +// @ExceptionHandler(AccessDeniedException.class) +// @ResponseStatus(HttpStatus.FORBIDDEN) +// public String forbidden() { +// return "error/403"; +// } + +// @ExceptionHandler(BadRequestException.class) +// @ResponseStatus(HttpStatus.BAD_REQUEST) +// public String badRequest() { +// return "error/400"; +// } + +// @ExceptionHandler(Exception.class) +// @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) +// public String internalServerError(Exception ex) { + +// ex.printStackTrace(); + +// return "error/500"; +// } + +// } \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/exception/custom/BadRequestException.java b/src/main/java/com/attendenceSystem/exception/custom/BadRequestException.java new file mode 100644 index 0000000000000000000000000000000000000000..d7d45dfc00c4687e9e1a32e9827363996d6cebce --- /dev/null +++ b/src/main/java/com/attendenceSystem/exception/custom/BadRequestException.java @@ -0,0 +1,7 @@ +package com.attendenceSystem.exception.custom; + +public class BadRequestException extends RuntimeException{ + public BadRequestException(String message){ + super(message); + } +} diff --git a/src/main/java/com/attendenceSystem/exception/custom/ResourceNotFoundException.java b/src/main/java/com/attendenceSystem/exception/custom/ResourceNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..07c9d0f1ffeeb3f69ebd71e1f2903d29405fe57e --- /dev/null +++ b/src/main/java/com/attendenceSystem/exception/custom/ResourceNotFoundException.java @@ -0,0 +1,7 @@ +package com.attendenceSystem.exception.custom; + +public class ResourceNotFoundException extends RuntimeException{ + public ResourceNotFoundException(String message){ + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/module/log/dto/request/AuditLogRequest.java b/src/main/java/com/attendenceSystem/module/log/dto/request/AuditLogRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..e56d8c11f7e0552daa0c601509943f9af19c99ae --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/dto/request/AuditLogRequest.java @@ -0,0 +1,14 @@ +package com.attendenceSystem.module.log.dto.request; + +import com.attendenceSystem.module.log.entity.enums.LogAction; +import com.attendenceSystem.module.log.entity.enums.LogEntityType; +import com.attendenceSystem.module.user.entity.User; + +public record AuditLogRequest( + User user, + LogEntityType logEntityType, + Long entityId, + LogAction action, + String description) { + +} diff --git a/src/main/java/com/attendenceSystem/module/log/dto/response/AuditLogResponse.java b/src/main/java/com/attendenceSystem/module/log/dto/response/AuditLogResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..6697f0bf705a87e21db7607349962c62d88c0568 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/dto/response/AuditLogResponse.java @@ -0,0 +1,18 @@ +package com.attendenceSystem.module.log.dto.response; + +import com.attendenceSystem.module.log.entity.enums.LogAction; +import com.attendenceSystem.module.log.entity.enums.LogEntityType; + +import lombok.Builder; + +@Builder +public record AuditLogResponse( + Long id, + Long userId, + String username, + LogEntityType entityType, + Long entityId, + LogAction action, + String description, + String createdAt) { +} diff --git a/src/main/java/com/attendenceSystem/module/log/entity/AuditLog.java b/src/main/java/com/attendenceSystem/module/log/entity/AuditLog.java new file mode 100644 index 0000000000000000000000000000000000000000..ebf5e78fa22b768365814afe73119d6db1a30926 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/entity/AuditLog.java @@ -0,0 +1,58 @@ +package com.attendenceSystem.module.log.entity; + +import java.time.Instant; + +import org.hibernate.annotations.CreationTimestamp; + +import com.attendenceSystem.module.log.entity.enums.LogAction; +import com.attendenceSystem.module.log.entity.enums.LogEntityType; +import com.attendenceSystem.module.user.entity.User; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "audit_logs") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuditLog { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "entity_id") + private Long entityId; + + @Column(name = "entity_type", nullable = false) + private LogEntityType entityType; + + @Column(name = "action", nullable = false) + private LogAction action; + + @Column(name = "description", columnDefinition = "LONGTEXT") + private String description; + + @CreationTimestamp + @Column(name = "created_at", updatable = false) + private Instant createdAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", updatable = false) + private User user; +} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/module/log/entity/converter/LogActionConverter.java b/src/main/java/com/attendenceSystem/module/log/entity/converter/LogActionConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..6d8224a607977dc2cf2fab428bf1e938cac2f769 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/entity/converter/LogActionConverter.java @@ -0,0 +1,21 @@ +package com.attendenceSystem.module.log.entity.converter; + +import com.attendenceSystem.module.log.entity.enums.LogAction; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter(autoApply = true) +public class LogActionConverter implements AttributeConverter { + + @Override + public Long convertToDatabaseColumn(LogAction attribute) { + return attribute == null ? null : attribute.getCode(); + } + + @Override + public LogAction convertToEntityAttribute(Long dbData) { + return dbData == null ? null : LogAction.fromValue(dbData); + } + +} diff --git a/src/main/java/com/attendenceSystem/module/log/entity/converter/LogEntityTypeConverter.java b/src/main/java/com/attendenceSystem/module/log/entity/converter/LogEntityTypeConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..6c00a0b51e8b210cfe7b241ba6f7c3823333b503 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/entity/converter/LogEntityTypeConverter.java @@ -0,0 +1,21 @@ +package com.attendenceSystem.module.log.entity.converter; + +import com.attendenceSystem.module.log.entity.enums.LogEntityType; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter(autoApply = true) +public class LogEntityTypeConverter implements AttributeConverter{ + + @Override + public Long convertToDatabaseColumn(LogEntityType attribute) { + return attribute == null ? null : attribute.getCode(); + } + + @Override + public LogEntityType convertToEntityAttribute(Long dbData) { + return dbData == null ? null : LogEntityType.fromValue(dbData); + } + +} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/module/log/entity/enums/LogAction.java b/src/main/java/com/attendenceSystem/module/log/entity/enums/LogAction.java new file mode 100644 index 0000000000000000000000000000000000000000..dcced205fc9ff2d47372bccef96b3908a7e966ef --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/entity/enums/LogAction.java @@ -0,0 +1,31 @@ +package com.attendenceSystem.module.log.entity.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum LogAction { + CREATE(1), + UPDATE(2), + DELETE(3), + RESTORE(4), + APPROVE(5), + LOCK(6), + UNLOCK(7), + CHANGE_PASSWORD(8), + LOGIN(9), + LOGOUT(10), + PROCESS(11); + + private final long code; + + public static LogAction fromValue(long code) { + for (LogAction action : LogAction.values()) { + if (action.code == code) { + return action; + } + } + throw new IllegalArgumentException("Không tìm thấy loại hành động: " + code); + } +} diff --git a/src/main/java/com/attendenceSystem/module/log/entity/enums/LogEntityType.java b/src/main/java/com/attendenceSystem/module/log/entity/enums/LogEntityType.java new file mode 100644 index 0000000000000000000000000000000000000000..cf97d347f8d649b5bc964897327c97df759c3e0f --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/entity/enums/LogEntityType.java @@ -0,0 +1,20 @@ +package com.attendenceSystem.module.log.entity.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum LogEntityType { + USER(1); + + private final long code; + public static LogEntityType fromValue(long code) { + for (LogEntityType action : LogEntityType.values()) { + if (action.code == code) { + return action; + } + } + throw new IllegalArgumentException("Không tìm thấy loại Entity: " + code); + } +} diff --git a/src/main/java/com/attendenceSystem/module/log/mapper/request/AuditLogRequestMapping.java b/src/main/java/com/attendenceSystem/module/log/mapper/request/AuditLogRequestMapping.java new file mode 100644 index 0000000000000000000000000000000000000000..e9a993e1597c6dccbc1b2a786454e420d377d94c --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/mapper/request/AuditLogRequestMapping.java @@ -0,0 +1,5 @@ +package com.attendenceSystem.module.log.mapper.request; + +public class AuditLogRequestMapping { + +} diff --git a/src/main/java/com/attendenceSystem/module/log/mapper/response/AuditLogResponseMapper.java b/src/main/java/com/attendenceSystem/module/log/mapper/response/AuditLogResponseMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4bc88806b568e524d52ab2ff522c84df5aedb402 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/mapper/response/AuditLogResponseMapper.java @@ -0,0 +1,20 @@ +package com.attendenceSystem.module.log.mapper.response; + +import com.attendenceSystem.module.log.dto.response.AuditLogResponse; +import com.attendenceSystem.module.log.entity.AuditLog; +import com.attendenceSystem.util.TimeUtil; + +public class AuditLogResponseMapper { + public static AuditLogResponse fromEntity(AuditLog auditLog) { + return AuditLogResponse.builder() + .id(auditLog.getId()) + .userId(auditLog.getUser().getId()) + .username(auditLog.getUser().getUsername()) + .entityType(auditLog.getEntityType()) + .entityId(auditLog.getEntityId()) + .action(auditLog.getAction()) + .description(auditLog.getDescription()) + .createdAt(TimeUtil.formatInstant(auditLog.getCreatedAt(), null)) + .build(); + } +} diff --git a/src/main/java/com/attendenceSystem/module/log/repository/AuditLogRepository.java b/src/main/java/com/attendenceSystem/module/log/repository/AuditLogRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..ee7c16703e108704f71099f5ebfc17c0a1f2291a --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/repository/AuditLogRepository.java @@ -0,0 +1,13 @@ +package com.attendenceSystem.module.log.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.attendenceSystem.module.log.entity.AuditLog; + +@Repository +public interface AuditLogRepository extends JpaRepository { + Page findAllByOrderByCreatedAtDesc(Pageable pageable); +} diff --git a/src/main/java/com/attendenceSystem/module/log/service/AuditLogService.java b/src/main/java/com/attendenceSystem/module/log/service/AuditLogService.java new file mode 100644 index 0000000000000000000000000000000000000000..e812abfed4119fb7af57ad0be624097ec6af270d --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/service/AuditLogService.java @@ -0,0 +1,13 @@ +package com.attendenceSystem.module.log.service; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import com.attendenceSystem.module.log.dto.request.AuditLogRequest; +import com.attendenceSystem.module.log.dto.response.AuditLogResponse; + +public interface AuditLogService { + void log(AuditLogRequest request); + + Page getLogs(Pageable pageable); +} diff --git a/src/main/java/com/attendenceSystem/module/log/service/impl/AuditLogServiceImpl.java b/src/main/java/com/attendenceSystem/module/log/service/impl/AuditLogServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..879832fabd40b4c54707ec3894d78e4fade34693 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/log/service/impl/AuditLogServiceImpl.java @@ -0,0 +1,40 @@ +package com.attendenceSystem.module.log.service.impl; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; + +import com.attendenceSystem.module.log.dto.request.AuditLogRequest; +import com.attendenceSystem.module.log.dto.response.AuditLogResponse; +import com.attendenceSystem.module.log.entity.AuditLog; +import com.attendenceSystem.module.log.mapper.response.AuditLogResponseMapper; +import com.attendenceSystem.module.log.repository.AuditLogRepository; +import com.attendenceSystem.module.log.service.AuditLogService; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AuditLogServiceImpl implements AuditLogService { + private final AuditLogRepository auditLogRepository; + + @Transactional + @Override + public void log(AuditLogRequest request) { + AuditLog auditLog = AuditLog.builder() + .user(request.user()) + .entityType(request.logEntityType()) + .entityId(request.entityId()) + .action(request.action()) + .description(request.description()) + .build(); + auditLogRepository.save(auditLog); + } + + @Override + public Page getLogs(Pageable pageable) { + return auditLogRepository + .findAll(pageable) + .map(AuditLogResponseMapper::fromEntity); + } + +} diff --git a/src/main/java/com/attendenceSystem/module/user/controller/AuthController.java b/src/main/java/com/attendenceSystem/module/user/controller/AuthController.java new file mode 100644 index 0000000000000000000000000000000000000000..d7d943f41a250974c5f2184334bdfbffe9d1bf75 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/controller/AuthController.java @@ -0,0 +1,25 @@ +package com.attendenceSystem.module.user.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.attendenceSystem.constant.Routes; +import com.attendenceSystem.module.user.service.AuthService; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; + + + +@Controller +@RequestMapping(Routes.Auth.ROOT) +@RequiredArgsConstructor +public class AuthController { + private final AuthService authService; + + @GetMapping(Routes.Auth.REGISTER) + public String toRegisterPage() { + return "auth/register"; + } + +} diff --git a/src/main/java/com/attendenceSystem/module/user/dto/request/LoginRequest.java b/src/main/java/com/attendenceSystem/module/user/dto/request/LoginRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..4b2fd0b3bf967e4a96024ee280620b5f1830f98e --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/dto/request/LoginRequest.java @@ -0,0 +1,13 @@ +package com.attendenceSystem.module.user.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record LoginRequest( + @NotBlank(message = "Tên đăng nhập hoặc email không được để trống") + String login, + + @NotBlank(message = "Mật khẩu không được để trống") + @Size(min = 8, message = "Mật khẩu phải chứa ít nhất 8 kí tự") + String password) { +} diff --git a/src/main/java/com/attendenceSystem/module/user/dto/request/RegisterRequest.java b/src/main/java/com/attendenceSystem/module/user/dto/request/RegisterRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..9ec1cce629ba7302889466777a2e960a4813c8c5 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/dto/request/RegisterRequest.java @@ -0,0 +1,37 @@ +package com.attendenceSystem.module.user.dto.request; + +import com.attendenceSystem.annotation.PasswordMatch; +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +@PasswordMatch +public record RegisterRequest( + + @NotBlank(message = "Tên đăng nhập không được để trống") + @Size(min = 3, max = 30, message = "Tên đăng nhập phải có độ dài từ 3 đến 30 ký tự") + @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "Tên đăng nhập không được chứa ký tự đặc biệt") + String username, + + @NotBlank(message = "Email không được để trống") + @Size(max = 255, message = "Email không được vượt quá 255 ký tự") + @Email(message = "Email không đúng định dạng") + String email, + + @NotBlank(message = "Mật khẩu không được để trống") + @Size(min = 8, message = "Mật khẩu phải chứa ít nhất 8 kí tự") + String password, + + @NotBlank(message = "Mật khẩu xác nhận không được để trống") + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + String rePassword, + + @NotBlank(message = "Họ tên không được để trống") + @Size(max = 255, message = "Họ tên không được vượt quá 255 ký tự") + String fullName + +) { +} diff --git a/src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java b/src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..6196728a9c8f7dbe3308d67f950ce269aa052c8f --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java @@ -0,0 +1,14 @@ +package com.attendenceSystem.module.user.dto.response; + +import lombok.Builder; + +@Builder +public record UserResponse( + Long id, + String username, + String email, + String fullName, + Boolean isActive, + String role) { + +} diff --git a/src/main/java/com/attendenceSystem/module/user/entity/User.java b/src/main/java/com/attendenceSystem/module/user/entity/User.java new file mode 100644 index 0000000000000000000000000000000000000000..fe38353503909efe792f5cb8f6cb6c8536332bcd --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/entity/User.java @@ -0,0 +1,57 @@ +package com.attendenceSystem.module.user.entity; + +import java.time.Instant; + +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import com.attendenceSystem.module.user.entity.enums.Role; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + @Column(name = "username", unique = true, nullable = false, length = 30) + private String username; + @Column(name = "email", unique = true, nullable = false, length = 255) + private String email; + @Column(name = "password", nullable = false, length = 255) + private String password; + @Column(name = "role", nullable = false) + private Role role; + @Column(name = "is_active", nullable = false) + @Builder.Default + private boolean isActive = true; + @Column(name = "full_name", nullable = false, length = 255) + private String fullName; + @CreationTimestamp + @Column(name = "created_at", nullable = false, updatable = false) + private Instant createdAt; + @UpdateTimestamp + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + + @Column(name = "must_change_password", nullable = false) + @Builder.Default + private boolean mustChangePassword = false; +} diff --git a/src/main/java/com/attendenceSystem/module/user/entity/converter/RoleConverter.java b/src/main/java/com/attendenceSystem/module/user/entity/converter/RoleConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..20a3df6914734c8d8d26c24e0d22d48366551e5c --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/entity/converter/RoleConverter.java @@ -0,0 +1,20 @@ +package com.attendenceSystem.module.user.entity.converter; + +import com.attendenceSystem.module.user.entity.enums.Role; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter(autoApply = true) +public class RoleConverter implements AttributeConverter { + + @Override + public Integer convertToDatabaseColumn(Role role) { + return role == null ? null : role.getValue(); + } + + @Override + public Role convertToEntityAttribute(Integer dbData) { + return dbData == null ? null : Role.fromValue(dbData); + } +} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/user/entity/enums/Role.java b/src/main/java/com/attendenceSystem/module/user/entity/enums/Role.java similarity index 89% rename from src/main/java/com/attendenceSystem/user/entity/enums/Role.java rename to src/main/java/com/attendenceSystem/module/user/entity/enums/Role.java index a73799070127663b716635055803976b5751821c..d4fee264d997dd936b043d8fdcf9f3a02bda0ff4 100644 --- a/src/main/java/com/attendenceSystem/user/entity/enums/Role.java +++ b/src/main/java/com/attendenceSystem/module/user/entity/enums/Role.java @@ -1,4 +1,4 @@ -package com.attendenceSystem.user.entity.enums; +package com.attendenceSystem.module.user.entity.enums; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java b/src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..83a04d2bb6e731c32dc8040197e4eccf440e344b --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java @@ -0,0 +1,19 @@ +package com.attendenceSystem.module.user.mapper.request; + +import com.attendenceSystem.module.user.dto.request.RegisterRequest; +import com.attendenceSystem.module.user.entity.User; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RegisterRequestMapper { + public static User toEntity(RegisterRequest request, String hashPassword) { + return User.builder() + .username(request.username()) + .email(request.email()) + .password(hashPassword) + .fullName(request.fullName()) + .build(); + } +} diff --git a/src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java b/src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..00e4d6048a7d9af5f98905d2000f5029c959123e --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java @@ -0,0 +1,28 @@ +package com.attendenceSystem.module.user.mapper.response; + +import java.time.ZoneId; + +import org.springframework.stereotype.Component; + +import com.attendenceSystem.module.user.dto.response.UserResponse; +import com.attendenceSystem.module.user.entity.User; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class UserResponseMapper { + + private final ZoneId applicationZoneId; + + public UserResponse fromEntity(User user) { + return UserResponse.builder() + .id(user.getId()) + .username(user.getUsername()) + .email(user.getEmail()) + .fullName(user.getFullName()) + .isActive(user.isActive()) + .role(user.getRole().name()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java b/src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..f7a7d63c5971b75e60ab04255cde21fa4033e7d1 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java @@ -0,0 +1,24 @@ +package com.attendenceSystem.module.user.repository; + +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.attendenceSystem.module.user.entity.User; + +@Repository +public interface UserRepository extends JpaRepository { + Optional findUserByUsername(String username); + Optional findUserByEmail(String email); + boolean existsByUsername(String username); + boolean existsByEmail(String email); + Optional findUserByUsernameOrEmail(String username, String email); + boolean existsByUsernameOrEmail(String username, String email); + Page findAllByOrderByIdAsc(Pageable pageable); + long countByIsActiveTrue(); + long countByIsActiveFalse(); + Optional findByUsername(String username); +} diff --git a/src/main/java/com/attendenceSystem/module/user/service/AuthService.java b/src/main/java/com/attendenceSystem/module/user/service/AuthService.java new file mode 100644 index 0000000000000000000000000000000000000000..30f774edf70cca332ca1a338c42248399ffe2b29 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/service/AuthService.java @@ -0,0 +1,12 @@ +package com.attendenceSystem.module.user.service; + +import com.attendenceSystem.module.user.dto.request.LoginRequest; +import com.attendenceSystem.module.user.dto.request.RegisterRequest; +import com.attendenceSystem.module.user.dto.response.UserResponse; + +public interface AuthService { + UserResponse login(LoginRequest request); + + void register(RegisterRequest request); + +} diff --git a/src/main/java/com/attendenceSystem/module/user/service/UserService.java b/src/main/java/com/attendenceSystem/module/user/service/UserService.java new file mode 100644 index 0000000000000000000000000000000000000000..29cd05821fdfd193033741f14d525e6abfc4493b --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/service/UserService.java @@ -0,0 +1,12 @@ +package com.attendenceSystem.module.user.service; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import com.attendenceSystem.module.user.dto.response.UserResponse; + +public interface UserService { + Page getAccounts(Pageable pageable); + UserResponse getById(Long id); + void deleteUser(Long id); +} diff --git a/src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java b/src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2373209ec3d775f9a58006c88a0e8aede8ad523a --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java @@ -0,0 +1,72 @@ +package com.attendenceSystem.module.user.service.impl; + +import com.attendenceSystem.module.user.mapper.request.RegisterRequestMapper; +import com.attendenceSystem.module.user.mapper.response.UserResponseMapper; +import java.util.Optional; + +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.attendenceSystem.module.user.dto.request.LoginRequest; +import com.attendenceSystem.module.user.dto.request.RegisterRequest; +import com.attendenceSystem.module.user.dto.response.UserResponse; +import com.attendenceSystem.module.user.entity.User; +import com.attendenceSystem.module.user.repository.UserRepository; +import com.attendenceSystem.module.user.service.AuthService; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AuthServiceImpl implements AuthService { + private final UserResponseMapper userResponseMapper; + private final UserRepository userRepository; + private final AuthenticationManager authenticationManager; + private final PasswordEncoder passwordEncoder; + + @Transactional + @Override + public void register(RegisterRequest request) { + if (existsByKeyword(request.username())) { + throw new IllegalArgumentException("Tên đăng nhập đã tồn tại!"); + } + if (existsByKeyword(request.email())) { + throw new IllegalArgumentException("Email này đã được đăng ký!"); + } + String hashPassword = passwordEncoder.encode(request.password()); + User savedUser = RegisterRequestMapper.toEntity(request, hashPassword); + userRepository.save(savedUser); + } + + @Override + public UserResponse login(LoginRequest request) { + + Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + request.login(), + request.password())); + + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(authentication); + SecurityContextHolder.setContext(context); + + User user = findUser(authentication.getName()) + .orElseThrow(() -> new IllegalArgumentException( + "Tên đăng nhập hoặc mật khẩu không đúng.")); + return userResponseMapper.fromEntity(user); + } + + private Optional findUser(String keyword) { + return userRepository.findUserByUsernameOrEmail(keyword, keyword); + } + + private boolean existsByKeyword(String keyword) { + return userRepository.existsByUsernameOrEmail(keyword, keyword); + } +} diff --git a/src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java b/src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..12b9fbe17edc21f575a159126d96d97c623c0c32 --- /dev/null +++ b/src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java @@ -0,0 +1,43 @@ +package com.attendenceSystem.module.user.service.impl; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.attendenceSystem.module.user.dto.response.UserResponse; +import com.attendenceSystem.module.user.entity.User; +import com.attendenceSystem.module.user.mapper.response.UserResponseMapper; +import com.attendenceSystem.module.user.repository.UserRepository; +import com.attendenceSystem.module.user.service.UserService; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService { + private final UserRepository userRepository; + private final UserResponseMapper userResponseMapper; + + @Override + public UserResponse getById(Long id) { + return userResponseMapper.fromEntity(findById(id)); + } + + @Transactional + @Override + public void deleteUser(Long id) { + userRepository.delete(findById(id)); + } + + private User findById(Long id) { + return userRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Không tìm thấy người dùng với id: " + id)); + } + + @Override + public Page getAccounts(Pageable pageable) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getAccounts'"); + } +} diff --git a/src/main/java/com/attendenceSystem/security/ActiveUserFilter.java b/src/main/java/com/attendenceSystem/security/ActiveUserFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..7ebc9a32781d68aaf5d4dff9ee1593eaeaec8645 --- /dev/null +++ b/src/main/java/com/attendenceSystem/security/ActiveUserFilter.java @@ -0,0 +1,67 @@ +// package com.attendenceSystem.security; + +// import java.io.IOException; + +// import org.springframework.security.authentication.AnonymousAuthenticationToken; +// import org.springframework.security.core.Authentication; +// import org.springframework.security.core.context.SecurityContextHolder; +// import org.springframework.stereotype.Component; +// import org.springframework.web.filter.OncePerRequestFilter; + +// import com.attendenceSystem.constant.Routes; +// import com.attendenceSystem.entity.User; +// import com.attendenceSystem.repository.UserRepository; + +// import jakarta.servlet.FilterChain; +// import jakarta.servlet.ServletException; +// import jakarta.servlet.http.HttpServletRequest; +// import jakarta.servlet.http.HttpServletResponse; +// import jakarta.servlet.http.HttpSession; +// import lombok.RequiredArgsConstructor; + +// @Component +// @RequiredArgsConstructor +// public class ActiveUserFilter extends OncePerRequestFilter { + +// private final UserRepository userRepository; + +// @Override +// protected void doFilterInternal( +// HttpServletRequest request, +// HttpServletResponse response, +// FilterChain filterChain) +// throws ServletException, IOException { + +// Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + +// if (authentication != null +// && authentication.isAuthenticated() +// && !(authentication instanceof AnonymousAuthenticationToken)) { + +// String username = authentication.getName(); + +// User user = userRepository.findByUsername(username).orElse(null); + +// if (user == null || !user.isActive()) { +// SecurityContextHolder.clearContext(); +// HttpSession session = request.getSession(false); +// if (session != null) { +// session.invalidate(); +// } +// response.sendRedirect(Routes.USER + "/login"); +// return; +// } +// } + +// filterChain.doFilter(request, response); +// } + +// @Override +// protected boolean shouldNotFilter(HttpServletRequest request) { +// String uri = request.getRequestURI(); + +// return uri.startsWith("/css/") +// || uri.startsWith("/js/") +// || uri.startsWith("/images/"); +// } +// } \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/security/ForceChangePasswordInterceptor.java b/src/main/java/com/attendenceSystem/security/ForceChangePasswordInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3162ca01a03ba14a8713e31835410af9a2e8eadc --- /dev/null +++ b/src/main/java/com/attendenceSystem/security/ForceChangePasswordInterceptor.java @@ -0,0 +1,41 @@ +// package com.attendenceSystem.security; + +// import org.springframework.stereotype.Component; +// import org.springframework.web.servlet.HandlerInterceptor; + +// import com.attendenceSystem.constant.Routes; +// import com.attendenceSystem.entity.User; +// import com.attendenceSystem.repository.UserRepository; +// import com.attendenceSystem.util.SecurityUtil; + +// import jakarta.servlet.http.HttpServletRequest; +// import jakarta.servlet.http.HttpServletResponse; +// import lombok.RequiredArgsConstructor; + +// @Component +// @RequiredArgsConstructor +// public class ForceChangePasswordInterceptor implements HandlerInterceptor { +// private final UserRepository userRepository; + +// @Override +// public boolean preHandle( +// HttpServletRequest request, +// HttpServletResponse response, +// Object handler) +// throws Exception { +// String username = SecurityUtil.getCurrentUserName(); +// if (username == null) { +// return true; +// } +// User user = userRepository.findUserByUsername(username).orElse(null); +// if (user == null) { +// return true; +// } +// String uri = request.getRequestURI(); +// if (user.isMustChangePassword() && !uri.startsWith(Routes.USER + "/change-password")) { +// response.sendRedirect(Routes.USER + "/change-password"); +// return false; +// } +// return true; +// } +// } \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/security/SecurityConfig.java b/src/main/java/com/attendenceSystem/security/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..6dc19e9ef43be56df1fcc46855348b4290a20f57 --- /dev/null +++ b/src/main/java/com/attendenceSystem/security/SecurityConfig.java @@ -0,0 +1,60 @@ +package com.attendenceSystem.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +// import com.attendenceSystem.constant.Routes; +// import com.attendenceSystem.entity.enums.Role; + +import lombok.RequiredArgsConstructor; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + // private final ActiveUserFilter activeUserFilter; + private final AuthenticationConfiguration authenticationConfiguration; + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll()) + .csrf(csrf -> csrf.disable()); + return http.build(); + } + + @Bean + public AuthenticationManager authenticationManager() throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + // Chỉ dùng để test admin + // @Bean + // public UserDetailsService userDetailsService( + // PasswordEncoder passwordEncoder) { + + // UserDetails admin = User.builder() + // .username("admin") + // .password(passwordEncoder.encode("123456")) + // .roles(Role.ADMIN.name()) + // .build(); + + // return new InMemoryUserDetailsManager(admin); + // } +} diff --git a/src/main/java/com/attendenceSystem/user/dto/request/LoginRequest.java b/src/main/java/com/attendenceSystem/user/dto/request/LoginRequest.java deleted file mode 100644 index 1aad262b0525e8d6c2ac5d05ee184e9d3671d3b2..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/dto/request/LoginRequest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.attendenceSystem.user.dto.request; - - -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; -import lombok.Data; - -@Data -public class LoginRequest { - @NotBlank(message = "Email không được để trống") - @Size(max = 255, message = "Email không được vượt quá 255 ký tự") - @Email(message = "Email không đúng định dạng") - private String email; - @NotBlank(message = "Mật khẩu không được để trống") - @Size(min = 8, message = "Mật khẩu phải chứa ít nhất 8 kí tự") - private String password; - - -} diff --git a/src/main/java/com/attendenceSystem/user/dto/request/RegisterRequest.java b/src/main/java/com/attendenceSystem/user/dto/request/RegisterRequest.java deleted file mode 100644 index 1a6dfdab259afd24020413e93630c07527ef1959..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/dto/request/RegisterRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.attendenceSystem.user.dto.request; - -import com.attendenceSystem.annotation.PasswordMatch; -import com.attendenceSystem.user.entity.User; -import com.fasterxml.jackson.annotation.JsonProperty; - -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; -import lombok.Data; -import lombok.NonNull; - -@Data -@PasswordMatch -public class RegisterRequest { - @NotBlank(message = "Email không được để trống") - @Size(max = 255, message = "Email không được vượt quá 255 ký tự") - @Email(message = "Email không đúng định dạng") - private String email; - @NotBlank(message = "Mật khẩu không được để trống") - @Size(min = 8, message = "Mật khẩu phải chứa ít nhất 8 kí tự") - private String password; - @NotBlank(message = "Mật khẩu xác nhận không được để trống") - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - private String rePassword; - @NotBlank(message = "Họ tên không được để trống") - @Size(max = 255, message = "Họ tên không được vượt quá 255 ký tự") - private String fullName; - - @NonNull - public User toEntity(String hashPassword) { - return User.builder() - .email(this.email) - .password(hashPassword) - .fullName(this.fullName) - .build(); - } -} diff --git a/src/main/java/com/attendenceSystem/user/dto/response/UserResponse.java b/src/main/java/com/attendenceSystem/user/dto/response/UserResponse.java deleted file mode 100644 index c8e344bf64ccb12daaeb30238ad85654149872ce..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/dto/response/UserResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.attendenceSystem.user.dto.response; - -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class UserResponse { - private Long id; - private String email; - private String fullName; - private String avatar; - private String status; - private String createdAt; - private String updatedAt; - private Boolean deleted; -} diff --git a/src/main/java/com/attendenceSystem/user/entity/User.java b/src/main/java/com/attendenceSystem/user/entity/User.java deleted file mode 100644 index f05aa98da3b0e66beb87f3ae2e2148e3b67989f4..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/entity/User.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.attendenceSystem.user.entity; - -import java.time.Instant; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Builder -@Entity -@Table(name = "users") -public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private Long id; - @Column(name = "email") - private String email; - @Column(name = "password") - private String password; - @Column(name = "full_name") - private String fullName; - @Column(name = "avatar") - private String avatar; - @Column(name = "role") - private String role; - @Column(name = "status") - private String status; - @Column(name = "created_at") - private Instant createdAt; - @Column(name = "updated_at") - private Instant updatedAt; - @Column(name = "deleted") - private Boolean deleted; -} diff --git a/src/main/java/com/attendenceSystem/user/entity/converter/RoleConverter.java b/src/main/java/com/attendenceSystem/user/entity/converter/RoleConverter.java deleted file mode 100644 index ce327a4e7ba2c7b3a0200b281d9c3c3acbbb78c9..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/entity/converter/RoleConverter.java +++ /dev/null @@ -1,15 +0,0 @@ -// package com.attendenceSystem.user.entity.converter; - -// @Converter(autoApply = true) -// public class RoleConverter implements AttributeConverter { - -// @Override -// public Integer convertToDatabaseColumn(Role role) { -// return role == null ? null : role.getValue(); -// } - -// @Override -// public Role convertToEntityAttribute(Integer dbData) { -// return dbData == null ? null : Role.fromValue(dbData); -// } -// } \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/user/mapper/request/LoginRequestMapper.java b/src/main/java/com/attendenceSystem/user/mapper/request/LoginRequestMapper.java deleted file mode 100644 index 9607fe2d62f0471536b8752a9350fea1a76410ac..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/mapper/request/LoginRequestMapper.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.attendenceSystem.user.mapper.request; - -public class LoginRequestMapper { - -} diff --git a/src/main/java/com/attendenceSystem/user/mapper/request/RegisterRequestMapper.java b/src/main/java/com/attendenceSystem/user/mapper/request/RegisterRequestMapper.java deleted file mode 100644 index f01c998a39be64ccefd6d07006207497fa3a2d0e..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/mapper/request/RegisterRequestMapper.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.attendenceSystem.user.mapper.request; - -public class RegisterRequestMapper { - -} diff --git a/src/main/java/com/attendenceSystem/user/mapper/response/UserResponseMapper.java b/src/main/java/com/attendenceSystem/user/mapper/response/UserResponseMapper.java deleted file mode 100644 index bd71a690e8b3cb3b2d38714dc405b64d7eb3c3ee..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/mapper/response/UserResponseMapper.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.attendenceSystem.user.mapper.response; - -import java.time.ZoneId; - -import org.springframework.stereotype.Component; - -import com.attendenceSystem.user.dto.response.UserResponse; -import com.attendenceSystem.user.entity.User; -import com.attendenceSystem.util.TimeUtil; - -import lombok.RequiredArgsConstructor; - -@Component -@RequiredArgsConstructor -public class UserResponseMapper { - - private final ZoneId applicationZoneId; - - public UserResponse toResponse(User user) { - - return UserResponse.builder() - .id(user.getId()) - .email(user.getEmail()) - .fullName(user.getFullName()) - .avatar(user.getAvatar()) - .status(user.getStatus()) - .createdAt( - TimeUtil.formatInstant( - user.getCreatedAt(), - applicationZoneId)) - .updatedAt( - TimeUtil.formatInstant( - user.getUpdatedAt(), - applicationZoneId)) - .deleted(user.getDeleted()) - .build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/attendenceSystem/user/repository/UserRepository.java b/src/main/java/com/attendenceSystem/user/repository/UserRepository.java deleted file mode 100644 index 6e9ac3b97703ef373b9e01e92e1e425278b1c84b..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/repository/UserRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.attendenceSystem.user.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import com.attendenceSystem.user.entity.User; - -@Repository -public interface UserRepository extends JpaRepository { - -} diff --git a/src/main/java/com/attendenceSystem/user/service/UserService.java b/src/main/java/com/attendenceSystem/user/service/UserService.java deleted file mode 100644 index b590eb96b81727000e44deaaca7aebdf66ac1b6b..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/service/UserService.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.attendenceSystem.user.service; - -import com.attendenceSystem.user.dto.request.LoginRequest; -import com.attendenceSystem.user.dto.request.RegisterRequest; -import com.attendenceSystem.user.dto.response.UserResponse; - -public interface UserService { - UserResponse login(LoginRequest request); - - void register(RegisterRequest request); - - void deleteUser(Long id); - - UserResponse findAccountById(Long id); -} diff --git a/src/main/java/com/attendenceSystem/user/service/impl/UserServiceImpl.java b/src/main/java/com/attendenceSystem/user/service/impl/UserServiceImpl.java deleted file mode 100644 index f620c26cf7001b6b7740fc3d77a8b4510a9c2e68..0000000000000000000000000000000000000000 --- a/src/main/java/com/attendenceSystem/user/service/impl/UserServiceImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.attendenceSystem.user.service.impl; - -import java.time.Instant; -import java.time.ZoneId; - -import com.attendenceSystem.user.dto.request.LoginRequest; -import com.attendenceSystem.user.dto.request.RegisterRequest; -import com.attendenceSystem.user.dto.response.UserResponse; -import com.attendenceSystem.user.entity.User; -import com.attendenceSystem.user.repository.UserRepository; -import com.attendenceSystem.user.service.UserService; -import com.attendenceSystem.util.TimeUtil; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class UserServiceImpl implements UserService { - private final UserRepository userRepository; - private final ZoneId applicationZoneId; - // private final PasswordEncoder passwordEncoder; - - @Override - public UserResponse login(LoginRequest request) { - // Tìm tài khoản thông qua email từ request, không có báo lỗi. - - // Kiểm tra mật khẩu từ request có chính xác không. Sai báo lỗi - - // Trả UserResponse - return null; - } - - // @Transactional - @Override - public void register(RegisterRequest request) { - // Kiểm tra email - - // encode password - - // Lưu User - } - - @Override - public void deleteUser(Long id) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'deleteUser'"); - } - - @Override - public UserResponse findAccountById(Long id) { - // Kiểm tra id == null - - // Tìm kiếm user thông qua id - - // Trả về UserResponse. - return null; - } - - private String getCurrentTime() { - - return TimeUtil.formatInstant( - Instant.now(), - applicationZoneId); - } - -} diff --git a/src/main/java/com/attendenceSystem/validator/PasswordMatchValidator.java b/src/main/java/com/attendenceSystem/validator/PasswordMatchValidator.java index 4832a5ad70dfbba24439f323fb7584d342c7becf..6c04b1f3b457eb7c568eedb7c628f911580aa39a 100644 --- a/src/main/java/com/attendenceSystem/validator/PasswordMatchValidator.java +++ b/src/main/java/com/attendenceSystem/validator/PasswordMatchValidator.java @@ -1,7 +1,7 @@ package com.attendenceSystem.validator; import com.attendenceSystem.annotation.PasswordMatch; -import com.attendenceSystem.user.dto.request.RegisterRequest; +import com.attendenceSystem.module.user.dto.request.RegisterRequest; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; @@ -13,13 +13,13 @@ public class PasswordMatchValidator public boolean isValid(RegisterRequest request, ConstraintValidatorContext context) { - if (request.getPassword() == null - || request.getRePassword() == null) { + if (request.password() == null + || request.rePassword() == null) { return true; } - boolean valid = request.getPassword() - .equals(request.getRePassword()); + boolean valid = request.password() + .equals(request.rePassword()); if (!valid) { context.disableDefaultConstraintViolation(); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0465d99e510b704df87cc1697b6eb35b4c836f7e..eaef8c7219b0223ccc61c5363776f0d5139ef1a6 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,14 +23,14 @@ spring.devtools.livereload.enabled=true server.servlet.jsp.init-parameters.development=true # DataSource Configuration for SQL Server -# spring.datasource.url=jdbc:mariadb://localhost:3306/MOONBLIGHT -# spring.datasource.username=root -# spring.datasource.password=QQQewqwqa401! -# spring.datasource.driver-class-name=org.mariadb.jdbc.Driver - -spring.datasource.url=jdbc:mysql://localhost:3306/game_promo_web +spring.datasource.url=jdbc:mariadb://localhost:3306/ATTENDANCE spring.datasource.username=root -spring.datasource.password=annguyenthanh2k5 +spring.datasource.password=QQQewqwqa401! +spring.datasource.driver-class-name=org.mariadb.jdbc.Driver + +# spring.datasource.url=jdbc:mysql://localhost:3306/game_promo_web +# spring.datasource.username=root +# spring.datasource.password=annguyenthanh2k5 # SMPT EMAIL @@ -40,7 +40,18 @@ spring.datasource.password=annguyenthanh2k5 # spring.mail.password=lzzxdgzmirxdwqdv # JPA configuration +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true + + +# spring.mail.properties.mail.smtp.auth=true +# spring.mail.properties.mail.smtp.starttls.enable=true +# Catch exception +# server.error.include-message=never +# server.error.include-binding-errors=never +# server.error.include-stacktrace=never +# server.error.include-exception=false ->>>>>>> Stashed changes +app.timezone=Asia/Ho_Chi_Minh \ No newline at end of file diff --git a/src/main/resources/templates/cms/auths/login.html b/src/main/resources/templates/cms/auth/login.html similarity index 100% rename from src/main/resources/templates/cms/auths/login.html rename to src/main/resources/templates/cms/auth/login.html diff --git a/src/main/resources/templates/cms/auths/register.html b/src/main/resources/templates/cms/auth/register.html similarity index 100% rename from src/main/resources/templates/cms/auths/register.html rename to src/main/resources/templates/cms/auth/register.html diff --git a/src/main/resources/templates/cms/auths/verify-otp.html b/src/main/resources/templates/cms/auth/verify-otp.html similarity index 100% rename from src/main/resources/templates/cms/auths/verify-otp.html rename to src/main/resources/templates/cms/auth/verify-otp.html diff --git a/src/main/resources/templates/cms/documents/document-create.html b/src/main/resources/templates/cms/document/document-create.html similarity index 100% rename from src/main/resources/templates/cms/documents/document-create.html rename to src/main/resources/templates/cms/document/document-create.html diff --git a/src/main/resources/templates/cms/documents/document-detail.html b/src/main/resources/templates/cms/document/document-detail.html similarity index 100% rename from src/main/resources/templates/cms/documents/document-detail.html rename to src/main/resources/templates/cms/document/document-detail.html diff --git a/src/main/resources/templates/cms/documents/document-list.html b/src/main/resources/templates/cms/document/document-list.html similarity index 100% rename from src/main/resources/templates/cms/documents/document-list.html rename to src/main/resources/templates/cms/document/document-list.html diff --git a/src/main/resources/templates/cms/homaPage.jsp b/src/main/resources/templates/cms/homaPage.jsp deleted file mode 100644 index 789a6de1fcd26d45b86325ee7fb541c407c8c46d..0000000000000000000000000000000000000000 --- a/src/main/resources/templates/cms/homaPage.jsp +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - Dashboard - - - - - - - -
- -
- -
- - -
- -
- -
-
-
- SMART ATTENDANCE -
- -
- SYSTEM -
- -
- -

- Giải pháp điểm danh Face ID thông minh cho doanh nghiệp và cơ sở giáo dục. - Quản lý hiệu quả, chính xác và an toàn -

- - Bắt đầu ngay - - Xem Demo - -
- -
-
-
-
- -
5000+
-
Người dùng
-
-
- -
99.8%
-
Độ chính xác
-
-
- -
50+
-
Đơn vị
-
-
- -
24/7
-
Hoạt động
-
-
-
-
-
- - -
-
-
-

Tính năng nổi bật

-

Giải pháp toàn diện cho quản lý điểm danh

-
-
-
-
- -
-

Face Recognition

-

Nhận diện khuôn mặt chính xác với AI, chống - điểm danh hộ

-
-
-
- -
-

Analytics Dashboard

-

Thống kê realtime, biểu đồ trực quan, báo cáo - chi tiết

-
-
-
- -
-

Report Management

-

Quản lý báo cáo công việc hằng ngày và cuối - tuần

-
-
-
- -
-

Leave Management

-

Xin nghỉ phép, duyệt đơn, theo dõi lịch sử - nghỉ

-
-
-
-
- -
-
-
-
- - - - \ No newline at end of file diff --git a/src/main/resources/templates/cms/layouts/footer.html b/src/main/resources/templates/cms/layout/footer.html similarity index 100% rename from src/main/resources/templates/cms/layouts/footer.html rename to src/main/resources/templates/cms/layout/footer.html diff --git a/src/main/resources/templates/cms/layouts/header.html b/src/main/resources/templates/cms/layout/header.html similarity index 100% rename from src/main/resources/templates/cms/layouts/header.html rename to src/main/resources/templates/cms/layout/header.html diff --git a/src/main/resources/templates/cms/reports/report-day.html b/src/main/resources/templates/cms/report/report-day.html similarity index 100% rename from src/main/resources/templates/cms/reports/report-day.html rename to src/main/resources/templates/cms/report/report-day.html diff --git a/src/main/resources/templates/cms/reports/report-month.html b/src/main/resources/templates/cms/report/report-month.html similarity index 100% rename from src/main/resources/templates/cms/reports/report-month.html rename to src/main/resources/templates/cms/report/report-month.html diff --git a/src/main/resources/templates/cms/users/user-information.html b/src/main/resources/templates/cms/user/user-information.html similarity index 100% rename from src/main/resources/templates/cms/users/user-information.html rename to src/main/resources/templates/cms/user/user-information.html diff --git a/src/main/webapp/WEB-INF/views/attendances/homeAttendance.jsp b/src/main/webapp/WEB-INF/views/attendances/homeAttendance.jsp deleted file mode 100644 index 13708df6a3acf8cb7975b7cf52466e8885469045..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/attendances/homeAttendance.jsp +++ /dev/null @@ -1,143 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" %> - - - - - - - - Home Attendance - - - - - - -
-
- - -
-

Home Attendance 1

-
22/22/22
-
-
- -
- -
- 00:00:00 -
- - - - - -
-
- -
-
-

Lịch sử chấm công

- -
    - -
  • -
    - - Ngày 01/01/2024 - - - - Vào lúc 08:00 - - - - Ra lúc 17:00 - -
    -
  • - -
-
-
- -
- - - -
-
-
-
- -
- ✓ Nhận diện thành công -
- -
- -
-

- Hướng dẫn chấm công bằng nhận diện khuôn mặt: -

- -
    -
  1. Đứng cách camera khoảng 50cm - 1m
  2. -
  3. Nhìn thẳng vào camera
  4. -
  5. Giữ khuôn mặt trong khung hình
  6. -
  7. Hệ thống sẽ tự động nhận diện và ghi nhận
  8. -
-
- -
-
- -

- Thống kê hôm nay -

- -
-

- Đã chấm công -

- 42 -
- -
-

- Đi muộn -

- 8 -
- -
-

- Chưa chấm công -

- 12 -
- -
-

- Tổng nhân viên: 50 -

- -

- Giờ làm việc: 08:00 - 17:00 -

-
- -
- - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/auths/forgotPass.jsp b/src/main/webapp/WEB-INF/views/auths/forgotPass.jsp deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/main/webapp/WEB-INF/views/auths/login.jsp b/src/main/webapp/WEB-INF/views/auths/login.jsp deleted file mode 100644 index 34ff895c610229d101438d7a2d86967df33df2b6..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/auths/login.jsp +++ /dev/null @@ -1,98 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ include file="/WEB-INF/views/layouts/header.jsp" %> - -
-
-
-
- -
-

Đăng nhập

-

Truy cập vào hệ thống quản lý điểm danh

-
- -
-
- - -
- -
- -
- - -
-
- -
- - - -
-
- -
- Chưa có tài khoản? - - Đăng ký ngay - -
-
-
- - - -<%@ include file="/WEB-INF/views/layouts/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/auths/register.jsp b/src/main/webapp/WEB-INF/views/auths/register.jsp deleted file mode 100644 index 6470f68de49fe2db6c5b0ec6b326629feec672ae..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/auths/register.jsp +++ /dev/null @@ -1,81 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ include file="/WEB-INF/views/layouts/header.jsp" %> - -
-
-
-
- -
-

Đăng ký

-

Tạo tài khoản mới để sử dụng hệ thống

-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- - -
- -
- Đã có tài khoản? - - Đăng nhập - -
-
-
- -<%@ include file="/WEB-INF/views/layouts/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/dashBoard/employees/dashboard.jsp b/src/main/webapp/WEB-INF/views/dashBoard/employees/dashboard.jsp deleted file mode 100644 index 0bceea177213f5be318d38bcc9aacd9d15b8b858..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/dashBoard/employees/dashboard.jsp +++ /dev/null @@ -1,173 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - -<%-- Set page variables --%> - - - - - - -<%-- Define menu items --%> - -<%-- In real app, this would be populated from backend --%> - -<%@ include file="/WEB-INF/views/layout/header.jsp" %> - -
- <%@ include file="/WEB-INF/views/layout/sidebar.jsp" %> - -
-
-

Dashboard

- -
- -
-
- -
-

Xin chào, ${userName}!

-

Chúc bạn một ngày làm việc hiệu quả

-
- - -
-
-
-
-

Check In hôm nay

-

08:01 AM

-

+2 phút sớm

-
-
- -
-
-
- -
-
-
-

Giờ làm việc

-

7h 23m

-
-
- -
-
-
- -
-
-
-

Tỷ lệ chuyên cần

-

96%

-

+2% so với tháng trước

-
-
- -
-
-
- -
-
-
-

Yêu cầu chờ duyệt

-

2

-

1 nghỉ phép, 1 báo cáo

-
-
- -
-
-
-
- - -
-
-

- - Lịch trình hôm nay -

-
-
-
- -
-
-
Check In
-
08:01
-
-
Hoàn thành
-
-
-
- -
-
-
Nghỉ trưa
-
12:00
-
-
-
-
- -
-
-
Quay lại làm việc
-
13:00
-
-
-
-
- -
-
-
Check Out
-
17:30
-
-
- -
-
- -
-

- - Lịch làm việc -

-
-
-
- Có mặt -
-
-
- Đi muộn -
-
-
- Vắng mặt -
-
-
- Nghỉ phép -
-
-
-
-
-
-
-
- -<%@ include file="/WEB-INF/views/layouts/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/home.jsp b/src/main/webapp/WEB-INF/views/home.jsp deleted file mode 100644 index 66630f547f1ad5dd50a8e1cf0fbf7b620649d8cc..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/home.jsp +++ /dev/null @@ -1,130 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ include file="/WEB-INF/views/layouts/header.jsp" %> - -
- - - - -
-
-
-
-

- - SMART ATTENDANCE - -
- SYSTEM -

-

- Giải pháp điểm danh Face ID thông minh cho doanh nghiệp và cơ sở giáo dục. - Quản lý hiệu quả, chính xác và an toàn. -

- -
- -
-
-
-
- -
5000+
-
Người dùng
-
-
- -
99.8%
-
Độ chính xác
-
-
- -
50+
-
Đơn vị
-
-
- -
24/7
-
Hoạt động
-
-
-
-
-
-
-
- - -
-
-
-

Tính năng nổi bật

-

Giải pháp toàn diện cho quản lý điểm danh

-
-
-
-
- -
-

Face Recognition

-

Nhận diện khuôn mặt chính xác với AI, chống điểm danh hộ

-
-
-
- -
-

Analytics Dashboard

-

Thống kê realtime, biểu đồ trực quan, báo cáo chi tiết

-
-
-
- -
-

Report Management

-

Quản lý báo cáo công việc hằng ngày và cuối tuần

-
-
-
- -
-

Leave Management

-

Xin nghỉ phép, duyệt đơn, theo dõi lịch sử nghỉ

-
-
-
-
- - -
-
-

© 2026 Smart Attendance System. All rights reserved.

-
-
-
- -<%@ include file="/WEB-INF/views/layouts/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/homet.html b/src/main/webapp/WEB-INF/views/homet.html deleted file mode 100644 index 57ddcb4238801f70ef2dd13ae252b3cbe6517d18..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/homet.html +++ /dev/null @@ -1,475 +0,0 @@ - - - - - - - - - Danh sách thế giới - - - - -
- - -
- -
-
- -
-

Danh sách thế giới

- - - + Tạo thế giới mới - -
- -

-

- -

-

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDẢnhƯu tiênTagTiêu đềTrạng tháiHành động
- World Image - - - - - -
- -
- -
- - -
- -
- - -
- -
- -
- - - -
-
-
- - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/landing.jsp b/src/main/webapp/WEB-INF/views/landing.jsp deleted file mode 100644 index d8cf01a4febbb1cac0344183469a8e8f9acdddd7..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/landing.jsp +++ /dev/null @@ -1,130 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ include file="/WEB-INF/views/layout/header.jsp" %> - -
- - - - -
-
-
-
-

- - SMART ATTENDANCE - -
- SYSTEM -

-

- Giải pháp điểm danh Face ID thông minh cho doanh nghiệp và cơ sở giáo dục. - Quản lý hiệu quả, chính xác và an toàn. -

- -
- -
-
-
-
- -
5000+
-
Người dùng
-
-
- -
99.8%
-
Độ chính xác
-
-
- -
50+
-
Đơn vị
-
-
- -
24/7
-
Hoạt động
-
-
-
-
-
-
-
- - -
-
-
-

Tính năng nổi bật

-

Giải pháp toàn diện cho quản lý điểm danh

-
-
-
-
- -
-

Face Recognition

-

Nhận diện khuôn mặt chính xác với AI, chống điểm danh hộ

-
-
-
- -
-

Analytics Dashboard

-

Thống kê realtime, biểu đồ trực quan, báo cáo chi tiết

-
-
-
- -
-

Report Management

-

Quản lý báo cáo công việc hằng ngày và cuối tuần

-
-
-
- -
-

Leave Management

-

Xin nghỉ phép, duyệt đơn, theo dõi lịch sử nghỉ

-
-
-
-
- - -
-
-

© 2026 Smart Attendance System. All rights reserved.

-
-
-
- -<%@ include file="/WEB-INF/views/layout/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/layouts/base.jsp b/src/main/webapp/WEB-INF/views/layouts/base.jsp deleted file mode 100644 index 198e9da810b88d58564c6ee1fa2a12d0cbcaa7cb..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/layouts/base.jsp +++ /dev/null @@ -1,32 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - -<%@ include file="/WEB-INF/views/layouts/header.jsp" %> - -
- - <%@ include file="/WEB-INF/views/layouts/sidebar.jsp" %> - - -
- -
-
-

${pageTitle}

-
-
- -
-
- - -
- -
-
-
- -<%@ include file="/WEB-INF/views/layouts/footer.jsp" %> diff --git a/src/main/webapp/WEB-INF/views/layouts/footer.jsp b/src/main/webapp/WEB-INF/views/layouts/footer.jsp deleted file mode 100644 index 0f9296a74599bf31286737b97204dd2d96f09fbd..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/layouts/footer.jsp +++ /dev/null @@ -1,13 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> - - - - - - - - - - diff --git a/src/main/webapp/WEB-INF/views/layouts/header.jsp b/src/main/webapp/WEB-INF/views/layouts/header.jsp deleted file mode 100644 index 290f3b41916dd3eba0009243160eebc0e62c27ef..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/layouts/header.jsp +++ /dev/null @@ -1,40 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - - - - - ${pageTitle != null ? pageTitle : 'Smart Attendance System'} - - - - - - - - - - - - - - - - - - - diff --git a/src/main/webapp/WEB-INF/views/layouts/sidebar.jsp b/src/main/webapp/WEB-INF/views/layouts/sidebar.jsp deleted file mode 100644 index 12b0510755fffa8811b4436376293bef21c71ed3..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/layouts/sidebar.jsp +++ /dev/null @@ -1,46 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - diff --git a/src/main/webapp/WEB-INF/views/webapp1/face-attendance.jsp b/src/main/webapp/WEB-INF/views/webapp1/face-attendance.jsp deleted file mode 100644 index aed74e4fecc8dc2f1d2f51fccd594177e6327bd9..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/webapp1/face-attendance.jsp +++ /dev/null @@ -1,157 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> - - - - - - Điểm Danh Face ID - Face ID Attendance - - - - - -
- -
- -
-
- -
-

Lịch sử gần đây

-
-
-
-
-
-
Nguyễn Văn A
-
Check In: 07:58
-
-
-
-
-
-
!
-
-
Trần Thị B
-
Check In: 08:12 (Muộn)
-
-
-
-
-
-
-
-
Lê Văn C
-
Check In: 08:00
-
-
-
-
-
- - -
-

Quét khuôn mặt

-
-
👤
-
-
-
-
-
-
-

Vui lòng nhìn vào camera để điểm danh

-

Hệ thống đang quét...

-
- - -
-

Thống kê hôm nay

-
-
Đã điểm danh
-
42
-
-
-
Đi muộn
-
8
-
-
-
Chưa điểm danh
-
12
-
-
-
Tổng nhân viên
-
50
-
Tỷ lệ chuyên cần: 84%
-
-
-
-
- - - - diff --git a/src/main/webapp/WEB-INF/views/webapp1/index.jsp b/src/main/webapp/WEB-INF/views/webapp1/index.jsp deleted file mode 100644 index 0c9a326eccab9b7f8145c4bb101829888024484f..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/webapp1/index.jsp +++ /dev/null @@ -1,52 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> - - - - - - Hệ Thống Điểm Danh Face ID - - - - -
-
-

🎯 Hệ Thống Điểm Danh

-

Face ID Recognition

-

- Hệ thống điểm danh tự động bằng nhận diện khuôn mặt, - quản lý báo cáo và nghỉ phép thông minh -

- - - -
-

© 2026 Face ID Attendance System. All rights reserved.

-
-
-
- - - - diff --git a/src/main/webapp/WEB-INF/views/webapp1/login.jsp b/src/main/webapp/WEB-INF/views/webapp1/login.jsp deleted file mode 100644 index ceeb8019617201bdb632dc084b0911b9640c8c4b..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/webapp1/login.jsp +++ /dev/null @@ -1,98 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> - - - - - - - Đăng Nhập - Face ID Attendance - - - - - -
-
-
-

Đăng Nhập

-

Nhập thông tin để truy cập hệ thống

-
- -
- <% String error=request.getParameter("error"); if (error !=null) { %> -
- Sai email hoặc mật khẩu! -
- <% } %> - -
-
- - -
- -
- - -
- -
- -
- - -
-
- - -
-
- - - -
- -
-
-
- - - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/webapp1/register.jsp b/src/main/webapp/WEB-INF/views/webapp1/register.jsp deleted file mode 100644 index d6ebc2128d79818b3f30ddef9098f52cc04763ac..0000000000000000000000000000000000000000 --- a/src/main/webapp/WEB-INF/views/webapp1/register.jsp +++ /dev/null @@ -1,87 +0,0 @@ -<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> - - - - - - Đăng Ký - Face ID Attendance - - - - -
-
-
-

Đăng Ký Tài Khoản

-

Tạo tài khoản mới để sử dụng hệ thống

-
- -
-
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- Lưu ý: Tài khoản của bạn sẽ cần được Admin phê duyệt trước khi có thể đăng nhập. -
- - -
-
- - -
-
- - - -