diff --git a/src/main/java/uk/ac/cf/spring/demo/exception/ResourceNotFoundException.java b/src/main/java/uk/ac/cf/spring/demo/exception/ResourceNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..9593c9c187ddf5411ac674c727ab0b10c84ebaef --- /dev/null +++ b/src/main/java/uk/ac/cf/spring/demo/exception/ResourceNotFoundException.java @@ -0,0 +1,8 @@ +package uk.ac.cf.spring.demo.exception; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String message) { + super(message); + } +} + diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/User.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/User.java deleted file mode 100644 index 9f5bd332dbac8aecd02c0cdd0629dea4d5a58c05..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/User.java +++ /dev/null @@ -1,15 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor // è‡ªåŠ¨ç”Ÿæˆæ— 傿ž„é€ å‡½æ•° -public class User { - private Long id; - private String email; - private String username; -} \ No newline at end of file diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserController.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserController.java deleted file mode 100644 index 483e3b5a5c1486d4ed0f1cc7808b76df825b80b6..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserController.java +++ /dev/null @@ -1,50 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.ModelAndView; - -import java.util.List; -@RestController -@Controller -public class UserController { - private final UserService userService; - - // 使用 @Autowired 进行ä¾èµ–æ³¨å…¥ï¼ˆæž„é€ å‡½æ•°æ³¨å…¥ï¼‰ - @Autowired - public UserController(UserService userService) { - this.userService = userService; - } - - // èŽ·å–æ‰€æœ‰ç”¨æˆ·åˆ—表 - @GetMapping - public List<User> getAllUsers() { - return userService.getAllUsers(); - } - - // 通过用户 ID 获å–用户详情 - @GetMapping("/api/users/{id}") - public User getUserById(@PathVariable Long id) { - return userService.getUserById(id); - } - - // æ·»åŠ ç”¨æˆ· - @PostMapping - public void addUser(@RequestBody User user) { - userService.addUser(user); - } - - // æ›´æ–°ç”¨æˆ·ä¿¡æ¯ -// @PutMapping("/{id}") -// public void updateUser(@PathVariable Long id, @RequestBody User user) { -// user.setId(id); // ç¡®ä¿æ›´æ–°çš„对象有æ£ç¡®çš„ ID -// userService.updateUser(user); -// } - - // åˆ é™¤ç”¨æˆ· - @DeleteMapping("/{id}") - public void deleteUser(@PathVariable Long id) { - userService.deleteUser(id); - } -} \ No newline at end of file diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserService.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserService.java deleted file mode 100644 index 7c3f4f454e7dbf0a21355658ecddff310d4e2c52..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserService.java +++ /dev/null @@ -1,23 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - - -import java.util.List; - -public interface UserService { - // èŽ·å–æ‰€æœ‰ç”¨æˆ· - List<User> getAllUsers(); - - // 通过 ID 获å–用户 - User getUserById(Long id); - - // 通过用户å获å–用户 - List<User> getUsersByUsername(String username); - - // 通过邮箱获å–用户 - User getUserByEmail(String email); - - // æ·»åŠ ç”¨æˆ· - void addUser(User user); - - void deleteUser(Long id); -} \ No newline at end of file diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserServiceImpl.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserServiceImpl.java deleted file mode 100644 index b180ab3d2454e8c7f0b86fcc3873e5d04205f286..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/UserServiceImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class UserServiceImpl implements UserService{ - private final userDao userDao; // 声明ä¾èµ– - public UserServiceImpl(userDao userDao) { - this.userDao = userDao; - } - @Override - public List<User> getAllUsers() { - return userDao.getAllUsers(); - } - - @Override - public User getUserById(Long id) { - return null; - } - - @Override - public List<User> getUsersByUsername(String username) { - return null; - } - - @Override - public User getUserByEmail(String email) { - return null; - } - - @Override - public void addUser(User user) { - - } - - @Override - public void deleteUser(Long id) { - - } -} diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/Userform.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/Userform.java deleted file mode 100644 index 4fe5fd6ed70ca68e9800f1d9f6ca1e4f159c2085..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/Userform.java +++ /dev/null @@ -1,17 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class Userform { - private Long id; - private String email; - private String username; - - public Userform() { - - } -} - diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/userDao.java b/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/userDao.java deleted file mode 100644 index bff08095c8b53a77ff19d413a7d070ed75a63694..0000000000000000000000000000000000000000 --- a/src/main/java/uk/ac/cf/spring/demo/sports/Userdetail/userDao.java +++ /dev/null @@ -1,70 +0,0 @@ -package uk.ac.cf.spring.demo.sports.Userdetail; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository // æ ‡æ³¨ä¸º Spring 管ç†çš„ Bean -public class userDao { - - private final JdbcTemplate jdbcTemplate; - - // æž„é€ å‡½æ•°æ³¨å…¥ JdbcTemplate - public userDao(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - // èŽ·å–æ‰€æœ‰ç”¨æˆ· - public List<User> getAllUsers() { - // 查询所有用户的 SQL è¯å¥ - String sql = "SELECT id, email, username FROM information"; - - // æ‰§è¡ŒæŸ¥è¯¢å¹¶å°†ç»“æžœæ˜ å°„åˆ° User 对象 - return jdbcTemplate.query(sql, (rs, rowNum) -> new User( - rs.getLong("id"), // èŽ·å– id - rs.getString("email"), // èŽ·å– email - rs.getString("username") // èŽ·å– username - )); - } - - // æ ¹æ® ID 获å–å•个用户 - public User getUserById(Long id) { - // 查询å•个用户的 SQL è¯å¥ - String sql = "SELECT id, email, username FROM information WHERE id = ?"; - - // 执行查询并返回唯一的 User 对象 - return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> new User( - rs.getLong("id"), // èŽ·å– id - rs.getString("email"), // èŽ·å– email - rs.getString("username") // èŽ·å– username - )); - } - - // æ·»åŠ ä¸€ä¸ªæ–°ç”¨æˆ· - public int addUser(User user) { - // æ’入用户的 SQL è¯å¥ - String sql = "INSERT INTO information (email, username) VALUES (?, ?)"; - - // 执行æ’å…¥æ“作并返回å—å½±å“的行数 - return jdbcTemplate.update(sql, user.getEmail(), user.getUsername()); - } - - // æ›´æ–°ç”¨æˆ·ä¿¡æ¯ - public int updateUser(User user) { - // 更新用户的 SQL è¯å¥ - String sql = "UPDATE information SET email = ?, username = ? WHERE id = ?"; - - // 执行更新æ“作并返回å—å½±å“的行数 - return jdbcTemplate.update(sql, user.getEmail(), user.getUsername(), user.getId()); - } - - // åˆ é™¤ç”¨æˆ· - public int deleteUser(Long id) { - // åˆ é™¤ç”¨æˆ·çš„ SQL è¯å¥ - String sql = "DELETE FROM information WHERE id = ?"; - - // æ‰§è¡Œåˆ é™¤æ“作并返回å—å½±å“的行数 - return jdbcTemplate.update(sql, id); - } -} diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityConfig.java b/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityConfig.java index 86abcdc63e5372e4141fae3868b5cbdf08706b5d..10a8e80dedb69bb13ea24da5ff55cbf1fa1189ff 100644 --- a/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityConfig.java +++ b/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityConfig.java @@ -25,35 +25,21 @@ public class SecurityConfig { "/", // root path "/match", // match data path "/match/**", + "/users", // user data path + "/users/**", "/api/**", // API "/html/**", // static HTML "/html/register.html", // registration path "/html/login.html", // login - "/html/table-tennis rules.html", + "/html/table-tennisrules.html", "/rankings", //ranking data path "/rankings/**", "/html/table-tennisrules.html" }; -// @Bean -// public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { -// http -// .authorizeHttpRequests(request -> request -// .requestMatchers(ENDPOINTS_WHITELIST).permitAll() // Allow whitelisted pages without authentication -// .anyRequest().authenticated() // Other pages require authentication -// ) -// .csrf().disable() -// -// .formLogin(form -> form -// .loginPage("/html/login.html").permitAll() // Using Custom Pages -// .defaultSuccessUrl("/html/matchSchedule.html", true) // After successful login, you will be redirected -// .failureUrl("/html/login.html?error=true") // After login failure, you will be redirected -// ) -// .logout().logoutUrl("/logout").logoutSuccessUrl("/"); // Logout Configuration -// -// -// return http.build(); -// } + public static final String[] ADMIN_WHITELIST = { + "/admin/**", + }; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -61,8 +47,8 @@ public class SecurityConfig { // Configure access rights for paths .authorizeHttpRequests(request -> request .requestMatchers(ENDPOINTS_WHITELIST).permitAll() // Allow whitelisted pages without authentication - .requestMatchers("/admin/**").hasRole("ADMIN") // Only users with the ADMIN role are allowed to access - .requestMatchers("/html/matchDetailChangeScore.html").hasRole("ADMIN") // Only users with the ADMIN role are allowed to access + .requestMatchers("/users/current").permitAll() + .requestMatchers("/html/backGroundMatch.html").hasRole("ADMIN") // Only users with the ADMIN role are allowed to access .anyRequest().authenticated() // Other paths require authentication ) @@ -82,9 +68,10 @@ public class SecurityConfig { // Logout Configuration .logout(logout -> logout .logoutUrl("/logout") // Set the logout path - .logoutSuccessUrl("/") // The path to which you are redirected after the logout is successful + .logoutSuccessUrl("/html/login.html") // The path to which you are redirected after the logout is successful + .invalidateHttpSession(true) // Invalidate the session + .clearAuthentication(true) // Clear authentication information ); - return http.build(); } diff --git a/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityUtils.java b/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..2fff4a26178f8336eb9175b5436c92ffac94935e --- /dev/null +++ b/src/main/java/uk/ac/cf/spring/demo/sports/security/SecurityUtils.java @@ -0,0 +1,48 @@ +package uk.ac.cf.spring.demo.util; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import uk.ac.cf.spring.demo.user.User; +import uk.ac.cf.spring.demo.user.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import java.util.Optional; + +public class SecurityUtils { + + @Autowired + private UserRepository userRepository; + + // 获å–当å‰è®¤è¯å¯¹è±¡ + public static Authentication getAuthentication() { + return SecurityContextHolder.getContext().getAuthentication(); + } + + // 检查当å‰ç”¨æˆ·æ˜¯å¦ä¸ºç®¡ç†å‘˜ + public static boolean isAdmin() { + Authentication authentication = getAuthentication(); + return authentication.getAuthorities().stream() + .anyMatch(authority -> authority.getAuthority().equals("ROLE_ADMIN")); + } + + // 获å–当å‰ç”¨æˆ·çš„角色 + public static String getCurrentUserRole() { + Authentication authentication = getAuthentication(); + return authentication.getAuthorities().stream() + .map(authority -> authority.getAuthority()) + .findFirst() + .orElse("ROLE_USER"); + } + + // 获å–当å‰ç”¨æˆ·å + public static String getCurrentUsername() { + Authentication authentication = getAuthentication(); + return authentication.getName(); + } + + // 从数æ®åº“ä¸åŠ è½½å½“å‰ç”¨æˆ·è¯¦ç»†ä¿¡æ¯ + public Optional<User> getCurrentUserDetails() { + String username = getCurrentUsername(); + return userRepository.findByUsername(username); + } +} diff --git a/src/main/java/uk/ac/cf/spring/demo/user/CustomUserDetailsService.java b/src/main/java/uk/ac/cf/spring/demo/user/CustomUserDetailsService.java new file mode 100644 index 0000000000000000000000000000000000000000..0455ac126d18cfe586b299c37a72ab7026ee1bdd --- /dev/null +++ b/src/main/java/uk/ac/cf/spring/demo/user/CustomUserDetailsService.java @@ -0,0 +1,35 @@ +package uk.ac.cf.spring.demo.user; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("User not found")); + + // 将用户的角色转æ¢ä¸º GrantedAuthority + List<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority("ROLE_" + user.getRole())); + + // 返回 UserDetails 对象 + return new org.springframework.security.core.userdetails.User( + user.getUsername(), + user.getPassword(), + authorities + ); + } +} + diff --git a/src/main/java/uk/ac/cf/spring/demo/user/UserRepository.java b/src/main/java/uk/ac/cf/spring/demo/user/UserRepository.java index b3fbd2f9bbb35466a35e07382c1e9ace7e2e8613..2d0c05a6782cedb994dfa065c36be8036403ac2c 100644 --- a/src/main/java/uk/ac/cf/spring/demo/user/UserRepository.java +++ b/src/main/java/uk/ac/cf/spring/demo/user/UserRepository.java @@ -3,6 +3,8 @@ package uk.ac.cf.spring.demo.user; import org.springframework.stereotype.Repository; import java.sql.*; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; @Repository @@ -12,6 +14,39 @@ public class UserRepository { private static final String USERNAME = "root"; private static final String PASSWORD = "comsc"; + public List<User> findAll() { + String sql = "SELECT * FROM information"; + List<User> users = new ArrayList<>(); + try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); + PreparedStatement ps = conn.prepareStatement(sql); + ResultSet rs = ps.executeQuery()) { + + while (rs.next()) { + User user = new User(); + user.setId(rs.getInt("id")); + user.setUsername(rs.getString("username")); + user.setEmail(rs.getString("email")); + user.setPassword(rs.getString("password")); + user.setRole(rs.getString("role")); + users.add(user); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return users; + } + + public void delete(User user) { + String sql = "DELETE FROM information WHERE id = ?"; + try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, user.getId()); + ps.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + // æ£€æŸ¥ç”¨æˆ·åæ˜¯å¦å˜åœ¨ public boolean existsByUsername(String username) { String sql = "SELECT COUNT(*) FROM information WHERE username = ?"; @@ -47,7 +82,7 @@ public class UserRepository { } // æ’入用户 - public void save(User user) { + public User save(User user) { String sql = "INSERT INTO information (username, email, password, role) VALUES (?, ?, ?, ?)"; try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); PreparedStatement ps = conn.prepareStatement(sql)) { @@ -59,8 +94,32 @@ public class UserRepository { } catch (SQLException e) { e.printStackTrace(); } + return user; } + public Optional<User> findById(int id) { + String sql = "SELECT * FROM information WHERE id = ?"; + try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setInt(1, id); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + User user = new User(); + user.setId(rs.getInt("id")); + user.setUsername(rs.getString("username")); + user.setEmail(rs.getString("email")); + user.setPassword(rs.getString("password")); + user.setRole(rs.getString("role")); + return Optional.of(user); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return Optional.empty(); + } + + // æ ¹æ®é‚®ç®±æŸ¥æ‰¾ç”¨æˆ· public Optional<User> findByEmail(String email) { String sql = "SELECT * FROM information WHERE email = ?"; @@ -83,5 +142,28 @@ public class UserRepository { } return Optional.empty(); } + + public Optional<User> findByUsername(String username) { + String sql = "SELECT * FROM information WHERE username = ?"; + try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, username); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + User user = new User(); + user.setId(rs.getInt("id")); + user.setUsername(rs.getString("username")); + user.setEmail(rs.getString("email")); + user.setPassword(rs.getString("password")); + user.setRole(rs.getString("role")); + return Optional.of(user); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } + return Optional.empty(); + } + } diff --git a/src/main/java/uk/ac/cf/spring/demo/user/controller/LoginController.java b/src/main/java/uk/ac/cf/spring/demo/user/controller/LoginController.java index ff15671183ada5289ce1e698f0a68cd1e1bf3a59..8cc779cf024dd395a8d8fc896bb3dc205214b9e5 100644 --- a/src/main/java/uk/ac/cf/spring/demo/user/controller/LoginController.java +++ b/src/main/java/uk/ac/cf/spring/demo/user/controller/LoginController.java @@ -1,14 +1,21 @@ package uk.ac.cf.spring.demo.user.controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import uk.ac.cf.spring.demo.user.User; import uk.ac.cf.spring.demo.user.UserRepository; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; + +import java.util.Map; import java.util.Optional; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import static uk.ac.cf.spring.demo.util.SecurityUtils.getCurrentUserRole; @Controller public class LoginController { @@ -46,5 +53,36 @@ public class LoginController { // If the password is verified return ResponseEntity.ok("{\"message\": \"Login successful\"}"); } + + @GetMapping("/html/backGroundMatch.html") + public ResponseEntity<String> accessRestrictedPage() { + if (uk.ac.cf.spring.demo.util.SecurityUtils.isAdmin()) { + return ResponseEntity.ok("Welcome, Admin!"); + } else { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Access Denied"); + } + } + + @GetMapping("/users/current") + public ResponseEntity<?> getCurrentUser() { + String username = uk.ac.cf.spring.demo.util.SecurityUtils.getCurrentUsername(); + if (username == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("{\"message\": \"User not logged in\"}"); + } + + // Return user information + return ResponseEntity.ok(Map.of( + "username", username + )); + } + + + +// @GetMapping("/logout") +// public ResponseEntity<?> logoutUser(HttpServletRequest request, HttpServletResponse response) { +// SecurityContextHolder.clearContext(); // 清除用户认è¯ä¿¡æ¯ +// request.getSession().invalidate(); // 销æ¯ä¼šè¯ +// return ResponseEntity.ok("Logged out successfully"); +// } } diff --git a/src/main/java/uk/ac/cf/spring/demo/user/controller/UserController.java b/src/main/java/uk/ac/cf/spring/demo/user/controller/UserController.java new file mode 100644 index 0000000000000000000000000000000000000000..20fba0d17bfc552762947a2c6fb74e1eca815a3d --- /dev/null +++ b/src/main/java/uk/ac/cf/spring/demo/user/controller/UserController.java @@ -0,0 +1,58 @@ +package uk.ac.cf.spring.demo.user.controller; + +import uk.ac.cf.spring.demo.exception.ResourceNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import uk.ac.cf.spring.demo.user.User; +import uk.ac.cf.spring.demo.user.*; + +import java.util.List; + +@RestController +@RequestMapping("/users") +public class UserController { + + @Autowired + private UserRepository userRepository; + + @GetMapping + public List<User> getAllUsers() { + return userRepository.findAll(); + } + + @GetMapping("/{id}") + public User getUserById(@PathVariable Integer id) { + return userRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User not found with ID: " + id)); + } + + @PostMapping + public User createUser(@RequestBody User user) { + return userRepository.save(user); + } + + @PutMapping("/{id}") + public User updateUser(@PathVariable Integer id, @RequestBody User userDetails) { + User user = userRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User not found with ID: " + id)); + + user.setUsername(userDetails.getUsername()); + user.setEmail(userDetails.getEmail()); + user.setPassword(userDetails.getPassword()); + user.setRole(userDetails.getRole()); + + return userRepository.save(user); + } + + @DeleteMapping("/{id}") + public ResponseEntity<?> deleteUser(@PathVariable Integer id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User not found with ID: " + id)); + + userRepository.delete(user); + return ResponseEntity.ok().build(); + } + + +} diff --git a/src/main/resources/static/css/backGroundUser.css b/src/main/resources/static/css/backGroundUser.css new file mode 100644 index 0000000000000000000000000000000000000000..d94c9908a43447074b1bf7df4266e24e60144d32 --- /dev/null +++ b/src/main/resources/static/css/backGroundUser.css @@ -0,0 +1,42 @@ +body { + font-family: Gill Sans MT, sans-serif; + margin: 20px; + padding: 0; + background-color: #f4f4f4; +} + +h1, h2 { + text-align: center; +} + +table { + width: 100%; + border-collapse: collapse; + margin: 20px 0; +} + +th, td { + border: 1px solid #ddd; + padding: 8px; + text-align: center; +} + +th { + background-color: #f4f4f4; +} + +button { + padding: 5px 10px; + margin: 2px; + border: none; + border-radius: 3px; + cursor: pointer; +} + +button:hover { + background-color: #ddd; +} + +button:active { + background-color: #ccc; +} \ No newline at end of file diff --git a/src/main/resources/static/html/backGroundUser.html b/src/main/resources/static/html/backGroundUser.html new file mode 100644 index 0000000000000000000000000000000000000000..13fa7cb018d34f957423352d41a9c54416ba80c9 --- /dev/null +++ b/src/main/resources/static/html/backGroundUser.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>User Management</title> + <link rel="stylesheet" href="/css/backGroundUser.css"> +</head> +<body> +<h1>User Management</h1> +<h2>User List</h2> +<table id="userTable"> + <thead> + <tr> + <th>ID</th> + <th>Username</th> + <th>Email</th> + <th>Role</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + <!-- Users will be displayed here --> + </tbody> +</table> +<hr> +<div id="addUserForm"> + <h2>Add User</h2> + <form id="userForm"> + <label for="username">Username: </label> + <input type="text" id="username" name="username" required><br> + <label for="email">Email: </label> + <input type="email" id="email" name="email" required><br> + <label for="password">Password: </label> + <input type="password" id="password" name="password" required><br> + <label for="role">Role: </label> + <select id="role" name="role"> + <option value="USER">USER</option> + <option value="ADMIN">ADMIN</option> + </select><br> + <button type="button" onclick="addUser()">Add User</button> + </form> +</div> +<script src="/js/backGroundUser.js"></script> +</body> +</html> \ No newline at end of file diff --git a/src/main/resources/static/html/navBar.html b/src/main/resources/static/html/navBar.html index 1714c606e7e43f48c70a1701ac8034f9794b263f..4d9895c801b6ca59aa56f193fb168e9806501275 100644 --- a/src/main/resources/static/html/navBar.html +++ b/src/main/resources/static/html/navBar.html @@ -7,7 +7,7 @@ <li><a href="#">News</a></li> <li><a href="#">Videos</a></li> <li><a href="http://localhost:8080/html/rules.html">Rules</a></li> - <li><a href="#">Players</a></li> + <li><a href="http://localhost:8080/html/UserCenter.html">Players</a></li> <li><a href="http://localhost:8080/html/matchSchedule.html">Matches</a></li> <li><a href="http://localhost:8080/html/ranking.html">Rankings</a></li> </ul> @@ -18,10 +18,16 @@ <!-- <button class="signup-btn">Sign Up</button>--> <!-- <button class="subscribe-btn">Subscribe</button>--> <!-- </div>--> +<!-- <div class="auth-buttons">--> +<!-- <a href="http://localhost:8080/html/login.html" class="login-btn">Login</a>--> +<!-- <a href="http://localhost:8080/html/register.html" class="signup-btn">Sign Up</a>--> +<!-- <a href="http://localhost:8080/logout" class="logout-btn">Logout</a>--> +<!-- </div>--> + <div class="auth-buttons"> - <a href="http://localhost:8080/html/login.html" class="login-btn">Login</a> + <a id="auth-btn" href="http://localhost:8080/html/login.html" class="login-btn">Login</a> <a href="http://localhost:8080/html/register.html" class="signup-btn">Sign Up</a> - <a href="html/subscribe.html" class="subscribe-btn">Subscribe</a> + <a id="logout-btn" href="http://localhost:8080/logout" class="logout-btn">Logout</a> </div> </nav> \ No newline at end of file diff --git a/src/main/resources/static/js/backGroundUser.js b/src/main/resources/static/js/backGroundUser.js new file mode 100644 index 0000000000000000000000000000000000000000..b32035d1dfb83ff644e3f055cdfc056e8e41144f --- /dev/null +++ b/src/main/resources/static/js/backGroundUser.js @@ -0,0 +1,117 @@ +const USERS_API_URL = '/users'; + +window.onload = function () { + fetchUsers(); +}; + +// Fetch and display all users +function fetchUsers() { + fetch(USERS_API_URL) + .then(res => res.json()) + .then(data => { + const tableBody = document.querySelector('#userTable tbody'); + tableBody.innerHTML = ''; // Clear previous rows + + data.forEach(user => { + const userRow = document.createElement('tr'); + userRow.innerHTML = ` + <td>${user.id}</td> + <td>${user.username}</td> + <td>${user.email}</td> + <td>${user.role}</td> + <td> + <button onclick="editUser(${user.id})">Edit</button> + <button onclick="deleteUser(${user.id})">Delete</button> + </td> + `; + tableBody.appendChild(userRow); + }); + }) + .catch(err => console.error('Error fetching users:', err)); +} + +// Add a new user +function addUser() { + const userForm = document.getElementById('userForm'); + const formData = new FormData(userForm); + const userData = {}; + + formData.forEach((value, key) => { + userData[key] = value; + }); + + fetch(USERS_API_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(userData), + }) + .then(res => res.json()) + .then(() => { + alert('User added successfully!'); + fetchUsers(); + userForm.reset(); + }) + .catch(err => console.error('Error adding user:', err)); +} + +// Delete a user by ID +function deleteUser(id) { + fetch(`${USERS_API_URL}/${id}`, { + method: 'DELETE', + }) + .then(res => res.json()) + .then(() => { + alert('User deleted successfully!'); + fetchUsers(); + }) + .catch(err => console.error('Error deleting user:', err)); +} + +// Edit a user and pre-fill the form +function editUser(id) { + fetch(`${USERS_API_URL}/${id}`) + .then(res => res.json()) + .then(user => { + document.getElementById('username').value = user.username; + document.getElementById('email').value = user.email; + document.getElementById('password').value = ''; // Leave empty for security + document.getElementById('role').value = user.role; + + const addButton = document.querySelector('#userForm button'); + addButton.textContent = 'Update User'; + addButton.setAttribute('onclick', `updateUser(${id})`); + }) + .catch(err => console.error('Error editing user:', err)); +} + +// Update an existing user +function updateUser(id) { + const userForm = document.getElementById('userForm'); + const formData = new FormData(userForm); + const userData = {}; + + formData.forEach((value, key) => { + userData[key] = value; + }); + + fetch(`${USERS_API_URL}/${id}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(userData), + }) + .then(res => res.json()) + .then(() => { + alert('User updated successfully!'); + fetchUsers(); + userForm.reset(); + + const addButton = document.querySelector('#userForm button'); + addButton.textContent = 'Add User'; + addButton.setAttribute('onclick', 'addUser()'); + }) + .catch(err => console.error('Error updating user:', err)); +} \ No newline at end of file diff --git a/src/main/resources/static/js/navBar.js b/src/main/resources/static/js/navBar.js index 511600350cb19674d99956cc95a132b337ab8550..9976453a376e89ad01838efb3626197bd0629f6f 100644 --- a/src/main/resources/static/js/navBar.js +++ b/src/main/resources/static/js/navBar.js @@ -1,11 +1,60 @@ +// function loadNavbar(targetElementId) { +// fetch('navbar.html') +// .then(response => response.text()) +// .then(data => { +// // add the bar +// document.getElementById(targetElementId).innerHTML = data; +// }) +// .catch(error => { +// console.error('loadNav errors:', error); +// }); +// } + +// Load the navigation bar dynamically function loadNavbar(targetElementId) { fetch('navbar.html') .then(response => response.text()) .then(data => { - // add the bar + // Add the navbar content to the target element document.getElementById(targetElementId).innerHTML = data; + + // After the navbar is loaded, check and update user authentication state + updateAuthButtons(); }) .catch(error => { console.error('loadNav errors:', error); }); -} \ No newline at end of file +} + +// Update authentication buttons based on user login state +function updateAuthButtons() { + fetch('/users/current', { method: 'GET' }) + .then(response => { + if (!response.ok) { + throw new Error('User not logged in'); + } + return response.json(); + }) + .then(data => { + // If logged in, update Login button to display username + const authBtn = document.getElementById('auth-btn'); + authBtn.textContent = data.username; + authBtn.href = '#'; // Disable navigation for username display + authBtn.classList.remove('login-btn'); + authBtn.classList.add('username-btn'); + + // Show the Logout button + document.getElementById('logout-btn').style.display = 'block'; + }) + .catch(() => { + // If not logged in, reset the buttons to default state + const authBtn = document.getElementById('auth-btn'); + authBtn.textContent = 'Login'; + authBtn.href = '/html/login.html'; // Link back to the login page + authBtn.classList.add('login-btn'); + authBtn.classList.remove('username-btn'); + + // Hide the Logout button + document.getElementById('logout-btn').style.display = 'none'; + }); +}