FEAT: deleteRoom endpoint and ResponseEntity usage

This commit is contained in:
2026-06-18 18:44:18 +02:00
parent 835ad93bac
commit 1bd62ff3ca
10 changed files with 109 additions and 53 deletions

Binary file not shown.

View File

@@ -0,0 +1,16 @@
package com.mallardromain.hotel.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class AppConfig {
// By putting this here, UserService can grab it WITHOUT triggering SecurityConfig!
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@@ -18,9 +18,12 @@ public class DatabaseSeeder {
if (userRepository.count() == 0) { if (userRepository.count() == 0) {
User testUser1 = new User("test1", passwordEncoder.encode("password1")); User testUser1 = new User("test1", passwordEncoder.encode("password1"));
User testUser2 = new User("test2", passwordEncoder.encode("password2")); User testUser2 = new User("test2", passwordEncoder.encode("password2"));
User adminUser1 = new User("admin1", passwordEncoder.encode("password1"));
adminUser1.setRole("ADMIN");
userRepository.save(testUser1); userRepository.save(testUser1);
userRepository.save(testUser2); userRepository.save(testUser2);
userRepository.save(adminUser1);
} }
}; };
} }

View File

@@ -6,6 +6,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
@@ -17,7 +18,9 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import com.mallardromain.hotel.security.JWTFilter; import com.mallardromain.hotel.security.JWTFilter;
@Configuration @Configuration
@EnableMethodSecurity
public class SecurityConfig { public class SecurityConfig {
private final JWTFilter jwtFilter; private final JWTFilter jwtFilter;
public SecurityConfig(JWTFilter jwtFilter) { public SecurityConfig(JWTFilter jwtFilter) {
@@ -46,12 +49,6 @@ public class SecurityConfig {
return http.build(); return http.build();
} }
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean @Bean
public AuthenticationManager authenticationManager( public AuthenticationManager authenticationManager(
AuthenticationConfiguration config, AuthenticationConfiguration config,

View File

@@ -2,6 +2,10 @@ package com.mallardromain.hotel.controller;
import java.util.List; import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import com.mallardromain.hotel.model.Room; import com.mallardromain.hotel.model.Room;
@@ -19,27 +23,57 @@ public class RoomController {
} }
@GetMapping @GetMapping
public List<Room> getRooms() { public ResponseEntity<?> getRooms() {
return service.findAll(); try{
List<Room> roomList = service.findAll();
return ResponseEntity.ok(roomList);
} catch(RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
} }
@PostMapping @PostMapping("/create")
public Room createRoom(@RequestBody Room room){ @PreAuthorize("hasRole('ADMIN')")
return service.createRoom(room); public ResponseEntity<?> createRoom(@RequestBody Room room){
try{
Room createdRoom = service.createRoom(room);
return ResponseEntity.ok(createdRoom);
} catch(RuntimeException e){
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
} }
@PutMapping("/{id}/clean") @PutMapping("/{id}/clean")
public Room setRoomClean( public ResponseEntity<?> setRoomClean(@PathVariable Integer id){
@PathVariable Integer id try{
){ Room updatedRoom = service.setRoomClean(id);
return service.setRoomClean(id); return ResponseEntity.ok(updatedRoom);
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
} }
@PutMapping("/{id}/dirty") @PutMapping("/{id}/dirty")
public Room setRoomDirty( public ResponseEntity setRoomDirty(@PathVariable Integer id) {
@PathVariable Integer id try {
){ Room updatedRoom = service.setRoomDirty(id);
return service.setRoomDirty(id); return ResponseEntity.ok(updatedRoom);
} catch (RuntimeException e){
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
}
@DeleteMapping("/delete/{id}")
@PreAuthorize("hasRole('ADMIN')") // Keep the boss door locked!
public ResponseEntity<?> deleteRoom(@PathVariable Integer id) {
try{
service.deleteRoom(id);
return ResponseEntity.ok("Room successfully deleted!");
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
} }
} }

View File

@@ -19,7 +19,7 @@ public class Room {
} }
public Room(Integer id, String number, String status){ public Room(String number, String status){
//this.id = id; id is/should be generated by the DB //this.id = id; id is/should be generated by the DB
this.number = number; this.number = number;
this.status = status; this.status = status;

View File

@@ -14,6 +14,9 @@ public class User {
private String password; private String password;
@Column(nullable = false)
private String role = "USER";
public User(){ public User(){
} }
@@ -46,4 +49,13 @@ public class User {
public void setPassword(String password){ public void setPassword(String password){
this.password = password; this.password = password;
} }
public String getRole(){
return role;
}
public void setRole(String role){
this.role = role;
}
} }

View File

@@ -5,6 +5,8 @@ import java.util.Collections;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@@ -23,9 +25,11 @@ import jakarta.servlet.http.HttpServletResponse;
public class JWTFilter extends OncePerRequestFilter { public class JWTFilter extends OncePerRequestFilter {
private final JWTService jwtService; private final JWTService jwtService;
private final UserDetailsService userDetailsService;
public JWTFilter(JWTService jwtService){ public JWTFilter(JWTService jwtService, UserDetailsService userDetailsService){
this.jwtService = jwtService; this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
} }
@Override @Override
@@ -35,14 +39,9 @@ public class JWTFilter extends OncePerRequestFilter {
FilterChain filterChain FilterChain filterChain
) throws ServletException, IOException { ) throws ServletException, IOException {
String authHeader = request String authHeader = request.getHeader("Authorization");
.getHeader("Authorization");
if ( authHeader == null
||
!authHeader.startsWith("Bearer ")
) {
if ( authHeader == null || !authHeader.startsWith("Bearer ") ) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return;
} }
@@ -51,23 +50,18 @@ public class JWTFilter extends OncePerRequestFilter {
if (jwtService.isTockenValid(token)){ if (jwtService.isTockenValid(token)){
String username = jwtService String username = jwtService.extractUsername(token);
.extractUsername(token);
UsernamePasswordAuthenticationToken auth = UserDetails userDetails = userDetailsService.loadUserByUsername(username);
new UsernamePasswordAuthenticationToken(
username, UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
userDetails,
null, null,
Collections.emptyList() userDetails.getAuthorities()
);
auth.setDetails(
new WebAuthenticationDetailsSource()
.buildDetails(request)
); );
SecurityContextHolder.getContext() auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request) );
.setAuthentication(auth); SecurityContextHolder.getContext().setAuthentication(auth);
} }
filterChain.doFilter(request, response); filterChain.doFilter(request, response);

View File

@@ -22,14 +22,7 @@ public class RoomService {
return repo.findAll(); return repo.findAll();
} }
public Room createRoomTest() { public Room createRoomTest(Room room) {
Room room = new Room(
666,
"test",
"clean"
);
return repo.save(room); return repo.save(room);
} }
@@ -47,7 +40,7 @@ public class RoomService {
return repo.save(room); return repo.save(room);
} }
public Room setRoomDirty(Integer id){ public Room setRoomDirty(Integer id){
Room room = repo.findById(id) Room room = repo.findById(id)
.orElseThrow(() -> new RuntimeException("Room not found")); .orElseThrow(() -> new RuntimeException("Room not found"));
@@ -57,4 +50,11 @@ public class RoomService {
return repo.save(room); return repo.save(room);
} }
public void deleteRoom(Integer id) {
if (!repo.existsById(id)) {
throw new RuntimeException("Room with ID " + id + " not found");
}
repo.deleteById(id);
}
} }

View File

@@ -40,7 +40,7 @@ public class UserService implements UserDetailsService {
.map(user -> org.springframework.security.core.userdetails.User .map(user -> org.springframework.security.core.userdetails.User
.withUsername(user.getUsername()) .withUsername(user.getUsername())
.password(user.getPassword()) .password(user.getPassword())
.authorities("USER") // Default role .authorities("ROLE_" + user.getRole().toUpperCase()) // Default role
.build() .build()
) )
.orElseThrow(() -> new UsernameNotFoundException("User not found in DB")); .orElseThrow(() -> new UsernameNotFoundException("User not found in DB"));