Compare commits

..

3 commits

12 changed files with 555 additions and 3 deletions

View file

@ -0,0 +1,42 @@
package fr.vincent.ramiere.mangerautourdesimplonback.config;
import fr.vincent.ramiere.mangerautourdesimplonback.service.JpaUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
private final JpaUserDetailsService jpaUserDetailsService;
public SecurityConfig(JpaUserDetailsService jpaUserDetailsService) {
this.jpaUserDetailsService = jpaUserDetailsService;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/restaurants/**").permitAll()
.requestMatchers("/api/v1/personnes/**").permitAll()
.anyRequest().authenticated())
.userDetailsService(jpaUserDetailsService)
.httpBasic(Customizer.withDefaults())
.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View file

@ -0,0 +1,91 @@
package fr.vincent.ramiere.mangerautourdesimplonback.controller;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Restaurant;
import fr.vincent.ramiere.mangerautourdesimplonback.service.RestaurantService;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.AllArgsConstructor;
/**
* Controleur REST pour la gestion des restaurants.
* Expose les endpoints de l'API pour les opérations CRUD.
*/
@RestController
@RequestMapping("/api/v1/restaurants")
@AllArgsConstructor
public class RestaurantController {
private final RestaurantService restaurantService;
/**
* Endpoint pour récupérer la liste de tous les restaurants.
* @return une ResponseEntity contenant la liste des restaurants et le statut HTTP OK.
*/
@GetMapping
public ResponseEntity<List<Restaurant>> getAllRestaurants() {
List<Restaurant> restaurants = restaurantService.getAllRestaurants();
return new ResponseEntity<>(restaurants, HttpStatus.OK);
}
/**
* Endpoint pour récupérer un restaurant par son identifiant.
* @param id L'identifiant du restaurant.
* @return une ResponseEntity contenant le restaurant s'il est trouvé (OK), sinon NOT_FOUND.
*/
@GetMapping("/{id}")
public ResponseEntity<Restaurant> getRestaurantById(@PathVariable Integer id) {
return restaurantService.getRestaurantById(id)
.map(restaurant -> new ResponseEntity<>(restaurant, HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
/**
* Endpoint pour créer un nouveau restaurant.
* @param restaurant Le restaurant à créer.
* @return une ResponseEntity contenant le restaurant créé et le statut CREATED.
*/
@PostMapping
public ResponseEntity<Restaurant> createRestaurant(@RequestBody Restaurant restaurant) {
Restaurant savedRestaurant = restaurantService.saveRestaurant(restaurant);
return new ResponseEntity<>(savedRestaurant, HttpStatus.CREATED);
}
/**
* Endpoint pour mettre à jour un restaurant existant.
* @param id L'identifiant du restaurant à mettre à jour.
* @param restaurantDetails Les nouvelles données du restaurant.
* @return une ResponseEntity contenant le restaurant mis à jour (OK), sinon NOT_FOUND.
*/
@PutMapping("/{id}")
public ResponseEntity<Restaurant> updateRestaurant(@PathVariable Integer id, @RequestBody Restaurant restaurantDetails) {
return restaurantService.updateRestaurant(id, restaurantDetails)
.map(updateRestaurant -> new ResponseEntity<>(updateRestaurant, HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
/**
* Endpoint pour supprimer un restaurant.
* @param id L'identifiant du restaurant à supprimer.
* @return une ResponseEntity avec le statut NO_CONTENT si la suppression réussit,
* ou NOT_FOUND si le restaurant n'existe pas.
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteRestaurant(@PathVariable Integer id) {
if (restaurantService.getRestaurantById(id).isPresent()) {
restaurantService.deleteRestaurant(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}

View file

@ -13,7 +13,10 @@ import java.util.Collection;
*/
@Entity
@Table(name = "restaurant")
@Data
@Getter
@Setter
@ToString(exclude = {"typerestaus", "preference"})
@EqualsAndHashCode(exclude = {"typerestaus", "preference"})
@NoArgsConstructor
@AllArgsConstructor
@Builder

View file

@ -0,0 +1,12 @@
package fr.vincent.ramiere.mangerautourdesimplonback.repository;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Personne;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface PersonneRepository extends JpaRepository<Personne, Integer> {
Optional<Personne> findByEmail(String email);
}

View file

@ -0,0 +1,16 @@
package fr.vincent.ramiere.mangerautourdesimplonback.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Restaurant;
/**
* Dépot pour l'entité Restaurant.
* Fournit les méthodes pour les opérations CRUD.
*/
@Repository
public interface RestaurantRepository extends JpaRepository<Restaurant, Integer>{
}

View file

@ -0,0 +1,29 @@
package fr.vincent.ramiere.mangerautourdesimplonback.service;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Personne;
import fr.vincent.ramiere.mangerautourdesimplonback.repository.PersonneRepository;
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;
@Service
public class JpaUserDetailsService implements UserDetailsService {
private final PersonneRepository personneRepository;
public JpaUserDetailsService(PersonneRepository personneRepository) {
this.personneRepository = personneRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Personne personne = personneRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("Aucun utilisateur trouvé avec l'email: " + username));
return new org.springframework.security.core.userdetails.User(
personne.getEmail(),
personne.getPassword(),
personne.getRoleList());
}
}

View file

@ -0,0 +1,78 @@
package fr.vincent.ramiere.mangerautourdesimplonback.service;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Restaurant;
import fr.vincent.ramiere.mangerautourdesimplonback.repository.RestaurantRepository;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
/**
* Service pour la gestion des restaurants.
* Contient la logique métier liée aux opérations sur les restaurants.
*/
@Service
@AllArgsConstructor
public class RestaurantService {
private final RestaurantRepository restaurantRepository;
/**
* Récupère tous les restaurants.
* @return une liste de tous les restaurants.
*/
public List<Restaurant> getAllRestaurants() {
return restaurantRepository.findAll();
}
/**
* Récupère un restaurant par son identifiant.
* @param id L'identifiant du restaurant.
* @return un Optional contenant le restaurant s'il est trouvé, sinon un Optional vide.
*/
public Optional<Restaurant> getRestaurantById(Integer id) {
return restaurantRepository.findById(id);
}
/**
* Enregistre un nouveau restaurant.
* @param restaurant Le restaurant à enregistrer.
* @return le restaurant enregistré
*/
public Restaurant saveRestaurant(Restaurant restaurant) {
return restaurantRepository.save(restaurant);
}
/**
* Met à jour un restaurant existant.
* @param id L'identifiant du restaurant à mettre à jour.
* @param restaurantDetails Les nouvelles informations du restaurant.
* @return le restaurant mis à jour.
*/
public Optional<Restaurant> updateRestaurant(Integer id, Restaurant restaurantDetails) {
return restaurantRepository.findById(id)
.map(existingRestaurant -> {
existingRestaurant.setNom(restaurantDetails.getNom());
existingRestaurant.setAdresse(restaurantDetails.getAdresse());
existingRestaurant.setTelephone(restaurantDetails.getTelephone());
existingRestaurant.setAccesPMR(restaurantDetails.getAccesPMR());
existingRestaurant.setAEmporter(restaurantDetails.getAEmporter());
existingRestaurant.setSurPlace(restaurantDetails.getSurPlace());
existingRestaurant.setPrix(restaurantDetails.getPrix());
existingRestaurant.setLatitude(restaurantDetails.getLatitude());
existingRestaurant.setLongitude(restaurantDetails.getLongitude());
existingRestaurant.setWebsite(restaurantDetails.getWebsite());
return restaurantRepository.save(existingRestaurant);
});
}
/**
* Supprime un restaurant par son identifiant.
* @param id L'identifiant du restaurant à supprimer.
*/
public void deleteRestaurant(Integer id) {
restaurantRepository.deleteById(id);
}
}

View file

@ -7,7 +7,8 @@ import org.springframework.boot.test.context.SpringBootTest;
class MangerAutourDeSimplonBackApplicationTests {
@Test
void testMain() {
MangerAutourDeSimplonBackApplication.main(new String[] {});
void contextLoads() {
// Ce test garantit que le contexte de l'application Spring peut démarrer avec
// succès.
}
}

View file

@ -0,0 +1,120 @@
package fr.vincent.ramiere.mangerautourdesimplonback.controller;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Restaurant;
import fr.vincent.ramiere.mangerautourdesimplonback.service.RestaurantService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class RestaurantControllerTest {
@Mock
private RestaurantService restaurantService;
@InjectMocks
private RestaurantController restaurantController;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void getAllRestaurants_shouldReturnListOfRestaurants() {
Restaurant r1 = new Restaurant();
Restaurant r2 = new Restaurant();
List<Restaurant> restaurants = Arrays.asList(r1, r2);
when(restaurantService.getAllRestaurants()).thenReturn(restaurants);
ResponseEntity<List<Restaurant>> response = restaurantController.getAllRestaurants();
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(restaurants, response.getBody());
}
@Test
void getRestaurantById_found_shouldReturnRestaurant() {
Restaurant restaurant = new Restaurant();
when(restaurantService.getRestaurantById(1)).thenReturn(Optional.of(restaurant));
ResponseEntity<Restaurant> response = restaurantController.getRestaurantById(1);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(restaurant, response.getBody());
}
@Test
void getRestaurantById_notFound_shouldReturnNotFound() {
when(restaurantService.getRestaurantById(1)).thenReturn(Optional.empty());
ResponseEntity<Restaurant> response = restaurantController.getRestaurantById(1);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertNull(response.getBody());
}
@Test
void createRestaurant_shouldReturnCreatedRestaurant() {
Restaurant restaurant = new Restaurant();
Restaurant savedRestaurant = new Restaurant();
when(restaurantService.saveRestaurant(restaurant)).thenReturn(savedRestaurant);
ResponseEntity<Restaurant> response = restaurantController.createRestaurant(restaurant);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
assertEquals(savedRestaurant, response.getBody());
}
@Test
void updateRestaurant_found_shouldReturnUpdatedRestaurant() {
Restaurant details = new Restaurant();
Restaurant updated = new Restaurant();
when(restaurantService.updateRestaurant(eq(1), any(Restaurant.class))).thenReturn(Optional.of(updated));
ResponseEntity<Restaurant> response = restaurantController.updateRestaurant(1, details);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(updated, response.getBody());
}
@Test
void updateRestaurant_notFound_shouldReturnNotFound() {
Restaurant details = new Restaurant();
when(restaurantService.updateRestaurant(eq(1), any(Restaurant.class))).thenReturn(Optional.empty());
ResponseEntity<Restaurant> response = restaurantController.updateRestaurant(1, details);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertNull(response.getBody());
}
@Test
void deleteRestaurant_found_shouldReturnNoContent() {
when(restaurantService.getRestaurantById(1)).thenReturn(Optional.of(new Restaurant()));
ResponseEntity<Void> response = restaurantController.deleteRestaurant(1);
assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
verify(restaurantService, times(1)).deleteRestaurant(1);
}
@Test
void deleteRestaurant_notFound_shouldReturnNotFound() {
when(restaurantService.getRestaurantById(1)).thenReturn(Optional.empty());
ResponseEntity<Void> response = restaurantController.deleteRestaurant(1);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
verify(restaurantService, never()).deleteRestaurant(anyInt());
}
}

View file

@ -9,5 +9,8 @@ class PersonneTest {
void testBuilder() {
Personne p = Personne.builder().nom("Test").prenom("Test").email("t@t.fr").password("1234").build();
assertEquals("Test", p.getNom());
assertEquals("Test", p.getPrenom());
assertEquals("t@t.fr", p.getEmail());
assertEquals("1234", p.getPassword());
}
}

View file

@ -0,0 +1,26 @@
package fr.vincent.ramiere.mangerautourdesimplonback.models;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class RestaurantTest {
@Test
void testBuilder() {
Restaurant r = Restaurant.builder().nom("Test").adresse("Adresse Test").telephone("0123456789").accesPMR(true)
.aEmporter(true)
.surPlace(false).prix(10).latitude("1.0").longitude("2.0").website("site-test.com").build();
assertEquals("Test", r.getNom());
assertEquals("Adresse Test", r.getAdresse());
assertEquals("0123456789", r.getTelephone());
assertTrue(r.getAccesPMR());
assertTrue(r.getAEmporter());
assertFalse(r.getSurPlace());
assertEquals(10, r.getPrix());
assertEquals("1.0", r.getLatitude());
assertEquals("2.0", r.getLongitude());
assertEquals("site-test.com", r.getWebsite());
}
}

View file

@ -0,0 +1,131 @@
package fr.vincent.ramiere.mangerautourdesimplonback.services;
import fr.vincent.ramiere.mangerautourdesimplonback.models.Restaurant;
import fr.vincent.ramiere.mangerautourdesimplonback.repository.RestaurantRepository;
import fr.vincent.ramiere.mangerautourdesimplonback.service.RestaurantService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
class RestaurantServiceTest {
@Mock
private RestaurantRepository restaurantRepository;
@InjectMocks
private RestaurantService restaurantService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void testGetAllRestaurants() {
Restaurant r1 = new Restaurant();
Restaurant r2 = new Restaurant();
when(restaurantRepository.findAll()).thenReturn(Arrays.asList(r1, r2));
List<Restaurant> result = restaurantService.getAllRestaurants();
assertEquals(2, result.size());
verify(restaurantRepository).findAll();
}
@Test
void testGetRestaurantById_Found() {
Restaurant r = new Restaurant();
r.setNom("Test");
when(restaurantRepository.findById(1)).thenReturn(Optional.of(r));
Optional<Restaurant> result = restaurantService.getRestaurantById(1);
assertTrue(result.isPresent());
assertEquals("Test", result.get().getNom());
verify(restaurantRepository).findById(1);
}
@Test
void testGetRestaurantById_NotFound() {
when(restaurantRepository.findById(2)).thenReturn(Optional.empty());
Optional<Restaurant> result = restaurantService.getRestaurantById(2);
assertFalse(result.isPresent());
verify(restaurantRepository).findById(2);
}
@Test
void testSaveRestaurant() {
Restaurant r = new Restaurant();
r.setNom("SaveTest");
when(restaurantRepository.save(r)).thenReturn(r);
Restaurant result = restaurantService.saveRestaurant(r);
assertEquals("SaveTest", result.getNom());
verify(restaurantRepository).save(r);
}
@Test
void testUpdateRestaurant_Found() {
Restaurant existing = new Restaurant();
existing.setNom("Old");
Restaurant details = new Restaurant();
details.setNom("New");
details.setAdresse("Adresse");
details.setTelephone("123");
details.setAccesPMR(true);
details.setAEmporter(true);
details.setSurPlace(false);
details.setPrix(10);
details.setLatitude("1.0");
details.setLongitude("2.0");
details.setWebsite("site");
when(restaurantRepository.findById(1)).thenReturn(Optional.of(existing));
when(restaurantRepository.save(any(Restaurant.class))).thenAnswer(invocation -> invocation.getArgument(0));
Optional<Restaurant> result = restaurantService.updateRestaurant(1, details);
assertTrue(result.isPresent());
Restaurant updatedRestaurant = result.get();
assertEquals("New", updatedRestaurant.getNom());
assertEquals("Adresse", updatedRestaurant.getAdresse());
assertEquals("123", updatedRestaurant.getTelephone());
assertTrue(updatedRestaurant.getAccesPMR());
assertTrue(updatedRestaurant.getAEmporter());
assertFalse(updatedRestaurant.getSurPlace());
assertEquals(10, updatedRestaurant.getPrix());
assertEquals("1.0", updatedRestaurant.getLatitude());
assertEquals("2.0", updatedRestaurant.getLongitude());
assertEquals("site", updatedRestaurant.getWebsite());
verify(restaurantRepository).findById(1);
verify(restaurantRepository).save(existing);
}
@Test
void testUpdateRestaurant_NotFound() {
Restaurant details = new Restaurant();
when(restaurantRepository.findById(99)).thenReturn(Optional.empty());
Optional<Restaurant> result = restaurantService.updateRestaurant(99, details);
assertFalse(result.isPresent());
verify(restaurantRepository).findById(99);
verify(restaurantRepository, never()).save(any());
}
@Test
void testDeleteRestaurant() {
restaurantService.deleteRestaurant(5);
verify(restaurantRepository).deleteById(5);
}
}