QPAT commited on
Commit
3e5b7ae
·
1 Parent(s): c092dca

Fix login and register and role

Browse files
Files changed (42) hide show
  1. src/main/java/com/attendenceSystem/constant/Routes.java +8 -0
  2. src/main/java/com/attendenceSystem/frontroller/HomeController.java +6 -4
  3. src/main/java/com/attendenceSystem/module/dashboard/dto/response/AccountTypeDistributionResponse.java +7 -0
  4. src/main/java/com/attendenceSystem/module/dashboard/dto/response/AdminDashboardResponse.java +24 -2
  5. src/main/java/com/attendenceSystem/module/dashboard/mapper/response/DashboardResponseMapper.java +7 -2
  6. src/main/java/com/attendenceSystem/module/dashboard/service/impl/DashboardServiceImpl.java +18 -4
  7. src/main/java/com/attendenceSystem/module/user/controller/AuthController.java +4 -0
  8. src/main/java/com/attendenceSystem/module/user/controller/UserController.java +19 -0
  9. src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java +1 -1
  10. src/main/java/com/attendenceSystem/module/user/entity/User.java +4 -3
  11. src/main/java/com/attendenceSystem/module/user/entity/converter/StatusConverter.java +20 -0
  12. src/main/java/com/attendenceSystem/module/user/entity/enums/Department.java +2 -1
  13. src/main/java/com/attendenceSystem/module/user/entity/enums/Status.java +23 -0
  14. src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java +4 -0
  15. src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java +2 -2
  16. src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java +3 -2
  17. src/main/java/com/attendenceSystem/module/user/service/UserService.java +2 -0
  18. src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java +16 -4
  19. src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java +47 -5
  20. src/main/java/com/attendenceSystem/security/CustomUserDetails.java +10 -3
  21. src/main/resources/static/js/charts/AccountChart.js +12 -8
  22. src/main/resources/templates/cms/absent/absent-create.html +1 -1
  23. src/main/resources/templates/cms/absent/absent-history.html +1 -1
  24. src/main/resources/templates/cms/absent/absent-list.html +1 -1
  25. src/main/resources/templates/cms/account/account-list.html +22 -7
  26. src/main/resources/templates/cms/account/employee-list.html +1 -1
  27. src/main/resources/templates/cms/attendance/attendance-history.html +1 -1
  28. src/main/resources/templates/cms/attendance/attendance.html +1 -1
  29. src/main/resources/templates/cms/auth/login.html +4 -4
  30. src/main/resources/templates/cms/dashboard/dashboard-admin.html +19 -10
  31. src/main/resources/templates/cms/dashboard/dashboard-employee.html +1 -1
  32. src/main/resources/templates/cms/dashboard/dashboard-manager.html +1 -1
  33. src/main/resources/templates/cms/document/document-create.html +1 -1
  34. src/main/resources/templates/cms/document/document-list.html +2 -2
  35. src/main/resources/templates/cms/face-id/faceID-create.html +1 -1
  36. src/main/resources/templates/cms/face-id/faceID-list.html +1 -1
  37. src/main/resources/templates/cms/password/change-password.html +1 -1
  38. src/main/resources/templates/cms/report/report-day.html +1 -1
  39. src/main/resources/templates/cms/report/report-month.html +1 -1
  40. src/main/resources/templates/cms/sidebar/sidebar-admin.html +2 -2
  41. src/main/resources/templates/cms/sidebar/sidebar-role.html +11 -0
  42. src/main/resources/templates/cms/user/user-information.html +2 -2
src/main/java/com/attendenceSystem/constant/Routes.java CHANGED
@@ -8,6 +8,14 @@ public final class Routes {
8
  public static final String REDIRECT = "redirect:";
9
  public static final String API = "/api";
10
 
 
 
 
 
 
 
 
 
11
  public static final class Auth {
12
  public static final String ROOT = "/auth";
13
  public static final String LOGIN = "/login";
 
8
  public static final String REDIRECT = "redirect:";
9
  public static final String API = "/api";
10
 
11
+ public static final class Action {
12
+ public static final String CREATE = "/create";
13
+ public static final String UPDATE = "/update";
14
+ public static final String DELETE = "/delete";
15
+ public static final String DEACTIVATE = "/deactivate";
16
+ public static final String ACTIVATE = "/activate";
17
+ }
18
+
19
  public static final class Auth {
20
  public static final String ROOT = "/auth";
21
  public static final String LOGIN = "/login";
src/main/java/com/attendenceSystem/frontroller/HomeController.java CHANGED
@@ -3,6 +3,8 @@ package com.attendenceSystem.frontroller;
3
  import org.springframework.stereotype.Controller;
4
  import org.springframework.web.bind.annotation.GetMapping;
5
 
 
 
6
  @Controller
7
  public class HomeController {
8
 
@@ -40,15 +42,15 @@ public class HomeController {
40
  }
41
  @GetMapping("/dashboardAdmin")
42
  public String dashboardAdmin() {
43
- return "cms/dashboard/dashboard-admin";
44
  }
45
  @GetMapping("/dashboardEmployee")
46
  public String dashboardEmployee() {
47
- return "cms/dashboard/dashboard-employee";
48
  }
49
  @GetMapping("/dashboardManager")
50
  public String dashboardManager() {
51
- return "cms/dashboard/dashboard-manager";
52
  }
53
 
54
  @GetMapping("/login")
@@ -108,4 +110,4 @@ public class HomeController {
108
  public String forgotPassword() {
109
  return "cms/password/forgot-password";
110
  }
111
- }
 
3
  import org.springframework.stereotype.Controller;
4
  import org.springframework.web.bind.annotation.GetMapping;
5
 
6
+ import com.attendenceSystem.constant.Routes;
7
+
8
  @Controller
9
  public class HomeController {
10
 
 
42
  }
43
  @GetMapping("/dashboardAdmin")
44
  public String dashboardAdmin() {
45
+ return Routes.REDIRECT + Routes.Dashboard.ROOT + Routes.Dashboard.ADMIN;
46
  }
47
  @GetMapping("/dashboardEmployee")
48
  public String dashboardEmployee() {
49
+ return Routes.REDIRECT + Routes.Dashboard.ROOT + Routes.Dashboard.STUDENT;
50
  }
51
  @GetMapping("/dashboardManager")
52
  public String dashboardManager() {
53
+ return Routes.REDIRECT + Routes.Dashboard.ROOT + Routes.Dashboard.MANAGER;
54
  }
55
 
56
  @GetMapping("/login")
 
110
  public String forgotPassword() {
111
  return "cms/password/forgot-password";
112
  }
113
+ }
src/main/java/com/attendenceSystem/module/dashboard/dto/response/AccountTypeDistributionResponse.java ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ package com.attendenceSystem.module.dashboard.dto.response;
2
+
3
+ public record AccountTypeDistributionResponse(
4
+ String code,
5
+ String label,
6
+ long count) {
7
+ }
src/main/java/com/attendenceSystem/module/dashboard/dto/response/AdminDashboardResponse.java CHANGED
@@ -1,9 +1,31 @@
1
  package com.attendenceSystem.module.dashboard.dto.response;
2
 
 
 
 
3
  public record AdminDashboardResponse(
4
  long totalAccounts,
5
  long activeAccounts,
6
  long inactiveAccounts,
7
- long pendingAccounts
 
8
  ) {
9
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  package com.attendenceSystem.module.dashboard.dto.response;
2
 
3
+ import java.util.List;
4
+ import java.util.Locale;
5
+
6
  public record AdminDashboardResponse(
7
  long totalAccounts,
8
  long activeAccounts,
9
  long inactiveAccounts,
10
+ long pendingAccounts,
11
+ List<AccountTypeDistributionResponse> accountTypeDistribution
12
  ) {
13
+ public String activeRate() {
14
+ return formatRate(activeAccounts);
15
+ }
16
+
17
+ public String inactiveRate() {
18
+ return formatRate(inactiveAccounts);
19
+ }
20
+
21
+ public String pendingRate() {
22
+ return formatRate(pendingAccounts);
23
+ }
24
+
25
+ private String formatRate(long value) {
26
+ if (totalAccounts == 0) {
27
+ return "0.0%";
28
+ }
29
+ return String.format(Locale.ROOT, "%.1f%%", value * 100.0 / totalAccounts);
30
+ }
31
+ }
src/main/java/com/attendenceSystem/module/dashboard/mapper/response/DashboardResponseMapper.java CHANGED
@@ -1,8 +1,11 @@
1
  package com.attendenceSystem.module.dashboard.mapper.response;
2
 
 
 
3
  import org.springframework.data.domain.Page;
4
  import org.springframework.stereotype.Component;
5
 
 
6
  import com.attendenceSystem.module.attendance.dto.response.AttendanceResponse;
7
  import com.attendenceSystem.module.dashboard.dto.response.AdminDashboardResponse;
8
  import com.attendenceSystem.module.dashboard.dto.response.ManagerDashboardResponse;
@@ -12,8 +15,10 @@ import com.attendenceSystem.module.dashboard.dto.response.StudentDashboardRespon
12
  public class DashboardResponseMapper {
13
 
14
  public AdminDashboardResponse toAdminDashboardResponse(long totalAccounts, long activeAccounts,
15
- long inactiveAccounts, long pendingAccounts) {
16
- return new AdminDashboardResponse(totalAccounts, activeAccounts, inactiveAccounts, pendingAccounts);
 
 
17
  }
18
 
19
  public ManagerDashboardResponse toManagerDashboardResponse(long totalEmployees, long attendedEmployees,
 
1
  package com.attendenceSystem.module.dashboard.mapper.response;
2
 
3
+ import java.util.List;
4
+
5
  import org.springframework.data.domain.Page;
6
  import org.springframework.stereotype.Component;
7
 
8
+ import com.attendenceSystem.module.dashboard.dto.response.AccountTypeDistributionResponse;
9
  import com.attendenceSystem.module.attendance.dto.response.AttendanceResponse;
10
  import com.attendenceSystem.module.dashboard.dto.response.AdminDashboardResponse;
11
  import com.attendenceSystem.module.dashboard.dto.response.ManagerDashboardResponse;
 
15
  public class DashboardResponseMapper {
16
 
17
  public AdminDashboardResponse toAdminDashboardResponse(long totalAccounts, long activeAccounts,
18
+ long inactiveAccounts, long pendingAccounts,
19
+ List<AccountTypeDistributionResponse> accountTypeDistribution) {
20
+ return new AdminDashboardResponse(totalAccounts, activeAccounts, inactiveAccounts, pendingAccounts,
21
+ accountTypeDistribution);
22
  }
23
 
24
  public ManagerDashboardResponse toManagerDashboardResponse(long totalEmployees, long attendedEmployees,
src/main/java/com/attendenceSystem/module/dashboard/service/impl/DashboardServiceImpl.java CHANGED
@@ -1,6 +1,7 @@
1
  package com.attendenceSystem.module.dashboard.service.impl;
2
 
3
  import java.time.LocalDate;
 
4
 
5
  import org.springframework.data.domain.Page;
6
  import org.springframework.data.domain.PageRequest;
@@ -10,6 +11,7 @@ import com.attendenceSystem.module.attendance.dto.response.AttendanceResponse;
10
  import com.attendenceSystem.module.attendance.mapper.response.AttendanceResponseMapper;
11
  import com.attendenceSystem.module.attendance.repository.AttendanceRecordRepository;
12
  import com.attendenceSystem.module.attendance.util.AttendanceCalculator;
 
13
  import com.attendenceSystem.module.dashboard.dto.response.AdminDashboardResponse;
14
  import com.attendenceSystem.module.dashboard.dto.response.StudentDashboardResponse;
15
  import com.attendenceSystem.module.dashboard.dto.response.ManagerDashboardResponse;
@@ -20,6 +22,7 @@ import com.attendenceSystem.module.report.entity.enums.ReportStatus;
20
  import com.attendenceSystem.module.report.repository.ReportRepository;
21
  import com.attendenceSystem.module.user.entity.User;
22
  import com.attendenceSystem.module.user.entity.enums.Role;
 
23
  import com.attendenceSystem.module.user.repository.UserRepository;
24
  import com.attendenceSystem.util.SecurityUtil;
25
 
@@ -37,11 +40,22 @@ public class DashboardServiceImpl implements DashboardService {
37
  @Override
38
  public AdminDashboardResponse getAdminDashboard() {
39
  long totalAccounts = userRepository.count();
40
- long activeAccounts = userRepository.countByIsActiveTrue();
41
- long inactiveAccounts = userRepository.countByIsActiveFalse();
42
- long pendingAccounts = userRepository.countByMustChangePasswordTrue();
 
 
 
 
 
 
43
  return dashboardResponseMapper.toAdminDashboardResponse(totalAccounts, activeAccounts, inactiveAccounts,
44
- pendingAccounts);
 
 
 
 
 
45
  }
46
 
47
  @Override
 
1
  package com.attendenceSystem.module.dashboard.service.impl;
2
 
3
  import java.time.LocalDate;
4
+ import java.util.Locale;
5
 
6
  import org.springframework.data.domain.Page;
7
  import org.springframework.data.domain.PageRequest;
 
11
  import com.attendenceSystem.module.attendance.mapper.response.AttendanceResponseMapper;
12
  import com.attendenceSystem.module.attendance.repository.AttendanceRecordRepository;
13
  import com.attendenceSystem.module.attendance.util.AttendanceCalculator;
14
+ import com.attendenceSystem.module.dashboard.dto.response.AccountTypeDistributionResponse;
15
  import com.attendenceSystem.module.dashboard.dto.response.AdminDashboardResponse;
16
  import com.attendenceSystem.module.dashboard.dto.response.StudentDashboardResponse;
17
  import com.attendenceSystem.module.dashboard.dto.response.ManagerDashboardResponse;
 
22
  import com.attendenceSystem.module.report.repository.ReportRepository;
23
  import com.attendenceSystem.module.user.entity.User;
24
  import com.attendenceSystem.module.user.entity.enums.Role;
25
+ import com.attendenceSystem.module.user.entity.enums.Status;
26
  import com.attendenceSystem.module.user.repository.UserRepository;
27
  import com.attendenceSystem.util.SecurityUtil;
28
 
 
40
  @Override
41
  public AdminDashboardResponse getAdminDashboard() {
42
  long totalAccounts = userRepository.count();
43
+ long activeAccounts = userRepository.countByStatus(Status.ACTIVE);
44
+ long inactiveAccounts = userRepository.countByStatus(Status.INACTIVE);
45
+ long pendingAccounts = userRepository.countByStatus(Status.PENDING);
46
+ var accountTypeDistribution = java.util.Arrays.stream(Role.values())
47
+ .map(role -> new AccountTypeDistributionResponse(
48
+ role.name(),
49
+ roleLabel(role),
50
+ userRepository.countByRole(role)))
51
+ .toList();
52
  return dashboardResponseMapper.toAdminDashboardResponse(totalAccounts, activeAccounts, inactiveAccounts,
53
+ pendingAccounts, accountTypeDistribution);
54
+ }
55
+
56
+ private String roleLabel(Role role) {
57
+ String roleName = role.name().toLowerCase(Locale.ROOT);
58
+ return roleName.substring(0, 1).toUpperCase(Locale.ROOT) + roleName.substring(1);
59
  }
60
 
61
  @Override
src/main/java/com/attendenceSystem/module/user/controller/AuthController.java CHANGED
@@ -1,6 +1,7 @@
1
  package com.attendenceSystem.module.user.controller;
2
 
3
  import org.springframework.security.core.Authentication;
 
4
  import org.springframework.security.core.AuthenticationException;
5
  import org.springframework.security.core.context.SecurityContextHolder;
6
  import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
@@ -81,6 +82,9 @@ public class AuthController {
81
  case "STUDENT" -> Routes.REDIRECT + Routes.Dashboard.ROOT + Routes.Dashboard.STUDENT;
82
  default -> Routes.REDIRECT + Routes.Dashboard.ROOT;
83
  };
 
 
 
84
  } catch (AuthenticationException e) {
85
  model.addAttribute("errorMessage", "Tên đăng nhập hoặc mật khẩu không đúng.");
86
  return Views.Auth.LOGIN;
 
1
  package com.attendenceSystem.module.user.controller;
2
 
3
  import org.springframework.security.core.Authentication;
4
+ import org.springframework.security.authentication.DisabledException;
5
  import org.springframework.security.core.AuthenticationException;
6
  import org.springframework.security.core.context.SecurityContextHolder;
7
  import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
 
82
  case "STUDENT" -> Routes.REDIRECT + Routes.Dashboard.ROOT + Routes.Dashboard.STUDENT;
83
  default -> Routes.REDIRECT + Routes.Dashboard.ROOT;
84
  };
85
+ } catch (DisabledException e) {
86
+ model.addAttribute("errorMessage", e.getMessage());
87
+ return Views.Auth.LOGIN;
88
  } catch (AuthenticationException e) {
89
  model.addAttribute("errorMessage", "Tên đăng nhập hoặc mật khẩu không đúng.");
90
  return Views.Auth.LOGIN;
src/main/java/com/attendenceSystem/module/user/controller/UserController.java CHANGED
@@ -10,10 +10,14 @@ import com.attendenceSystem.constant.Routes;
10
  import com.attendenceSystem.constant.Views;
11
  import com.attendenceSystem.module.user.dto.response.UserResponse;
12
  import com.attendenceSystem.module.user.service.UserService;
 
13
 
14
  import lombok.RequiredArgsConstructor;
15
  import org.springframework.web.bind.annotation.GetMapping;
16
  import org.springframework.web.bind.annotation.PathVariable;
 
 
 
17
  @Controller
18
  @RequestMapping(Routes.User.ROOT)
19
  @RequiredArgsConstructor
@@ -23,6 +27,8 @@ public class UserController {
23
  @GetMapping
24
  public String toListPage(@PageableDefault(size = 10) Pageable pageable, Model model) {
25
  model.addAttribute("users", userService.getUsers(pageable));
 
 
26
  return Views.User.LIST;
27
  }
28
 
@@ -38,4 +44,17 @@ public class UserController {
38
  return Views.User.PROFILE;
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
 
10
  import com.attendenceSystem.constant.Views;
11
  import com.attendenceSystem.module.user.dto.response.UserResponse;
12
  import com.attendenceSystem.module.user.service.UserService;
13
+ import com.attendenceSystem.util.SecurityUtil;
14
 
15
  import lombok.RequiredArgsConstructor;
16
  import org.springframework.web.bind.annotation.GetMapping;
17
  import org.springframework.web.bind.annotation.PathVariable;
18
+ import org.springframework.web.bind.annotation.PostMapping;
19
+ import org.springframework.web.bind.annotation.RequestBody;
20
+
21
  @Controller
22
  @RequestMapping(Routes.User.ROOT)
23
  @RequiredArgsConstructor
 
27
  @GetMapping
28
  public String toListPage(@PageableDefault(size = 10) Pageable pageable, Model model) {
29
  model.addAttribute("users", userService.getUsers(pageable));
30
+ model.addAttribute("currentUsername", SecurityUtil.getCurrentUserName());
31
+ model.addAttribute("currentRole", SecurityUtil.getCurrentUserRole());
32
  return Views.User.LIST;
33
  }
34
 
 
44
  return Views.User.PROFILE;
45
  }
46
 
47
+ @PostMapping(Routes.Action.DEACTIVATE + "/{id}")
48
+ public String deactiveUser(@PathVariable("id") Long id) {
49
+ userService.deactiveUser(id);
50
+ return Routes.REDIRECT + Routes.User.ROOT;
51
+ }
52
+
53
+ @PostMapping(Routes.Action.ACTIVATE + "/{id}")
54
+ public String activateUser(@PathVariable("id") Long id) {
55
+ userService.activateUser(id);
56
+ return Routes.REDIRECT + Routes.User.ROOT;
57
+ }
58
+
59
+
60
  }
src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java CHANGED
@@ -8,7 +8,7 @@ public record UserResponse(
8
  String username,
9
  String email,
10
  String fullName,
11
- Boolean isActive,
12
  String role) {
13
 
14
  }
 
8
  String username,
9
  String email,
10
  String fullName,
11
+ String status,
12
  String role) {
13
 
14
  }
src/main/java/com/attendenceSystem/module/user/entity/User.java CHANGED
@@ -7,6 +7,7 @@ import org.hibernate.annotations.UpdateTimestamp;
7
 
8
  import com.attendenceSystem.module.user.entity.enums.Department;
9
  import com.attendenceSystem.module.user.entity.enums.Role;
 
10
 
11
  import jakarta.persistence.Column;
12
  import jakarta.persistence.Entity;
@@ -42,12 +43,12 @@ public class User {
42
  private String password;
43
  @Column(name = "role", nullable = false)
44
  private Role role;
45
- @Column(name = "is_active", nullable = false)
46
  @Builder.Default
47
- private boolean isActive = true;
48
  @Column(name = "full_name", nullable = false, length = 255)
49
  private String fullName;
50
- @Column(name = "department")
51
  private Department department;
52
  @CreationTimestamp
53
  @Column(name = "created_at", nullable = false, updatable = false)
 
7
 
8
  import com.attendenceSystem.module.user.entity.enums.Department;
9
  import com.attendenceSystem.module.user.entity.enums.Role;
10
+ import com.attendenceSystem.module.user.entity.enums.Status;
11
 
12
  import jakarta.persistence.Column;
13
  import jakarta.persistence.Entity;
 
43
  private String password;
44
  @Column(name = "role", nullable = false)
45
  private Role role;
46
+ @Column(name = "status", nullable = false)
47
  @Builder.Default
48
+ private Status status = Status.PENDING;
49
  @Column(name = "full_name", nullable = false, length = 255)
50
  private String fullName;
51
+ @Column(name = "department", nullable = false)
52
  private Department department;
53
  @CreationTimestamp
54
  @Column(name = "created_at", nullable = false, updatable = false)
src/main/java/com/attendenceSystem/module/user/entity/converter/StatusConverter.java ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.attendenceSystem.module.user.entity.converter;
2
+
3
+ import com.attendenceSystem.module.user.entity.enums.Status;
4
+
5
+ import jakarta.persistence.AttributeConverter;
6
+ import jakarta.persistence.Converter;
7
+
8
+ @Converter(autoApply = true)
9
+ public class StatusConverter implements AttributeConverter<Status, Integer> {
10
+
11
+ @Override
12
+ public Integer convertToDatabaseColumn(Status status) {
13
+ return status == null ? null : status.getValue();
14
+ }
15
+
16
+ @Override
17
+ public Status convertToEntityAttribute(Integer dbData) {
18
+ return dbData == null ? null : Status.fromValue(dbData);
19
+ }
20
+ }
src/main/java/com/attendenceSystem/module/user/entity/enums/Department.java CHANGED
@@ -6,7 +6,8 @@ import lombok.RequiredArgsConstructor;
6
  @Getter
7
  @RequiredArgsConstructor
8
  public enum Department {
9
- SE(0);
 
10
 
11
  public final int value;
12
 
 
6
  @Getter
7
  @RequiredArgsConstructor
8
  public enum Department {
9
+ UNASSIGNED(0),
10
+ SE(1);
11
 
12
  public final int value;
13
 
src/main/java/com/attendenceSystem/module/user/entity/enums/Status.java ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.attendenceSystem.module.user.entity.enums;
2
+
3
+ import lombok.Getter;
4
+ import lombok.RequiredArgsConstructor;
5
+
6
+ @Getter
7
+ @RequiredArgsConstructor
8
+ public enum Status {
9
+ ACTIVE(1),
10
+ INACTIVE(2),
11
+ PENDING(3);
12
+
13
+ public final int value;
14
+
15
+ public static Status fromValue(int value) {
16
+ for (Status status : Status.values()) {
17
+ if (status.value == value) {
18
+ return status;
19
+ }
20
+ }
21
+ throw new IllegalArgumentException("Không tìm thấy trạng thái: " + value);
22
+ }
23
+ }
src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java CHANGED
@@ -2,7 +2,9 @@ package com.attendenceSystem.module.user.mapper.request;
2
 
3
  import com.attendenceSystem.module.user.dto.request.RegisterRequest;
4
  import com.attendenceSystem.module.user.entity.User;
 
5
  import com.attendenceSystem.module.user.entity.enums.Role;
 
6
 
7
  import lombok.AccessLevel;
8
  import lombok.NoArgsConstructor;
@@ -15,7 +17,9 @@ public final class RegisterRequestMapper {
15
  .email(request.getEmail())
16
  .password(hashPassword)
17
  .fullName(request.getFullName())
 
18
  .role(Role.STUDENT)
 
19
  .mustChangePassword(false)
20
  .build();
21
  }
 
2
 
3
  import com.attendenceSystem.module.user.dto.request.RegisterRequest;
4
  import com.attendenceSystem.module.user.entity.User;
5
+ import com.attendenceSystem.module.user.entity.enums.Department;
6
  import com.attendenceSystem.module.user.entity.enums.Role;
7
+ import com.attendenceSystem.module.user.entity.enums.Status;
8
 
9
  import lombok.AccessLevel;
10
  import lombok.NoArgsConstructor;
 
17
  .email(request.getEmail())
18
  .password(hashPassword)
19
  .fullName(request.getFullName())
20
+ .department(Department.UNASSIGNED)
21
  .role(Role.STUDENT)
22
+ .status(Status.PENDING)
23
  .mustChangePassword(false)
24
  .build();
25
  }
src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java CHANGED
@@ -21,8 +21,8 @@ public class UserResponseMapper {
21
  .username(user.getUsername())
22
  .email(user.getEmail())
23
  .fullName(user.getFullName())
24
- .isActive(user.isActive())
25
  .role(user.getRole().name())
26
  .build();
27
  }
28
- }
 
21
  .username(user.getUsername())
22
  .email(user.getEmail())
23
  .fullName(user.getFullName())
24
+ .status(user.getStatus() == null ? null : user.getStatus().name())
25
  .role(user.getRole().name())
26
  .build();
27
  }
28
+ }
src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java CHANGED
@@ -9,6 +9,7 @@ import org.springframework.stereotype.Repository;
9
 
10
  import com.attendenceSystem.module.user.entity.User;
11
  import com.attendenceSystem.module.user.entity.enums.Role;
 
12
 
13
  @Repository
14
  public interface UserRepository extends JpaRepository<User, Long> {
@@ -19,9 +20,9 @@ public interface UserRepository extends JpaRepository<User, Long> {
19
  Optional<User> findUserByUsernameOrEmail(String username, String email);
20
  boolean existsByUsernameOrEmail(String username, String email);
21
  Page<User> findAllByOrderByIdAsc(Pageable pageable);
22
- long countByIsActiveTrue();
23
- long countByIsActiveFalse();
24
  long countByMustChangePasswordTrue();
 
25
  long countByRoleNot(Role role);
26
  Optional<User> findByUsername(String username);
27
  }
 
9
 
10
  import com.attendenceSystem.module.user.entity.User;
11
  import com.attendenceSystem.module.user.entity.enums.Role;
12
+ import com.attendenceSystem.module.user.entity.enums.Status;
13
 
14
  @Repository
15
  public interface UserRepository extends JpaRepository<User, Long> {
 
20
  Optional<User> findUserByUsernameOrEmail(String username, String email);
21
  boolean existsByUsernameOrEmail(String username, String email);
22
  Page<User> findAllByOrderByIdAsc(Pageable pageable);
23
+ long countByStatus(Status status);
 
24
  long countByMustChangePasswordTrue();
25
+ long countByRole(Role role);
26
  long countByRoleNot(Role role);
27
  Optional<User> findByUsername(String username);
28
  }
src/main/java/com/attendenceSystem/module/user/service/UserService.java CHANGED
@@ -9,4 +9,6 @@ public interface UserService {
9
  Page<UserResponse> getUsers(Pageable pageable);
10
  UserResponse getById(Long id);
11
  void deleteUser(Long id);
 
 
12
  }
 
9
  Page<UserResponse> getUsers(Pageable pageable);
10
  UserResponse getById(Long id);
11
  void deleteUser(Long id);
12
+ void deactiveUser(Long id);
13
+ void activateUser(Long id);
14
  }
src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java CHANGED
@@ -5,6 +5,7 @@ import com.attendenceSystem.module.user.mapper.response.UserResponseMapper;
5
  import java.util.Optional;
6
 
7
  import org.springframework.security.authentication.AuthenticationManager;
 
8
  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
9
  import org.springframework.security.core.Authentication;
10
  import org.springframework.security.core.context.SecurityContext;
@@ -17,6 +18,7 @@ import com.attendenceSystem.module.user.dto.request.LoginRequest;
17
  import com.attendenceSystem.module.user.dto.request.RegisterRequest;
18
  import com.attendenceSystem.module.user.dto.response.UserResponse;
19
  import com.attendenceSystem.module.user.entity.User;
 
20
  import com.attendenceSystem.module.user.repository.UserRepository;
21
  import com.attendenceSystem.module.user.service.AuthService;
22
 
@@ -49,10 +51,20 @@ public class AuthServiceImpl implements AuthService {
49
  @Override
50
  public UserResponse login(LoginRequest request) {
51
 
52
- Authentication authentication = authenticationManager.authenticate(
53
- new UsernamePasswordAuthenticationToken(
54
- request.getLogin(),
55
- request.getPassword()));
 
 
 
 
 
 
 
 
 
 
56
 
57
  SecurityContext context = SecurityContextHolder.createEmptyContext();
58
  context.setAuthentication(authentication);
 
5
  import java.util.Optional;
6
 
7
  import org.springframework.security.authentication.AuthenticationManager;
8
+ import org.springframework.security.authentication.DisabledException;
9
  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
10
  import org.springframework.security.core.Authentication;
11
  import org.springframework.security.core.context.SecurityContext;
 
18
  import com.attendenceSystem.module.user.dto.request.RegisterRequest;
19
  import com.attendenceSystem.module.user.dto.response.UserResponse;
20
  import com.attendenceSystem.module.user.entity.User;
21
+ import com.attendenceSystem.module.user.entity.enums.Status;
22
  import com.attendenceSystem.module.user.repository.UserRepository;
23
  import com.attendenceSystem.module.user.service.AuthService;
24
 
 
51
  @Override
52
  public UserResponse login(LoginRequest request) {
53
 
54
+ Authentication authentication;
55
+ try {
56
+ authentication = authenticationManager.authenticate(
57
+ new UsernamePasswordAuthenticationToken(
58
+ request.getLogin(),
59
+ request.getPassword()));
60
+ } catch (DisabledException e) {
61
+ User user = findUser(request.getLogin())
62
+ .orElseThrow(() -> new DisabledException("Tên đăng nhập hoặc mật khẩu không đúng.", e));
63
+ if (user.getStatus() == Status.PENDING) {
64
+ throw new DisabledException("Tài khoản đang chờ duyệt", e);
65
+ }
66
+ throw new DisabledException("Tài khoản đã bị khóa", e);
67
+ }
68
 
69
  SecurityContext context = SecurityContextHolder.createEmptyContext();
70
  context.setAuthentication(authentication);
src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java CHANGED
@@ -7,9 +7,12 @@ import org.springframework.transaction.annotation.Transactional;
7
 
8
  import com.attendenceSystem.module.user.dto.response.UserResponse;
9
  import com.attendenceSystem.module.user.entity.User;
 
 
10
  import com.attendenceSystem.module.user.mapper.response.UserResponseMapper;
11
  import com.attendenceSystem.module.user.repository.UserRepository;
12
  import com.attendenceSystem.module.user.service.UserService;
 
13
 
14
  import lombok.RequiredArgsConstructor;
15
 
@@ -27,7 +30,50 @@ public class UserServiceImpl implements UserService {
27
  @Transactional
28
  @Override
29
  public void deleteUser(Long id) {
30
- userRepository.delete(findById(id));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
  private User findById(Long id) {
@@ -35,8 +81,4 @@ public class UserServiceImpl implements UserService {
35
  .orElseThrow(() -> new IllegalArgumentException("Không tìm thấy người dùng với id: " + id));
36
  }
37
 
38
- @Override
39
- public Page<UserResponse> getUsers(Pageable pageable) {
40
- return userRepository.findAll(pageable).map(userResponseMapper::fromEntity);
41
- }
42
  }
 
7
 
8
  import com.attendenceSystem.module.user.dto.response.UserResponse;
9
  import com.attendenceSystem.module.user.entity.User;
10
+ import com.attendenceSystem.module.user.entity.enums.Role;
11
+ import com.attendenceSystem.module.user.entity.enums.Status;
12
  import com.attendenceSystem.module.user.mapper.response.UserResponseMapper;
13
  import com.attendenceSystem.module.user.repository.UserRepository;
14
  import com.attendenceSystem.module.user.service.UserService;
15
+ import com.attendenceSystem.util.SecurityUtil;
16
 
17
  import lombok.RequiredArgsConstructor;
18
 
 
30
  @Transactional
31
  @Override
32
  public void deleteUser(Long id) {
33
+ User user = findById(id);
34
+ validateAdminAction(user);
35
+ userRepository.delete(user);
36
+ }
37
+
38
+ @Override
39
+ public Page<UserResponse> getUsers(Pageable pageable) {
40
+ return userRepository.findAll(pageable).map(userResponseMapper::fromEntity);
41
+ }
42
+
43
+ @Transactional
44
+ @Override
45
+ public void deactiveUser(Long id) {
46
+ User user = findById(id);
47
+ validateAdminAction(user);
48
+ if(user.getStatus() == Status.INACTIVE){
49
+ throw new IllegalStateException("Tài khoản đã bị khóa");
50
+ }
51
+ user.setStatus(Status.INACTIVE);
52
+ }
53
+
54
+ @Transactional
55
+ @Override
56
+ public void activateUser(Long id) {
57
+ User user = findById(id);
58
+ validateAdminAction(user);
59
+ if(user.getStatus() == Status.ACTIVE){
60
+ throw new IllegalStateException("Tài khoản chưa bị khóa");
61
+ }
62
+ user.setStatus(Status.ACTIVE);
63
+ }
64
+
65
+ private void validateAdminAction(User targetUser) {
66
+ String currentUsername = SecurityUtil.getCurrentUserName();
67
+ Role currentRole = SecurityUtil.getCurrentUserRole();
68
+ if (currentUsername == null || currentRole == null) {
69
+ throw new IllegalStateException("Không xác định được tài khoản hiện tại");
70
+ }
71
+ if (targetUser.getUsername().equals(currentUsername)) {
72
+ throw new IllegalStateException("Admin không thể thay đổi tài khoản của chính mình");
73
+ }
74
+ if (currentRole == Role.ADMIN && targetUser.getRole() == Role.ADMIN) {
75
+ throw new IllegalStateException("Admin không thể tác động tài khoản admin khác");
76
+ }
77
  }
78
 
79
  private User findById(Long id) {
 
81
  .orElseThrow(() -> new IllegalArgumentException("Không tìm thấy người dùng với id: " + id));
82
  }
83
 
 
 
 
 
84
  }
src/main/java/com/attendenceSystem/security/CustomUserDetails.java CHANGED
@@ -8,7 +8,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
8
  import org.springframework.security.core.userdetails.UserDetails;
9
 
10
  import com.attendenceSystem.module.user.entity.User;
11
- import com.attendenceSystem.module.user.entity.enums.Department;
12
 
13
  import lombok.Getter;
14
  import lombok.RequiredArgsConstructor;
@@ -24,6 +24,7 @@ public class CustomUserDetails implements UserDetails {
24
  private final String phone;
25
  private final String department;
26
  private final String role;
 
27
 
28
  public static CustomUserDetails fromUser(User user) {
29
  return new CustomUserDetails(
@@ -33,12 +34,18 @@ public class CustomUserDetails implements UserDetails {
33
  user.getFullName(),
34
  user.getEmail(),
35
  user.getPhone(),
36
- user.getDepartment().name(),
37
- user.getRole().name());
 
38
  }
39
 
40
  @Override
41
  public Collection<? extends GrantedAuthority> getAuthorities() {
42
  return List.of(new SimpleGrantedAuthority("ROLE_"+role));
43
  }
 
 
 
 
 
44
  }
 
8
  import org.springframework.security.core.userdetails.UserDetails;
9
 
10
  import com.attendenceSystem.module.user.entity.User;
11
+ import com.attendenceSystem.module.user.entity.enums.Status;
12
 
13
  import lombok.Getter;
14
  import lombok.RequiredArgsConstructor;
 
24
  private final String phone;
25
  private final String department;
26
  private final String role;
27
+ private final Status status;
28
 
29
  public static CustomUserDetails fromUser(User user) {
30
  return new CustomUserDetails(
 
34
  user.getFullName(),
35
  user.getEmail(),
36
  user.getPhone(),
37
+ user.getDepartment() == null ? null : user.getDepartment().name(),
38
+ user.getRole().name(),
39
+ user.getStatus());
40
  }
41
 
42
  @Override
43
  public Collection<? extends GrantedAuthority> getAuthorities() {
44
  return List.of(new SimpleGrantedAuthority("ROLE_"+role));
45
  }
46
+
47
+ @Override
48
+ public boolean isEnabled() {
49
+ return status == Status.ACTIVE;
50
+ }
51
  }
src/main/resources/static/js/charts/AccountChart.js CHANGED
@@ -1,21 +1,25 @@
1
  document.addEventListener("DOMContentLoaded", function () {
2
 
3
  const ctx = document.getElementById("accountTypeChart");
 
 
 
4
 
5
  new Chart(ctx, {
6
  type: "doughnut",
7
  data: {
8
- labels: [
9
- "Quản trị viên",
10
- "Giảng viên",
11
- "Sinh viên"
12
- ],
13
  datasets: [{
14
- data: [5, 40, 320],
15
  backgroundColor: [
16
  "#ef4444",
17
  "#3b82f6",
18
- "#10b981"
 
 
 
 
 
19
  ],
20
  borderWidth: 2,
21
  borderColor: "#ffffff"
@@ -45,4 +49,4 @@ document.addEventListener("DOMContentLoaded", function () {
45
  }
46
  });
47
 
48
- });
 
1
  document.addEventListener("DOMContentLoaded", function () {
2
 
3
  const ctx = document.getElementById("accountTypeChart");
4
+ const chartData = window.accountTypeChartData || {};
5
+ const labels = chartData.labels || [];
6
+ const values = chartData.values || [];
7
 
8
  new Chart(ctx, {
9
  type: "doughnut",
10
  data: {
11
+ labels: labels,
 
 
 
 
12
  datasets: [{
13
+ data: values,
14
  backgroundColor: [
15
  "#ef4444",
16
  "#3b82f6",
17
+ "#10b981",
18
+ "#f59e0b",
19
+ "#8b5cf6",
20
+ "#06b6d4",
21
+ "#f97316",
22
+ "#64748b"
23
  ],
24
  borderWidth: 2,
25
  borderColor: "#ffffff"
 
49
  }
50
  });
51
 
52
+ });
src/main/resources/templates/cms/absent/absent-create.html CHANGED
@@ -16,7 +16,7 @@
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
 
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
src/main/resources/templates/cms/absent/absent-history.html CHANGED
@@ -17,7 +17,7 @@
17
  <div class="layout">
18
 
19
  <!-- SIDEBAR -->
20
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
21
 
22
  <!-- CONTENT -->
23
  <div class="container-layout">
 
17
  <div class="layout">
18
 
19
  <!-- SIDEBAR -->
20
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
21
 
22
  <!-- CONTENT -->
23
  <div class="container-layout">
src/main/resources/templates/cms/absent/absent-list.html CHANGED
@@ -15,7 +15,7 @@
15
  <div class="layout">
16
 
17
  <!-- SIDEBAR -->
18
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
19
 
20
  <!-- CONTENT -->
21
  <div class="container-layout">
 
15
  <div class="layout">
16
 
17
  <!-- SIDEBAR -->
18
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
19
 
20
  <!-- CONTENT -->
21
  <div class="container-layout">
src/main/resources/templates/cms/account/account-list.html CHANGED
@@ -12,7 +12,7 @@
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
- <div th:replace="~{cms/sidebar/sidebar-admin :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
@@ -56,12 +56,27 @@
56
  </div>
57
  </td>
58
  <td th:text="${users.email()}">nguyenvana@company.com</td>
59
- <td ><span th:text="${users.role()}" class="role">Nhân viên</span></td>
60
- <td><span th:text="${users.isActive()} == true?'Hoạt động':'Ngừng hoạt động'" class="status active">Hoạt động</span></td>
 
 
 
61
  <td>
62
- <div class="actions">
63
- <button class="icon-btn btn-role">Đổi quyền</button>
64
- <button class="icon-btn lock">🔒</button>
 
 
 
 
 
 
 
 
 
 
 
 
65
  </div>
66
  </td>
67
  </tr>
@@ -134,4 +149,4 @@
134
 
135
  </body>
136
 
137
- </html>
 
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
 
56
  </div>
57
  </td>
58
  <td th:text="${users.email()}">nguyenvana@company.com</td>
59
+ <td><span th:text="${users.role()}" class="role">Nhân viên</span></td>
60
+ <td><span
61
+ th:text="${users.status() == 'ACTIVE' ? 'Hoạt động' : (users.status() == 'PENDING' ? 'Chờ duyệt' : 'Bị khóa')}"
62
+ th:class="${'status ' + (users.status() == 'ACTIVE' ? 'active' : 'inactive')}">Hoạt động</span>
63
+ </td>
64
  <td>
65
+ <div class="actions"
66
+ th:with="canManage=${users.username() != currentUsername and users.role() != 'ADMIN'}">
67
+
68
+ <button class="icon-btn btn-role" th:if="${canManage}">Đổi quyền</button>
69
+ <div th:if="${canManage and users.status() == 'ACTIVE'}">
70
+ <form th:action="@{/user/deactivate/{id}(id=${users.id()})}" method="post">
71
+ <button class="icon-btn lock">🔒</button>
72
+ </form>
73
+ </div>
74
+ <div th:if="${canManage and users.status() != 'ACTIVE'}">
75
+ <form th:action="@{/user/activate/{id}(id=${users.id()})}" method="post">
76
+ <button class="icon-btn unlock">🔓</button>
77
+ </form>
78
+ </div>
79
+ <span th:unless="${canManage}" class="action-note">Không thể thao tác</span>
80
  </div>
81
  </td>
82
  </tr>
 
149
 
150
  </body>
151
 
152
+ </html>
src/main/resources/templates/cms/account/employee-list.html CHANGED
@@ -15,7 +15,7 @@
15
 
16
  <div class="layout">
17
 
18
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
 
15
 
16
  <div class="layout">
17
 
18
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
src/main/resources/templates/cms/attendance/attendance-history.html CHANGED
@@ -15,7 +15,7 @@
15
 
16
  <div class="layout">
17
 
18
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
 
15
 
16
  <div class="layout">
17
 
18
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
src/main/resources/templates/cms/attendance/attendance.html CHANGED
@@ -14,7 +14,7 @@
14
  <div class="bg-image"></div>
15
 
16
  <div class="layout">
17
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
18
 
19
 
20
 
 
14
  <div class="bg-image"></div>
15
 
16
  <div class="layout">
17
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
18
 
19
 
20
 
src/main/resources/templates/cms/auth/login.html CHANGED
@@ -72,9 +72,9 @@
72
  <button class="auth-btn" type="submit">Đăng nhập</button>
73
  </form>
74
  <br><br>
75
- <a class="auth-btn" href="/dashboardEmployee">Nhân Viên</a>
76
- <a class="auth-btn" href="/dashboardManager">Quản lý</a>
77
- <a class="auth-btn" href="/dashboardAdmin">Admin</a>
78
  <br>
79
  <hr style="margin: 1rem 0; opacity: 0.2" />
80
  <div class="other-option">
@@ -94,4 +94,4 @@
94
  <div th:replace="~{cms/layout/footer :: footer}"></div>
95
  </body>
96
 
97
- </html>
 
72
  <button class="auth-btn" type="submit">Đăng nhập</button>
73
  </form>
74
  <br><br>
75
+ <a class="auth-btn" href="/dashboard/student">Nhân Viên</a>
76
+ <a class="auth-btn" href="/dashboard/manager">Quản lý</a>
77
+ <a class="auth-btn" href="/dashboard/admin">Admin</a>
78
  <br>
79
  <hr style="margin: 1rem 0; opacity: 0.2" />
80
  <div class="other-option">
 
94
  <div th:replace="~{cms/layout/footer :: footer}"></div>
95
  </body>
96
 
97
+ </html>
src/main/resources/templates/cms/dashboard/dashboard-admin.html CHANGED
@@ -13,7 +13,7 @@
13
  <body>
14
  <div class="bg-image"></div>
15
  <div class="layout">
16
- <div th:replace="~{cms/sidebar/sidebar-admin :: sidebar}"></div>
17
 
18
  <div class="container-layout">
19
 
@@ -38,9 +38,9 @@
38
  </div>
39
 
40
  <div class="admin-stat-card__body">
41
- <h2 class="admin-stat-card__number">53</h2>
42
  <p class="admin-stat-card__description">
43
- +12% so với tháng trước
44
  </p>
45
  </div>
46
  </div>
@@ -56,8 +56,9 @@
56
  </div>
57
 
58
  <div class="admin-stat-card__body">
59
- <h2 class="admin-stat-card__number">48</h2>
60
- <p class="admin-stat-card__description">
 
61
  90.6% tổng số
62
  </p>
63
  </div>
@@ -74,8 +75,9 @@
74
  </div>
75
 
76
  <div class="admin-stat-card__body">
77
- <h2 class="admin-stat-card__number">5</h2>
78
- <p class="admin-stat-card__description">
 
79
  Cần xem xét
80
  </p>
81
  </div>
@@ -92,8 +94,9 @@
92
  </div>
93
 
94
  <div class="admin-stat-card__body">
95
- <h2 class="admin-stat-card__number">7</h2>
96
- <p class="admin-stat-card__description">
 
97
  Tài khoản mới đăng ký
98
  </p>
99
  </div>
@@ -323,10 +326,16 @@
323
  <div th:replace="~{cms/layout/footer :: footer}"></div>
324
  </div>
325
  </div>
 
 
 
 
 
 
326
  <script th:src="@{https://cdn.jsdelivr.net/npm/chart.js}"></script>
327
  <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
328
  <script th:src="@{/js/charts/AccountChart.js}"></script>
329
  <script th:src="@{/js/charts/SystemActivityChart.js}"></script>
330
  </body>
331
 
332
- </html>
 
13
  <body>
14
  <div class="bg-image"></div>
15
  <div class="layout">
16
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
17
 
18
  <div class="container-layout">
19
 
 
38
  </div>
39
 
40
  <div class="admin-stat-card__body">
41
+ <h2 class="admin-stat-card__number" th:text="${dashboard.totalAccounts()}">53</h2>
42
  <p class="admin-stat-card__description">
43
+ Tất cả tài khoản trong hệ thống
44
  </p>
45
  </div>
46
  </div>
 
56
  </div>
57
 
58
  <div class="admin-stat-card__body">
59
+ <h2 class="admin-stat-card__number" th:text="${dashboard.activeAccounts()}">48</h2>
60
+ <p class="admin-stat-card__description"
61
+ th:text="${dashboard.activeRate()} + ' tổng số'">
62
  90.6% tổng số
63
  </p>
64
  </div>
 
75
  </div>
76
 
77
  <div class="admin-stat-card__body">
78
+ <h2 class="admin-stat-card__number" th:text="${dashboard.inactiveAccounts()}">5</h2>
79
+ <p class="admin-stat-card__description"
80
+ th:text="${dashboard.inactiveRate()} + ' tổng số'">
81
  Cần xem xét
82
  </p>
83
  </div>
 
94
  </div>
95
 
96
  <div class="admin-stat-card__body">
97
+ <h2 class="admin-stat-card__number" th:text="${dashboard.pendingAccounts()}">7</h2>
98
+ <p class="admin-stat-card__description"
99
+ th:text="${dashboard.pendingRate()} + ' tổng số'">
100
  Tài khoản mới đăng ký
101
  </p>
102
  </div>
 
326
  <div th:replace="~{cms/layout/footer :: footer}"></div>
327
  </div>
328
  </div>
329
+ <script th:inline="javascript">
330
+ window.accountTypeChartData = {
331
+ labels: /*[[${dashboard.accountTypeDistribution().![label]}]]*/ [],
332
+ values: /*[[${dashboard.accountTypeDistribution().![count]}]]*/ []
333
+ };
334
+ </script>
335
  <script th:src="@{https://cdn.jsdelivr.net/npm/chart.js}"></script>
336
  <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
337
  <script th:src="@{/js/charts/AccountChart.js}"></script>
338
  <script th:src="@{/js/charts/SystemActivityChart.js}"></script>
339
  </body>
340
 
341
+ </html>
src/main/resources/templates/cms/dashboard/dashboard-employee.html CHANGED
@@ -13,7 +13,7 @@
13
  <div class="bg-image"></div>
14
 
15
  <div class="layout">
16
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
17
 
18
  <div class="container-layout">
19
 
 
13
  <div class="bg-image"></div>
14
 
15
  <div class="layout">
16
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
17
 
18
  <div class="container-layout">
19
 
src/main/resources/templates/cms/dashboard/dashboard-manager.html CHANGED
@@ -12,7 +12,7 @@
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
 
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
src/main/resources/templates/cms/document/document-create.html CHANGED
@@ -17,7 +17,7 @@
17
  <div class="layout">
18
 
19
  <!-- SIDEBAR -->
20
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
21
 
22
  <!-- CONTENT -->
23
  <div class="container-layout">
 
17
  <div class="layout">
18
 
19
  <!-- SIDEBAR -->
20
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
21
 
22
  <!-- CONTENT -->
23
  <div class="container-layout">
src/main/resources/templates/cms/document/document-list.html CHANGED
@@ -12,7 +12,7 @@
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
@@ -142,4 +142,4 @@
142
  </div>
143
  </body>
144
 
145
- </html>
 
12
  <body>
13
  <div class="bg-image"></div>
14
  <div class="layout">
15
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
16
 
17
  <div class="container-layout">
18
 
 
142
  </div>
143
  </body>
144
 
145
+ </html>
src/main/resources/templates/cms/face-id/faceID-create.html CHANGED
@@ -16,7 +16,7 @@
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
 
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
src/main/resources/templates/cms/face-id/faceID-list.html CHANGED
@@ -14,7 +14,7 @@
14
  <div class="bg-image"></div>
15
  <div class="layout">
16
  <!-- SIDEBAR -->
17
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
18
 
19
  <!-- MAIN LAYOUT -->
20
  <div class="container-layout">
 
14
  <div class="bg-image"></div>
15
  <div class="layout">
16
  <!-- SIDEBAR -->
17
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
18
 
19
  <!-- MAIN LAYOUT -->
20
  <div class="container-layout">
src/main/resources/templates/cms/password/change-password.html CHANGED
@@ -16,7 +16,7 @@
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
20
 
21
  <!-- MAIN CONTENT -->
22
  <div class="container-layout">
 
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
20
 
21
  <!-- MAIN CONTENT -->
22
  <div class="container-layout">
src/main/resources/templates/cms/report/report-day.html CHANGED
@@ -15,7 +15,7 @@
15
  <div class="layout">
16
 
17
  <!-- Sidebar -->
18
- <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
19
 
20
  <!-- Content -->
21
  <div class="container-layout">
 
15
  <div class="layout">
16
 
17
  <!-- Sidebar -->
18
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
19
 
20
  <!-- Content -->
21
  <div class="container-layout">
src/main/resources/templates/cms/report/report-month.html CHANGED
@@ -15,7 +15,7 @@
15
 
16
  <div class="layout">
17
 
18
- <div th:replace="~{cms/sidebar/sidebar-manager :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
 
15
 
16
  <div class="layout">
17
 
18
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
19
 
20
  <div class="container-layout">
21
 
src/main/resources/templates/cms/sidebar/sidebar-admin.html CHANGED
@@ -16,7 +16,7 @@
16
  <ul class="sidebar-menu">
17
 
18
  <li class="sidebar-option">
19
- <a href="/dashboardAdmin" class="sidebar-link">
20
  <span>📊</span>
21
  Dashboard
22
  </a>
@@ -84,4 +84,4 @@
84
  }
85
  });
86
  </script>
87
- </div>
 
16
  <ul class="sidebar-menu">
17
 
18
  <li class="sidebar-option">
19
+ <a href="/dashboard/admin" class="sidebar-link">
20
  <span>📊</span>
21
  Dashboard
22
  </a>
 
84
  }
85
  });
86
  </script>
87
+ </div>
src/main/resources/templates/cms/sidebar/sidebar-role.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <th:block th:fragment="sidebar">
2
+ <th:block th:if="${#authorization.expression('hasRole(''ADMIN'')')}">
3
+ <th:block th:replace="~{cms/sidebar/sidebar-admin :: sidebar}"></th:block>
4
+ </th:block>
5
+ <th:block th:if="${#authorization.expression('hasRole(''MANAGER'')')}">
6
+ <th:block th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></th:block>
7
+ </th:block>
8
+ <th:block th:if="${#authorization.expression('hasRole(''STUDENT'')')}">
9
+ <th:block th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></th:block>
10
+ </th:block>
11
+ </th:block>
src/main/resources/templates/cms/user/user-information.html CHANGED
@@ -16,7 +16,7 @@
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
- <div th:replace="~{cms/sidebar/sidebar-manage :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
@@ -178,4 +178,4 @@
178
  </script>
179
  </body>
180
 
181
- </html>
 
16
  <div class="layout">
17
 
18
  <!-- SIDEBAR -->
19
+ <div th:replace="~{cms/sidebar/sidebar-role :: sidebar}"></div>
20
 
21
  <!-- CONTENT -->
22
  <div class="container-layout">
 
178
  </script>
179
  </body>
180
 
181
+ </html>