diff --git a/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminApiController.java b/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..9e2b2728b76b02971f0ae41ca6932e4563b344bc --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminApiController.java @@ -0,0 +1,83 @@ +package polish_community_group_11.polish_community.admin.controllers; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; +import polish_community_group_11.polish_community.admin.services.AdminService; +import polish_community_group_11.polish_community.register.models.User; +import polish_community_group_11.polish_community.register.services.UserService; + +@RestController +public class AdminApiController { + private final AdminService adminService; + private final UserService userService; + private Authentication authentication; + + public AdminApiController(AdminService adminService, UserService userService) { + this.adminService = adminService; + this.userService = userService; + } + + @PutMapping("/admin/edit/{user_id}/role") + public ResponseEntity<Void> changeUserRole(@PathVariable("user_id") int user_id, + @RequestBody String role_name) { + authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication.getAuthorities().stream().anyMatch( + a -> a.getAuthority().equals("ROLE_ADMIN"))) { + if (role_name == null || role_name.trim().isEmpty()) { + return ResponseEntity.badRequest().build(); + } + try { + User user = userService.findById(user_id); + if (user == null) { + return ResponseEntity.notFound().build(); + } + adminService.updateUserRole(user, role_name); + return ResponseEntity.ok().build(); + } catch (Exception e) { + return ResponseEntity.internalServerError().build(); + } + } else { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + } + + @PutMapping("/admin/edit/{user_id}/enabled") + public ResponseEntity<Void> enableOrDisableUser( + @PathVariable("user_id") int user_id, @RequestParam Boolean enabled) { + authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication.getAuthorities().stream().anyMatch( + a -> a.getAuthority().equals("ROLE_ADMIN"))) { + try { + User user = userService.findById(user_id); + if (user == null) { + return ResponseEntity.notFound().build(); // User not found + } + adminService.enableOrDisableUser(user, enabled); + return ResponseEntity.ok().build(); + } catch (IllegalArgumentException e) { + // Invalid boolean or other illegal arguments + return ResponseEntity.badRequest().build(); + } catch (Exception e) { + return ResponseEntity.internalServerError().build(); + } + } else { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + } + + @GetMapping("/admin/get/{user_id}") + public ResponseEntity<User> getUser(@PathVariable("user_id") int user_id) { + try { + User user = userService.findById(user_id); + if (user == null) { + return ResponseEntity.notFound().build(); // User not found + } + return ResponseEntity.ok(user); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); + } + } +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminController.java b/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminController.java new file mode 100644 index 0000000000000000000000000000000000000000..a892a06f9879d557dc957c944746ef8124be010a --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/controllers/AdminController.java @@ -0,0 +1,52 @@ +package polish_community_group_11.polish_community.admin.controllers; + +import org.apache.coyote.BadRequestException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.servlet.ModelAndView; +import polish_community_group_11.polish_community.admin.services.AdminService; +import polish_community_group_11.polish_community.register.services.RoleService; + +import java.sql.SQLException; + +@Controller +public class AdminController { + private final AdminService adminService; + private final RoleService roleService; + private Authentication authentication; + public AdminController(AdminService adminService, RoleService roleService) { + this.adminService = adminService; + this.roleService = roleService; + } + + @GetMapping("admin/userInfo") + public ModelAndView getFirstAdminUsers() throws SQLException, BadRequestException { + ModelAndView mav = new ModelAndView("admin/userManage"); + authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication.getAuthorities().stream().anyMatch( + a -> a.getAuthority().equals("ROLE_ADMIN"))) + { + mav.addObject("usersAdminInfo",adminService.getUserManagementInfo()); + mav.addObject("roles",roleService.findAllRoles()); + } + else{ + throw new BadRequestException("User is not admin"); + } + return mav; + } + @GetMapping("admin") + public ModelAndView getAdminDashboard() throws SQLException, BadRequestException { + ModelAndView mav = new ModelAndView("admin/adminBoard"); + authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication.getAuthorities().stream().anyMatch( + a -> a.getAuthority().equals("ROLE_ADMIN"))){ + mav.addObject("adminBoard",adminService.getBoardManagementInfo()); + } + else{ + throw new BadRequestException("User is not admin"); + } + return mav; + } +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepository.java b/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..673b304145dacd2dae6b05a79cb5a6eb63290a62 --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepository.java @@ -0,0 +1,14 @@ +package polish_community_group_11.polish_community.admin.dao; + +import polish_community_group_11.polish_community.admin.models.AdminBoard; +import polish_community_group_11.polish_community.admin.models.ManageUser; +import polish_community_group_11.polish_community.register.models.User; + +import java.sql.SQLException; +import java.util.List; + +public interface AdminRepository { + List<ManageUser> getUserManagementInfo() throws SQLException; + AdminBoard getBoardManagementInfo() throws SQLException; + int updateUserRole(User user); +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepositoryImpl.java b/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepositoryImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c768512fc24a3cae024048f541092bbc3c84af98 --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/dao/AdminRepositoryImpl.java @@ -0,0 +1,116 @@ +package polish_community_group_11.polish_community.admin.dao; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; +import polish_community_group_11.polish_community.admin.models.AdminBoard; +import polish_community_group_11.polish_community.admin.models.ManageUser; +import polish_community_group_11.polish_community.register.models.User; + +import java.sql.SQLException; +import java.time.DateTimeException; +import java.util.List; + +@Repository +public class AdminRepositoryImpl implements AdminRepository { + private JdbcTemplate jdbc; // JdbcTemplate instance for performing database operations + private RowMapper<ManageUser> adminManageUserMapper; // RowMapper to map rows of the database result set to Manage User objects + private RowMapper<AdminBoard> adminBoardMapper; + public AdminRepositoryImpl(JdbcTemplate aJdbc){ + this.jdbc = aJdbc; + setAdminManageUserMapper(); + setAdminBoardMapper(); + } + + public void setAdminManageUserMapper(){ + adminManageUserMapper = (rs, i) ->{ + return new ManageUser( + rs.getInt("id"), + rs.getString("fullname"), + rs.getString("email"), + rs.getBoolean("enabled"), + rs.getInt("role_id"), + rs.getString("role_name") + ); + }; + } + public void setAdminBoardMapper(){ + adminBoardMapper = (rs, i) ->{ + return new AdminBoard( + rs.getInt("total_users"), + rs.getInt("total_posts"), + rs.getInt("upcoming_events"), + rs.getInt("new_comments") + ); + }; + } + + public List<ManageUser> getUserManagementInfo() throws SQLException { + String sql="select u.id, u.fullname, u.email, u.enabled,u.role_id, rol.role_name from users u" + + " left join user_roles u_rol" + + " on u.id = u_rol.user_id" + + " join roles rol" + + " on u.role_id = rol.id" + + " order by u.id asc"; +// + +// " limit 10"; + List<ManageUser> users=null; + try{ + users=jdbc.query(sql, adminManageUserMapper); + } + catch(EmptyResultDataAccessException ex){ + // Handle case where no records were found + throw new EmptyResultDataAccessException("Did not find any records with selected id", 0); + } + catch (IncorrectResultSizeDataAccessException ex) { + // Handle case where multiple results were found + throw new IncorrectResultSizeDataAccessException("Multiple records generated, only one record expected",1); + } + catch (DataAccessException e) { + // Handle other database-related exceptions + throw new SQLException("Some unexpected database error occured."); + } + return users; + } + + public AdminBoard getBoardManagementInfo() throws SQLException { + String sql="SELECT" + + "(SELECT COUNT(id) FROM users) AS total_users," + + "(SELECT COUNT(post_id) FROM feed) AS total_posts," + + "(SELECT COUNT(event_id) FROM event WHERE event_date > CURRENT_DATE) AS upcoming_events," + + "(SELECT COUNT(id) FROM comment WHERE DATEDIFF(CURRENT_DATE, created_date) <= 3) AS new_comments"; + AdminBoard dashboard=null; + try{ + dashboard=jdbc.queryForObject(sql, adminBoardMapper); + } + catch (IncorrectResultSizeDataAccessException ex) { + // Handle case where multiple results were found + throw new IncorrectResultSizeDataAccessException("Multiple records generated, only one record expected",1); + } + catch (DataAccessException e) { + // Handle other database-related exceptions + throw new SQLException("Some unexpected database error occured."); + } + return dashboard; + } + + public int updateUserRole(User user){ + // Validate input to ensure no null values are passed + if (user == null || user.getId() <= 0 || user.getRoleId() <= 0) { + throw new IllegalArgumentException("Invalid user or role details."); + } + // SQL query for updating the user's role and enabled status + String sql = "UPDATE users SET role_id = ?, enabled = ? WHERE id = ?"; + + try { + // Perform the update operation + int rowsUpdated = jdbc.update(sql, user.getRoleId(), user.getEnabled(), user.getId()); + return rowsUpdated; + } catch (DataAccessException e) { + throw new RuntimeException("Database error occurred while updating user role.", e); + } + } +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/models/AdminBoard.java b/src/main/java/polish_community_group_11/polish_community/admin/models/AdminBoard.java new file mode 100644 index 0000000000000000000000000000000000000000..d26e64d4c47cbc996691ff7f7283dd8e2031831d --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/models/AdminBoard.java @@ -0,0 +1,15 @@ +package polish_community_group_11.polish_community.admin.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AdminBoard { + private int totalNoOfUsers; + private int totalPosts; + private int upcomingEvents; + private int newComments; +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/models/ManageUser.java b/src/main/java/polish_community_group_11/polish_community/admin/models/ManageUser.java new file mode 100644 index 0000000000000000000000000000000000000000..154adb4de538e16958c18895c766c5ca242d1a63 --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/models/ManageUser.java @@ -0,0 +1,17 @@ +package polish_community_group_11.polish_community.admin.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ManageUser { + private int id; + private String fullName; + private String email; + private Boolean enabled; + private int role_id; + private String role; +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/services/AdminService.java b/src/main/java/polish_community_group_11/polish_community/admin/services/AdminService.java new file mode 100644 index 0000000000000000000000000000000000000000..f25075d9f267fcaa3ba1bc5a079ca33c79ee5a70 --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/services/AdminService.java @@ -0,0 +1,15 @@ +package polish_community_group_11.polish_community.admin.services; + +import polish_community_group_11.polish_community.admin.models.AdminBoard; +import polish_community_group_11.polish_community.admin.models.ManageUser; +import polish_community_group_11.polish_community.register.models.User; + +import java.sql.SQLException; +import java.util.List; + +public interface AdminService { + List<ManageUser> getUserManagementInfo() throws SQLException; + AdminBoard getBoardManagementInfo() throws SQLException; + void updateUserRole(User user, String roleName); + void enableOrDisableUser(User user, Boolean enabled); +} diff --git a/src/main/java/polish_community_group_11/polish_community/admin/services/AdminServiceImpl.java b/src/main/java/polish_community_group_11/polish_community/admin/services/AdminServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a7952fb684302ba68bebf6218585342c512253b9 --- /dev/null +++ b/src/main/java/polish_community_group_11/polish_community/admin/services/AdminServiceImpl.java @@ -0,0 +1,42 @@ +package polish_community_group_11.polish_community.admin.services; + +import org.springframework.stereotype.Service; +import polish_community_group_11.polish_community.admin.dao.AdminRepository; +import polish_community_group_11.polish_community.admin.models.AdminBoard; +import polish_community_group_11.polish_community.admin.models.ManageUser; +import polish_community_group_11.polish_community.register.models.User; + +import java.sql.SQLException; +import java.util.List; + +@Service +public class AdminServiceImpl implements AdminService { + private final AdminRepository adminRepository; + + public AdminServiceImpl(AdminRepository adminRepository) { + this.adminRepository = adminRepository; + } + public List<ManageUser> getUserManagementInfo() throws SQLException { + return adminRepository.getUserManagementInfo(); + } + public AdminBoard getBoardManagementInfo() throws SQLException{ + return adminRepository.getBoardManagementInfo(); + } + + public void updateUserRole(User user, String roleName){ + int newRoleId=roleName.toLowerCase().contains("admin")?1:2; + boolean needsUpdate=user.getRoleId()==newRoleId?false:true; + if(needsUpdate){ + user.setRoleId(newRoleId); + adminRepository.updateUserRole(user); + } + } + + public void enableOrDisableUser(User user, Boolean enabled){ + boolean needsUpdate=(enabled==user.getEnabled())?false:true; + if(needsUpdate){ + user.setEnabled(enabled); + adminRepository.updateUserRole(user); + } + } +} diff --git a/src/main/java/polish_community_group_11/polish_community/event/dao/EventRepositoryImpl.java b/src/main/java/polish_community_group_11/polish_community/event/dao/EventRepositoryImpl.java index 2197c12e66e9341ecdf4b1f3db398b38929e6cd7..df9bc2b134a5c744246f2b3a95e9459f9a0b118b 100644 --- a/src/main/java/polish_community_group_11/polish_community/event/dao/EventRepositoryImpl.java +++ b/src/main/java/polish_community_group_11/polish_community/event/dao/EventRepositoryImpl.java @@ -55,7 +55,7 @@ public class EventRepositoryImpl implements EventRepository { // Method to retrieve all events from the database public List<Event> getAllEvents() { - String sql = "select * from event"; + String sql = "select * from event order by event_id desc"; return jdbc.query(sql, eventItemMapper); } diff --git a/src/main/java/polish_community_group_11/polish_community/register/dao/UserRepositoryImpl.java b/src/main/java/polish_community_group_11/polish_community/register/dao/UserRepositoryImpl.java index 0a3b1be269baaae808f0a2cee2849693ae839486..d9beeee03923ffbf0e02c67ee77c085389db4245 100644 --- a/src/main/java/polish_community_group_11/polish_community/register/dao/UserRepositoryImpl.java +++ b/src/main/java/polish_community_group_11/polish_community/register/dao/UserRepositoryImpl.java @@ -117,6 +117,7 @@ public class UserRepositoryImpl implements UserRepository { user.setDateOfBirth(rs.getObject("dob", LocalDate.class)); user.setRoleId(rs.getInt("role_id")); user.setOrganization(rs.getString("organization")); + user.setEnabled(rs.getBoolean("enabled")); return user; }, id); } catch (EmptyResultDataAccessException e) { diff --git a/src/main/java/polish_community_group_11/polish_community/register/models/User.java b/src/main/java/polish_community_group_11/polish_community/register/models/User.java index 1c152fdb496ad6d984e1b9dada97dd024a1bf69d..ce12c01d1de239e752c6ef763c72b0d21c1f3e4f 100644 --- a/src/main/java/polish_community_group_11/polish_community/register/models/User.java +++ b/src/main/java/polish_community_group_11/polish_community/register/models/User.java @@ -1,8 +1,13 @@ package polish_community_group_11.polish_community.register.models; +import lombok.Getter; +import lombok.Setter; + import java.time.LocalDate; import java.util.List; +@Getter +@Setter public class User { private int id; private String email; @@ -11,7 +16,7 @@ public class User { private LocalDate dob; // use LocalDate for dob private int roleId; private String organization; - + private Boolean enabled; // getters and setters public int getId() { diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 2371c4449bc48ab5ee94d057edc7beb68dc6f0a1..e54eea227e7ed0aadfd69be3ed6131ed0f894b78 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -69,8 +69,9 @@ create table if not exists users ( password VARCHAR(255) NOT NULL, fullname VARCHAR(255) NOT NULL, dob DATE, - role_id INT NOT NULL, + role_id INT NOT NULL default 2, organization varchar(255), + enabled boolean default true, FOREIGN KEY (role_id) REFERENCES roles(id) ); diff --git a/src/main/resources/static/css/admin/adminBoardStyles.css b/src/main/resources/static/css/admin/adminBoardStyles.css new file mode 100644 index 0000000000000000000000000000000000000000..b128e8d32476e221dc35f35fc9c7b65ca855298d --- /dev/null +++ b/src/main/resources/static/css/admin/adminBoardStyles.css @@ -0,0 +1,119 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +.header { + text-align: center; + margin-bottom: 20px; +} + +.header h1 { + font-size: 24px; + color: #333; +} + +.statistics { + display: flex; + justify-content: center; + gap: 1rem; + margin-bottom: 20px; +} + +.statistics .stat strong{ + font-size: 1.5rem; +} + +.statistics .stat aside{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.statistics .stat { + display: flex; + justify-content: center; + gap:1rem; + align-items: center; + background-color: #f9f9f9; + border: 1px solid #ddd; + border-radius: 8px; + padding: 1rem 2rem; + height: 8rem; + width: 15.8rem; + text-align: center; + font-size: 1rem; + color: #333; +} + +i{ + font-size: 2rem; +} + +.dashboard { + display: flex; + flex-wrap: wrap; + gap: 1.2rem; + justify-content: center; +} + +.card { + background-color: #fff; + border: 1px solid #ddd; + border-radius: 8px; + padding: 2rem; + width: 21.3rem; + height: 12rem; + text-align: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: transform 0.2s; +} + +.card:hover { + transform: translateY(-5px); +} + +.card h3 { + font-size: 18px; + color: #333; + margin-bottom: 10px; +} + +.card p { + font-size: 14px; + color: #666; + margin-bottom: 15px; +} + +.card button { + background-color: #000; + color: #fff; + border: none; + border-radius: 4px; + padding: 10px 20px; + cursor: pointer; + font-size: 14px; +} + +.card button:hover { + background-color: #444; +} + +.footer { + text-align: center; + margin-top: 30px; + font-size: 14px; + color: #666; +} + +.footer a { + color: #000; + text-decoration: none; + margin: 0 10px; +} + +.footer a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/src/main/resources/static/css/admin/userManageStyles.css b/src/main/resources/static/css/admin/userManageStyles.css new file mode 100644 index 0000000000000000000000000000000000000000..7c7e3b854ed23233e0c354e127f85670ae048b70 --- /dev/null +++ b/src/main/resources/static/css/admin/userManageStyles.css @@ -0,0 +1,43 @@ +table { + width: 100%; + border-collapse: collapse; + padding: 20px; +} +section{ + padding: 2rem; +} +.table-wrap{ + border-radius: 10px; +} + +th, td { + padding: 10px; + border: 1px solid #ccc; + text-align: center; +} +th { + background-color: #f4f4f4; +} +.btn { + padding: 10px 20px; + margin: 5px; + cursor: pointer; + border: none; + background-color: var(--primary-color); + color: var(--secondary-color); + border-radius: 5px; +} +.btn-disable { + background-color: #f44336; +} + +select { + width: 6rem; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; +} + +option { + padding: 5px 10px; +} \ No newline at end of file diff --git a/src/main/resources/static/css/headings/headings.css b/src/main/resources/static/css/headings/headings.css index 7c529b08c7cdd973682acac509c4cd925cd2cc11..547d068352bfa01d97e645c8d7e79d2b32e5ab71 100644 --- a/src/main/resources/static/css/headings/headings.css +++ b/src/main/resources/static/css/headings/headings.css @@ -6,7 +6,7 @@ } button { - padding: 10px 15px; + padding: 1rem 1rem; border: none; font-size: 14px; cursor: pointer; @@ -86,6 +86,5 @@ input[type="checkbox" i] { #delete-button{ visibility: hidden; float: right; - margin: 5px 0; - + /*margin: 5px 0;*/ } \ No newline at end of file diff --git a/src/main/resources/static/js/admin/admin.js b/src/main/resources/static/js/admin/admin.js new file mode 100644 index 0000000000000000000000000000000000000000..19d73c0a19f7034fb081e1e09345af925f98a0b1 --- /dev/null +++ b/src/main/resources/static/js/admin/admin.js @@ -0,0 +1,66 @@ +// Function to enable or disable a user +function toggleUserEnabled(userId, enable) { + //check current status and do the alternate + enable = enable !== true; + const url = `/admin/edit/${userId}/enabled?enabled=${enable}`; + + // Use Fetch API to send the PUT request + fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + credentials:"include" + }) + .then(response => { + if (response.ok) { + // Reload the page to reflect the changes + location.reload(); + } else { + alert('Failed to update user status.'); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Error occurred while updating user status.'); + }); +} + +function updateUserRole(userId){ + const roleSelect = document.getElementById('roleDdl'); + const selectedValue = roleSelect.value; + const url = `/admin/edit/${userId}/role`; + + // Use Fetch API to send the PUT request + fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + credentials:"include", + body:JSON.stringify(selectedValue) + }) + .then(response => { + if (response.ok) { + // Reload the page to reflect the changes + location.reload(); + } else { + alert('Failed to update user role.'); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Error occurred while updating user role.'); + }); +} + +function disableColorChange(){ + var actionBtn = document.querySelectorAll("#btn-enable-disable"); + actionBtn.forEach(e =>{ + if(e.innerText.toLowerCase().includes('disable')){ + e.style.backgroundColor='#E5E4E6'; + e.style.color='#09090B'; + } + }); +} +disableColorChange(); diff --git a/src/main/resources/templates/admin/adminBoard.html b/src/main/resources/templates/admin/adminBoard.html new file mode 100644 index 0000000000000000000000000000000000000000..630fee8b0b835c1e1e3a302cfb631922ab9705b3 --- /dev/null +++ b/src/main/resources/templates/admin/adminBoard.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/layout}"> +<head> + <meta charset="UTF-8"> + <title>Title</title> + <link rel="stylesheet" href="/css/admin/adminBoardStyles.css"> +</head> +<section layout:fragment="content"> + <div class="header"> + <h1>Admin Dashboard</h1> + </div> + + <div class="statistics"> + <div class="stat"><i class="bi bi-people"></i> + <aside><p> Total Users</p><strong><span th:text="*{adminBoard.getTotalNoOfUsers()}"></span></strong></p></aside> + </div> + <div class="stat"><p><i class="bi bi-file-earmark-text"></i> + <aside><p> Total Posts</p><strong><span th:text="*{adminBoard.getTotalPosts()}"></span></strong></p></aside> + </div> + <div class="stat"><p><i class="bi bi-calendar-week"></i> + <aside><p> Upcoming Events</p><strong><span th:text="*{adminBoard.getUpcomingEvents()}"></span></strong></p> + </aside> + </div> + <div class="stat"><p><i class="bi bi-chat-left-dots"></i> + <aside><p> New Comments</p><strong><span th:text="*{adminBoard.getNewComments()}"></span></strong></p> + </aside> + </div> + </div> + + <div class="dashboard"> + <div class="card"> + <h3>Manage Users</h3> + <p>View and manage user accounts</p> + <a th:href="@{/admin/userInfo}"> + <button>Manage</button> + </a> + </div> + + <div class="card"> + <h3>Feeds Management</h3> + <p>Review and manage community feeds</p> + <a th:href="@{/feed}"> + <button>Manage</button> + </a> + </div> + + <div class="card"> + <h3>Event Management</h3> + <p>Create and manage community events</p> + <a th:href="@{/event}"> + <button>Manage</button> + </a> + </div> + + <div class="card"> + <h3>Database Management</h3> + <p>Manage community information database</p> + <a th:href="@{/categories}"> + <button>Manage</button> + </a> + </div> + + <div class="card"> + <h3>Comments Moderation</h3> + <p>Review and moderate user comments</p> + <a th:href="@{/feed}"> + <button>Manage</button> + </a> + </div> + + <div class="card"> + <h3>News Management</h3> + <p>Create and manage community news</p> + <a th:href="@{/news}"> + <button>Manage</button> + </a> + </div> + </div> + +</section> +</html> \ No newline at end of file diff --git a/src/main/resources/templates/admin/userManage.html b/src/main/resources/templates/admin/userManage.html new file mode 100644 index 0000000000000000000000000000000000000000..23483a1ccbfb0d15e2b34ffed3e9590eb2cfc1a1 --- /dev/null +++ b/src/main/resources/templates/admin/userManage.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html xmlns:th="http://www.thymeleaf.org" + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + layout:decorate="~{layout/layout}"> + +<head> + <title>Manage Users</title> + <!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">--> + <link rel="stylesheet" href="/css/admin/userManageStyles.css"> + <script src="/js/admin/admin.js" defer></script> +</head> +<section layout:fragment="content"> + <h2>User Management</h2> + <div class="table-wrap"> + <table> + <thead> + <tr> + <th>ID</th> + <th>Full Name</th> + <th>Email</th> + <th>Role</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + <tr th:each="user : ${usersAdminInfo}"> + <td th:text="${user.id}"></td> + <td th:text="${user.fullName}"></td> + <td th:text="${user.email}"></td> + <td th:field="${user.role}"> + <select id="roleDdl" th:onchange="|updateUserRole(${user.id})|"> + <option th:selected="${role.name==user.role}" th:each="role : ${roles}" + th:text="${role.name}"></option> + </select> + </td> + <td> + <button id="btn-enable-disable" + class="btn" + th:onclick="|toggleUserEnabled(${user.id}, ${user.enabled})|"> + <span th:text="${user.enabled ? 'Disable' : 'Enable'}"></span> + </button> + </td> + </tr> + </tbody> + </table> + </div> +</section> +</html> diff --git a/src/main/resources/templates/headings/headings.html b/src/main/resources/templates/headings/headings.html index 590b35c4d8271c8ad49bc2983a9cda80a194dc4e..80cf562f5e032c351038c644a6f272581870b88c 100644 --- a/src/main/resources/templates/headings/headings.html +++ b/src/main/resources/templates/headings/headings.html @@ -12,7 +12,9 @@ <div th:replace="~{infoHeadingFragment/infoHeadingFragment :: breadcrumb}"></div> <div class="title-section"> <h1 id="category-name"></h1> + <div class="buttons"> + <button id="delete-button" disabled>Delete</button> <button id="edit-mode-button">Edit</button> <a id="addInfo"> <button id="add-new-information"> @@ -22,9 +24,9 @@ </a> </div> </div> + <div id="headings-container" class="headings-container"> <!-- i will render headings dynamically added here from js --> </div> - <button id="delete-button" disabled>Delete</button> </section> </html>