diff --git a/Design/adminPage_ideas.md b/Design/adminPage_ideas.md index 38b56a62..699924d0 100644 --- a/Design/adminPage_ideas.md +++ b/Design/adminPage_ideas.md @@ -4,7 +4,7 @@ PHẦN 1: CÁC CHỨC NĂNG TRÊN GISAO DIỆN ADMIN (UI MENUS) Đây là các chức năng mặc định xuất hiện ở thanh Menu bên trái (Sidebar) của trang quản trị: Menu chính Menu con Chức năng chi tiết -1. Dashboard (Bảng điều khiển) Home Xem tổng quan trạng thái website (Site Health, số lượng bài viết/trang, bình luận gần đây, hoạt động viết nháp nhanh). +(done)1. Dashboard (Bảng điều khiển) Home Xem tổng quan trạng thái website (Site Health, số lượng bài viết/trang, bình luận gần đây, hoạt động viết nháp nhanh). Updates Cập nhật phiên bản WordPress Core, Themes, Plugins và các gói dịch vụ ngôn ngữ. (Done) 2. Posts (Bài viết) All Posts Quản lý toàn bộ bài viết tin tức, blog, lọc theo ngày/chuyên mục. Add New Soạn thảo bài viết mới bằng Block Editor (Gutenberg) hoặc Classic Editor. @@ -22,7 +22,7 @@ Theme File Editor Chỉnh sửa trực tiếp file code của giao diện (chỉ (done)7. Plugins (Gói mở rộng) Installed Plugins Quản lý, kích hoạt, vô hiệu hóa hoặc xóa các Plugin đang có trên hệ thống. Add New Tìm kiếm và cài đặt Plugin mới từ thư viện WordPress.org hoặc upload file .zip. Plugin File Editor Chỉnh sửa mã nguồn của các Plugin trực tiếp từ admin. -8. Users (Thành viên) All Users Quản lý danh sách toàn bộ tài khoản đăng ký trên hệ thống. +(done) 8. Users (Thành viên) All Users Quản lý danh sách toàn bộ tài khoản đăng ký trên hệ thống. Add New Tạo tài khoản người dùng mới và chỉ định vai trò (Role). Profile Chỉnh sửa thông tin cá nhân của tài khoản đang đăng nhập (đổi pass, ngôn ngữ hiển thị). 9. Tools (Công cụ) Available Tools Các công cụ hỗ trợ chuyển đổi dữ liệu. diff --git a/sisvietnamvn_main/kill_app_forcely.sh b/sisvietnamvn_main/kill_app_forcely.sh new file mode 100755 index 00000000..25b60c47 --- /dev/null +++ b/sisvietnamvn_main/kill_app_forcely.sh @@ -0,0 +1 @@ +kill -9 $(lsof -t -i:8080) || true diff --git a/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/GlobalControllerAdvice.java b/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/GlobalControllerAdvice.java new file mode 100644 index 00000000..9025e604 --- /dev/null +++ b/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/GlobalControllerAdvice.java @@ -0,0 +1,44 @@ +package com.sisvietnamvn.web.controller; + +import com.sisvietnamvn.web.service.SettingService; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.Map; + +/** + * Provides global model attributes for all frontend controllers. + */ +@ControllerAdvice(basePackages = "com.sisvietnamvn.web.controller") +public class GlobalControllerAdvice { + + private final SettingService settingService; + private final PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + + public GlobalControllerAdvice(SettingService settingService) { + this.settingService = settingService; + } + + /** + * Makes the 'activeTheme' variable available to all Thymeleaf templates handled by controllers in this package. + */ + @ModelAttribute("activeTheme") + public String getActiveTheme() { + Map settings = settingService.getAllAsMap(); + String activeTheme = settings.getOrDefault("active_theme", "default"); + + // Validate that the layout actually exists to prevent Thymeleaf TemplateInputException crashes + try { + Resource[] resources = resourceResolver.getResources("classpath*:templates/themes/" + activeTheme + "/layout.html"); + if (resources == null || resources.length == 0) { + return "default"; // Fallback to safe layout + } + } catch (Exception e) { + return "default"; + } + + return activeTheme; + } +} diff --git a/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/manage/ManageThemeController.java b/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/manage/ManageThemeController.java new file mode 100644 index 00000000..b96bb16f --- /dev/null +++ b/sisvietnamvn_main/src/main/java/com/sisvietnamvn/web/controller/manage/ManageThemeController.java @@ -0,0 +1,98 @@ +package com.sisvietnamvn.web.controller.manage; + +import com.sisvietnamvn.web.service.SettingService; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import com.sisvietnamvn.web.security.AuthoritiesConstants; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Controller for the admin Themes page. + */ +@Controller +@RequestMapping("/manage/themes") +@PreAuthorize("hasAnyAuthority(\"" + AuthoritiesConstants.ADMIN + "\", \"" + AuthoritiesConstants.EDITOR + "\")") +public class ManageThemeController { + + private final SettingService settingService; + private final PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + + public ManageThemeController(SettingService settingService) { + this.settingService = settingService; + } + + private List getAvailableLayouts() { + List layouts = new ArrayList<>(); + try { + Resource[] resources = resourceResolver.getResources("classpath*:templates/themes/*/layout.html"); + for (Resource res : resources) { + String path = res.getURL().toString(); + java.util.regex.Matcher m = java.util.regex.Pattern.compile("themes/([^/]+)/layout\\.html$").matcher(path); + if (m.find()) { + layouts.add(m.group(1)); + } + } + } catch (IOException e) { + // Ignore if directory doesn't exist + } + + // Ensure we always have at least a fallback if empty + if (layouts.isEmpty()) { + layouts.add("default"); + } + return layouts; + } + + @GetMapping + public String listThemes(Model model) { + Map settings = settingService.getAllAsMap(); + String activeTheme = settings.getOrDefault("active_theme", "default"); + + model.addAttribute("activeTheme", activeTheme); + model.addAttribute("availableThemes", getAvailableLayouts()); + return "manage/themes/list"; + } + + private boolean isThemeComplete(String themeKey) { + try { + Resource[] layouts = resourceResolver.getResources("classpath*:templates/themes/" + themeKey + "/layout.html"); + Resource[] headers = resourceResolver.getResources("classpath*:templates/themes/" + themeKey + "/header.html"); + Resource[] footers = resourceResolver.getResources("classpath*:templates/themes/" + themeKey + "/footer.html"); + + return layouts.length > 0 && headers.length > 0 && footers.length > 0; + } catch (Exception e) { + return false; + } + } + + @PostMapping("/activate") + public String activateTheme(@RequestParam("themeKey") String themeKey, RedirectAttributes redirectAttributes) { + List validThemes = getAvailableLayouts(); + + if (!validThemes.contains(themeKey)) { + redirectAttributes.addFlashAttribute("errorMessage", "Invalid theme selected."); + return "redirect:/manage/themes"; + } + + if (!isThemeComplete(themeKey)) { + redirectAttributes.addFlashAttribute("errorMessage", "Cannot activate theme: Missing required files (layout.html, header.html, or footer.html)."); + return "redirect:/manage/themes"; + } + + settingService.setValue("active_theme", themeKey); + redirectAttributes.addFlashAttribute("successMessage", "New theme activated successfully."); + return "redirect:/manage/themes"; + } +} diff --git a/sisvietnamvn_main/src/main/resources/templates/fragments/manage-layout.html b/sisvietnamvn_main/src/main/resources/templates/fragments/manage-layout.html index 61a5c0a1..4f965060 100644 --- a/sisvietnamvn_main/src/main/resources/templates/fragments/manage-layout.html +++ b/sisvietnamvn_main/src/main/resources/templates/fragments/manage-layout.html @@ -113,6 +113,21 @@ + + + diff --git a/sisvietnamvn_main/src/main/resources/templates/manage/themes/list.html b/sisvietnamvn_main/src/main/resources/templates/manage/themes/list.html new file mode 100644 index 00000000..95786547 --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/manage/themes/list.html @@ -0,0 +1,61 @@ + + + + + Themes + + + + +
+ +
+

Themes

+
+ + + + + +
+ + +
+
+
+
Theme Name
+ Active +
+
+
+ +
+

A custom layout file loaded from the templates/themes directory.

+ +
+ + + +
+ +
+
+
+ +
+ +
+ + + + diff --git a/sisvietnamvn_main/src/main/resources/templates/page.html b/sisvietnamvn_main/src/main/resources/templates/page.html index 9a813688..58602d16 100644 --- a/sisvietnamvn_main/src/main/resources/templates/page.html +++ b/sisvietnamvn_main/src/main/resources/templates/page.html @@ -1,5 +1,5 @@ - + Page Title diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/default/footer.html b/sisvietnamvn_main/src/main/resources/templates/themes/default/footer.html new file mode 100644 index 00000000..926d083b --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/default/footer.html @@ -0,0 +1,11 @@ + + + + + + +
+

© 2026 Default Theme Footer. All rights reserved.

+
+ + diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/default/header.html b/sisvietnamvn_main/src/main/resources/templates/themes/default/header.html new file mode 100644 index 00000000..9112d412 --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/default/header.html @@ -0,0 +1,17 @@ + + + + + + +
+

Default Theme Header

+ +
+ + diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/default/layout.html b/sisvietnamvn_main/src/main/resources/templates/themes/default/layout.html new file mode 100644 index 00000000..9c49e0df --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/default/layout.html @@ -0,0 +1,18 @@ + + + + + Default Theme + + + +
+ +
+
+
+ + +
+ + diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/modern/footer.html b/sisvietnamvn_main/src/main/resources/templates/themes/modern/footer.html new file mode 100644 index 00000000..477322f8 --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/modern/footer.html @@ -0,0 +1,12 @@ + + + + + + +
+

Modern Theme Design

+

© 2026. Built with Spring Boot and Thymeleaf.

+
+ + diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/modern/header.html b/sisvietnamvn_main/src/main/resources/templates/themes/modern/header.html new file mode 100644 index 00000000..8bab2310 --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/modern/header.html @@ -0,0 +1,17 @@ + + + + + + +
+

MODERNTHEME

+ +
+ + diff --git a/sisvietnamvn_main/src/main/resources/templates/themes/modern/layout.html b/sisvietnamvn_main/src/main/resources/templates/themes/modern/layout.html new file mode 100644 index 00000000..9916f904 --- /dev/null +++ b/sisvietnamvn_main/src/main/resources/templates/themes/modern/layout.html @@ -0,0 +1,16 @@ + + + + + Modern Theme + + + +
+ +
+ + + + +