Spaces:
Configuration error
Configuration error
Merge branch 'main' of https://github.com/minhhai266/Attendance
Browse files- src/main/java/com/attendenceSystem/constant/Routes.java +8 -0
- src/main/java/com/attendenceSystem/frontroller/HomeController.java +6 -4
- src/main/java/com/attendenceSystem/module/dashboard/dto/response/AccountTypeDistributionResponse.java +7 -0
- src/main/java/com/attendenceSystem/module/dashboard/dto/response/AdminDashboardResponse.java +24 -2
- src/main/java/com/attendenceSystem/module/dashboard/mapper/response/DashboardResponseMapper.java +7 -2
- src/main/java/com/attendenceSystem/module/dashboard/service/impl/DashboardServiceImpl.java +18 -4
- src/main/java/com/attendenceSystem/module/user/controller/AuthController.java +4 -0
- src/main/java/com/attendenceSystem/module/user/controller/UserController.java +19 -0
- src/main/java/com/attendenceSystem/module/user/dto/response/UserResponse.java +1 -1
- src/main/java/com/attendenceSystem/module/user/entity/User.java +4 -3
- src/main/java/com/attendenceSystem/module/user/entity/converter/StatusConverter.java +20 -0
- src/main/java/com/attendenceSystem/module/user/entity/enums/Department.java +2 -1
- src/main/java/com/attendenceSystem/module/user/entity/enums/Status.java +23 -0
- src/main/java/com/attendenceSystem/module/user/mapper/request/RegisterRequestMapper.java +4 -0
- src/main/java/com/attendenceSystem/module/user/mapper/response/UserResponseMapper.java +2 -2
- src/main/java/com/attendenceSystem/module/user/repository/UserRepository.java +3 -2
- src/main/java/com/attendenceSystem/module/user/service/UserService.java +2 -0
- src/main/java/com/attendenceSystem/module/user/service/impl/AuthServiceImpl.java +16 -4
- src/main/java/com/attendenceSystem/module/user/service/impl/UserServiceImpl.java +47 -5
- src/main/java/com/attendenceSystem/security/CustomUserDetails.java +10 -3
- src/main/resources/static/js/charts/AccountChart.js +12 -8
- src/main/resources/templates/cms/absent/absent-create.html +1 -1
- src/main/resources/templates/cms/absent/absent-history.html +1 -1
- src/main/resources/templates/cms/absent/absent-list.html +1 -1
- src/main/resources/templates/cms/account/account-list.html +22 -7
- src/main/resources/templates/cms/account/employee-list.html +1 -1
- src/main/resources/templates/cms/attendance/attendance-history.html +1 -1
- src/main/resources/templates/cms/attendance/attendance.html +1 -1
- src/main/resources/templates/cms/auth/login.html +5 -6
- src/main/resources/templates/cms/dashboard/dashboard-admin.html +19 -10
- src/main/resources/templates/cms/dashboard/dashboard-employee.html +1 -1
- src/main/resources/templates/cms/dashboard/dashboard-manager.html +1 -1
- src/main/resources/templates/cms/document/document-create.html +1 -1
- src/main/resources/templates/cms/document/document-list.html +2 -2
- src/main/resources/templates/cms/face-id/faceID-create.html +1 -1
- src/main/resources/templates/cms/face-id/faceID-list.html +1 -1
- src/main/resources/templates/cms/password/change-password.html +1 -1
- src/main/resources/templates/cms/report/report-day.html +1 -1
- src/main/resources/templates/cms/report/report-month.html +1 -1
- src/main/resources/templates/cms/sidebar/sidebar-admin.html +2 -2
- src/main/resources/templates/cms/sidebar/sidebar-role.html +11 -0
- 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
|
| 44 |
}
|
| 45 |
@GetMapping("/dashboardEmployee")
|
| 46 |
public String dashboardEmployee() {
|
| 47 |
-
return
|
| 48 |
}
|
| 49 |
@GetMapping("/dashboardManager")
|
| 50 |
public String dashboardManager() {
|
| 51 |
-
return
|
| 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 |
-
|
|
|
|
|
|
|
| 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.
|
| 41 |
-
long inactiveAccounts = userRepository.
|
| 42 |
-
long pendingAccounts = userRepository.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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 = "
|
| 46 |
@Builder.Default
|
| 47 |
-
private
|
| 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 |
-
|
|
|
|
| 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 |
-
.
|
| 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
|
| 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
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.
|
| 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:
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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
|
| 60 |
-
<td><span
|
|
|
|
|
|
|
|
|
|
| 61 |
<td>
|
| 62 |
-
<div class="actions"
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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-
|
| 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-
|
| 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-
|
| 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
|
@@ -20,7 +20,7 @@
|
|
| 20 |
<div class="hero-content">
|
| 21 |
<h1 class="hero-title">
|
| 22 |
<span class="hero-title-gradient">
|
| 23 |
-
|
| 24 |
</span>
|
| 25 |
<br>
|
| 26 |
<span class="hero-title-white">
|
|
@@ -71,12 +71,11 @@
|
|
| 71 |
|
| 72 |
<button class="auth-btn" type="submit">Đăng nhập</button>
|
| 73 |
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
<br>
|
| 75 |
-
<!-- <br>
|
| 76 |
-
<a class="auth-btn" href="/dashboardEmployee">Nhân Viên</a>
|
| 77 |
-
<a class="auth-btn" href="/dashboardManager">Quản lý</a>
|
| 78 |
-
<a class="auth-btn" href="/dashboardAdmin">Admin</a>
|
| 79 |
-
<br> -->
|
| 80 |
<hr style="margin: 1rem 0; opacity: 0.2" />
|
| 81 |
<div class="other-option">
|
| 82 |
<a th:href="@{/auth/register}" class="register-link">
|
|
|
|
| 20 |
<div class="hero-content">
|
| 21 |
<h1 class="hero-title">
|
| 22 |
<span class="hero-title-gradient">
|
| 23 |
+
DXLAB ATTENDANCE
|
| 24 |
</span>
|
| 25 |
<br>
|
| 26 |
<span class="hero-title-white">
|
|
|
|
| 71 |
|
| 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">
|
| 81 |
<a th:href="@{/auth/register}" class="register-link">
|
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-
|
| 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 |
-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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-
|
| 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="/
|
| 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-
|
| 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>
|