From 4b692806c470d5d5040e4cbeeccebdb69bce87c2 Mon Sep 17 00:00:00 2001 From: Vincent Guillet Date: Fri, 31 Oct 2025 18:33:19 +0100 Subject: [PATCH] add Platform and Brand DTOs, mappers, and controllers; update security configuration for CORS --- .../api/config/SecurityConfig.java | 38 +++++----- .../api/controller/app/BrandController.java | 15 ++-- .../controller/app/PlatformController.java | 61 ++++++++++++++++ .../api/controller/auth/AuthController.java | 2 - .../fr/gameovergne/api/dto/app/BrandDTO.java | 15 ++++ .../gameovergne/api/dto/app/PlatformDTO.java | 18 +++++ .../fr/gameovergne/api/dto/user/UserDTO.java | 1 - .../api/mapper/app/BrandMapper.java | 23 ++++++ .../api/mapper/app/PlatformMapper.java | 41 +++++++++++ .../api/mapper/user/UserMapper.java | 1 - .../fr/gameovergne/api/model/app/Brand.java | 4 +- .../gameovergne/api/model/app/Category.java | 4 +- .../fr/gameovergne/api/model/app/Image.java | 4 +- .../gameovergne/api/model/app/Platform.java | 5 +- .../fr/gameovergne/api/model/app/Product.java | 5 +- .../repository/app/PlatformRepository.java | 11 +++ .../api/service/app/BrandService.java | 17 ++++- .../api/service/app/PlatformService.java | 71 +++++++++++++++++++ api/src/main/resources/application.properties | 2 +- 19 files changed, 306 insertions(+), 32 deletions(-) create mode 100644 api/src/main/java/fr/gameovergne/api/controller/app/PlatformController.java create mode 100644 api/src/main/java/fr/gameovergne/api/dto/app/BrandDTO.java create mode 100644 api/src/main/java/fr/gameovergne/api/dto/app/PlatformDTO.java create mode 100644 api/src/main/java/fr/gameovergne/api/mapper/app/BrandMapper.java create mode 100644 api/src/main/java/fr/gameovergne/api/mapper/app/PlatformMapper.java create mode 100644 api/src/main/java/fr/gameovergne/api/repository/app/PlatformRepository.java create mode 100644 api/src/main/java/fr/gameovergne/api/service/app/PlatformService.java diff --git a/api/src/main/java/fr/gameovergne/api/config/SecurityConfig.java b/api/src/main/java/fr/gameovergne/api/config/SecurityConfig.java index ba2be6d..85fcab9 100644 --- a/api/src/main/java/fr/gameovergne/api/config/SecurityConfig.java +++ b/api/src/main/java/fr/gameovergne/api/config/SecurityConfig.java @@ -4,9 +4,11 @@ import fr.gameovergne.api.service.security.JpaUserDetailsService; import fr.gameovergne.api.service.security.filter.JwtAuthFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; 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; @@ -17,8 +19,10 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import java.util.Arrays; @Configuration @EnableWebSecurity @@ -36,35 +40,37 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http + .cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(authz -> authz + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // autoriser les preflight .requestMatchers("/api/auth/**").permitAll() .requestMatchers("/api/users/**").authenticated() - .requestMatchers("/api/brands/**").authenticated() + .requestMatchers("/api/brands/**").permitAll() + .requestMatchers("/api/platforms/**").permitAll() .anyRequest().permitAll() ) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider()) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) - .httpBasic(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable); + return http.build(); } @Bean - public WebMvcConfigurer corsConfigurer() { - return new WebMvcConfigurer() { - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOrigins("http://localhost:4200", "http://127.0.0.1:4200") - .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") - .allowedHeaders("*") - .allowCredentials(true); - } - }; + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowedOrigins(Arrays.asList("http://localhost:4200", "http://127.0.0.1:4200")); + config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS")); + config.setAllowedHeaders(Arrays.asList("Authorization","Content-Type","Accept")); + config.setExposedHeaders(Arrays.asList("Authorization")); + config.setAllowCredentials(true); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + return source; } @Bean diff --git a/api/src/main/java/fr/gameovergne/api/controller/app/BrandController.java b/api/src/main/java/fr/gameovergne/api/controller/app/BrandController.java index d3e9734..0a99ee6 100644 --- a/api/src/main/java/fr/gameovergne/api/controller/app/BrandController.java +++ b/api/src/main/java/fr/gameovergne/api/controller/app/BrandController.java @@ -1,8 +1,11 @@ package fr.gameovergne.api.controller.app; +import fr.gameovergne.api.dto.app.BrandDTO; +import fr.gameovergne.api.mapper.app.BrandMapper; import fr.gameovergne.api.model.app.Brand; import fr.gameovergne.api.service.app.BrandService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -13,10 +16,12 @@ import java.util.List; public class BrandController { private final BrandService brandService; + private final BrandMapper brandMapper; @Autowired - public BrandController(BrandService brandService) { + public BrandController(BrandService brandService, BrandMapper brandMapper) { this.brandService = brandService; + this.brandMapper = brandMapper; } @GetMapping @@ -32,12 +37,14 @@ public class BrandController { } @PostMapping - public void saveBrand(@RequestBody Brand brand) { - brandService.saveBrand(brand); + public void saveBrand(@RequestBody BrandDTO brandDTO) { + brandService.saveBrand(brandMapper.fromDto(brandDTO)); } @PutMapping("/{id}") - public ResponseEntity updateBrand(@PathVariable Long id, @RequestBody Brand brand) { + public ResponseEntity updateBrand(@PathVariable Long id, @RequestBody BrandDTO brandDTO) { + Brand brand = brandMapper.fromDto(brandDTO); + brand.setId(id); return brandService.getBrandById(id) .map(existingBrand -> brandService.updateBrand(brand) .map(ResponseEntity::ok) diff --git a/api/src/main/java/fr/gameovergne/api/controller/app/PlatformController.java b/api/src/main/java/fr/gameovergne/api/controller/app/PlatformController.java new file mode 100644 index 0000000..c6b8f26 --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/controller/app/PlatformController.java @@ -0,0 +1,61 @@ +package fr.gameovergne.api.controller.app; + +import fr.gameovergne.api.dto.app.PlatformDTO; +import fr.gameovergne.api.mapper.app.PlatformMapper; +import fr.gameovergne.api.model.app.Platform; +import fr.gameovergne.api.service.app.PlatformService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/platforms") +public class PlatformController { + + private final PlatformService platformService; + private final PlatformMapper platformMapper; + + public PlatformController(PlatformService platformService, PlatformMapper platformMapper) { + this.platformService = platformService; + this.platformMapper = platformMapper; + } + + @GetMapping + public List getAllPlatforms() { + return platformService.getAllPlatforms() + .stream() + .map(platformMapper::toDto) + .toList(); + } + + @GetMapping("/{id}") + public ResponseEntity getPlatformById(@PathVariable Long id) { + return platformService.getPlatformById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + @PostMapping + public void savePlatform(@RequestBody PlatformDTO platformDTO) { + platformService.savePlatform(platformMapper.fromDto(platformDTO)); + } + + @PutMapping("/{id}") + public ResponseEntity updatePlatform(@PathVariable Long id, @RequestBody PlatformDTO platformDTO) { + Platform platform = platformMapper.fromDto(platformDTO); + platform.setId(id); + return platformService.getPlatformById(id) + .map(existingPlatform -> platformService.updatePlatform(platform) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build())) + .orElse(ResponseEntity.notFound().build()); + } + + @DeleteMapping("/{id}") + public ResponseEntity deletePlatformById(@PathVariable Long id) { + return platformService.deletePlatformById(id) + .map(platform -> ResponseEntity.ok().body(platform)) + .orElse(ResponseEntity.notFound().build()); + } +} diff --git a/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java b/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java index 82d02f8..56bfb0a 100644 --- a/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java +++ b/api/src/main/java/fr/gameovergne/api/controller/auth/AuthController.java @@ -27,7 +27,6 @@ public class AuthController { @PostMapping("/register") public ResponseEntity register(@RequestBody UserDTO dto) { - System.out.println("Registering: " + dto); return authService.register(UserMapper.fromDto(dto)) .map((ResponseEntity::ok)) .orElse(ResponseEntity.badRequest().build()); @@ -35,7 +34,6 @@ public class AuthController { @PostMapping("/login") public ResponseEntity authenticate(@RequestBody AuthRequest request, HttpServletResponse response) { - System.out.println("Authenticating: " + request); return authService.authenticate(request) .map(authResponse -> createAuthResponse(authResponse, response)) .orElse(ResponseEntity.badRequest().build()); diff --git a/api/src/main/java/fr/gameovergne/api/dto/app/BrandDTO.java b/api/src/main/java/fr/gameovergne/api/dto/app/BrandDTO.java new file mode 100644 index 0000000..1092ce5 --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/dto/app/BrandDTO.java @@ -0,0 +1,15 @@ +package fr.gameovergne.api.dto.app; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BrandDTO { + + @JsonProperty("name") + private String name; +} diff --git a/api/src/main/java/fr/gameovergne/api/dto/app/PlatformDTO.java b/api/src/main/java/fr/gameovergne/api/dto/app/PlatformDTO.java new file mode 100644 index 0000000..1a66208 --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/dto/app/PlatformDTO.java @@ -0,0 +1,18 @@ +package fr.gameovergne.api.dto.app; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PlatformDTO { + + @JsonProperty("name") + private String name; + + @JsonProperty("brand") + private BrandDTO brandDTO; +} diff --git a/api/src/main/java/fr/gameovergne/api/dto/user/UserDTO.java b/api/src/main/java/fr/gameovergne/api/dto/user/UserDTO.java index e3a76e6..5a896ac 100644 --- a/api/src/main/java/fr/gameovergne/api/dto/user/UserDTO.java +++ b/api/src/main/java/fr/gameovergne/api/dto/user/UserDTO.java @@ -12,6 +12,5 @@ public class UserDTO { private String lastName; private String username; private String email; - private String password; // Note: In a real application, avoid sending passwords in DTOs private String role; } diff --git a/api/src/main/java/fr/gameovergne/api/mapper/app/BrandMapper.java b/api/src/main/java/fr/gameovergne/api/mapper/app/BrandMapper.java new file mode 100644 index 0000000..eebf800 --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/mapper/app/BrandMapper.java @@ -0,0 +1,23 @@ +package fr.gameovergne.api.mapper.app; + +import fr.gameovergne.api.dto.app.BrandDTO; +import fr.gameovergne.api.model.app.Brand; +import org.springframework.stereotype.Component; + +@Component +public class BrandMapper { + + public Brand fromDto(BrandDTO brandDTO) { + if (brandDTO == null) return null; + Brand brand = new Brand(); + brand.setName(brandDTO.getName()); + return brand; + } + + public BrandDTO toDto(Brand brand) { + if (brand == null) return null; + BrandDTO brandDTO = new BrandDTO(); + brandDTO.setName(brand.getName()); + return brandDTO; + } +} diff --git a/api/src/main/java/fr/gameovergne/api/mapper/app/PlatformMapper.java b/api/src/main/java/fr/gameovergne/api/mapper/app/PlatformMapper.java new file mode 100644 index 0000000..a2c386d --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/mapper/app/PlatformMapper.java @@ -0,0 +1,41 @@ +package fr.gameovergne.api.mapper.app; + +import fr.gameovergne.api.dto.app.BrandDTO; +import fr.gameovergne.api.dto.app.PlatformDTO; +import fr.gameovergne.api.model.app.Platform; +import fr.gameovergne.api.service.app.BrandService; +import org.springframework.stereotype.Component; + +@Component +public class PlatformMapper { + + private final BrandService brandService; + + public PlatformMapper(BrandService brandService) { + this.brandService = brandService; + } + + public Platform fromDto(PlatformDTO platformDTO) { + if (platformDTO == null) return null; + Platform platform = new Platform(); + platform.setName(platformDTO.getName()); + if (platformDTO.getBrandDTO() != null && platformDTO.getBrandDTO().getName() != null) { + platform.setBrand(this.brandService.getBrandByName(platformDTO.getBrandDTO().getName()).orElse(null)); + } else { + platform.setBrand(null); + } + return platform; + } + + public PlatformDTO toDto(Platform platform) { + if (platform == null) return null; + PlatformDTO platformDTO = new PlatformDTO(); + platformDTO.setName(platform.getName()); + if (platform.getBrand() != null) { + platformDTO.setBrandDTO(new BrandDTO(platform.getBrand().getName())); + } else { + platformDTO.setBrandDTO(null); + } + return platformDTO; + } +} diff --git a/api/src/main/java/fr/gameovergne/api/mapper/user/UserMapper.java b/api/src/main/java/fr/gameovergne/api/mapper/user/UserMapper.java index 0aba25d..69e03e8 100644 --- a/api/src/main/java/fr/gameovergne/api/mapper/user/UserMapper.java +++ b/api/src/main/java/fr/gameovergne/api/mapper/user/UserMapper.java @@ -12,7 +12,6 @@ public class UserMapper { user.setLastName(userDTO.getLastName()); user.setUsername(userDTO.getUsername()); user.setEmail(userDTO.getEmail()); - user.setPassword(userDTO.getPassword()); user.setRole(Role.valueOf(userDTO.getRole() != null ? userDTO.getRole() : "USER")); return user; } diff --git a/api/src/main/java/fr/gameovergne/api/model/app/Brand.java b/api/src/main/java/fr/gameovergne/api/model/app/Brand.java index fb9bc75..9ec4e1e 100644 --- a/api/src/main/java/fr/gameovergne/api/model/app/Brand.java +++ b/api/src/main/java/fr/gameovergne/api/model/app/Brand.java @@ -1,6 +1,8 @@ package fr.gameovergne.api.model.app; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; @@ -13,6 +15,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "brands") public class Brand { @@ -25,6 +28,5 @@ public class Brand { private String name; @OneToMany(mappedBy = "brand", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference private List platforms; } diff --git a/api/src/main/java/fr/gameovergne/api/model/app/Category.java b/api/src/main/java/fr/gameovergne/api/model/app/Category.java index 7c3133a..21d044c 100644 --- a/api/src/main/java/fr/gameovergne/api/model/app/Category.java +++ b/api/src/main/java/fr/gameovergne/api/model/app/Category.java @@ -1,6 +1,8 @@ package fr.gameovergne.api.model.app; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; @@ -14,6 +16,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "categories") public class Category { @@ -26,6 +29,5 @@ public class Category { private String name; @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference private List products; } diff --git a/api/src/main/java/fr/gameovergne/api/model/app/Image.java b/api/src/main/java/fr/gameovergne/api/model/app/Image.java index 18b5f1e..fb72e45 100644 --- a/api/src/main/java/fr/gameovergne/api/model/app/Image.java +++ b/api/src/main/java/fr/gameovergne/api/model/app/Image.java @@ -1,6 +1,8 @@ package fr.gameovergne.api.model.app; import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import fr.gameovergne.api.model.user.User; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; @@ -14,6 +16,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "images") public class Image { @@ -35,7 +38,6 @@ public class Image { joinColumns = @JoinColumn(name = "image_id"), inverseJoinColumns = @JoinColumn(name = "user_id") ) - @JsonBackReference private List users; @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}) diff --git a/api/src/main/java/fr/gameovergne/api/model/app/Platform.java b/api/src/main/java/fr/gameovergne/api/model/app/Platform.java index d3ab8bf..d8926e2 100644 --- a/api/src/main/java/fr/gameovergne/api/model/app/Platform.java +++ b/api/src/main/java/fr/gameovergne/api/model/app/Platform.java @@ -1,6 +1,9 @@ package fr.gameovergne.api.model.app; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonManagedReference; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; @@ -13,6 +16,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "platforms") public class Platform { @@ -29,6 +33,5 @@ public class Platform { private Brand brand; @OneToMany(mappedBy = "platform", cascade = CascadeType.ALL, orphanRemoval = true) - @JsonManagedReference private List products; } diff --git a/api/src/main/java/fr/gameovergne/api/model/app/Product.java b/api/src/main/java/fr/gameovergne/api/model/app/Product.java index 1fb9f83..2534547 100644 --- a/api/src/main/java/fr/gameovergne/api/model/app/Product.java +++ b/api/src/main/java/fr/gameovergne/api/model/app/Product.java @@ -1,6 +1,8 @@ package fr.gameovergne.api.model.app; import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -15,6 +17,7 @@ import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Table(name = "products") public class Product { @@ -39,12 +42,10 @@ public class Product { @ManyToOne @JoinColumn(name = "category_id") - @JsonBackReference private Category category; @ManyToOne @JoinColumn(name = "platform_id") - @JsonBackReference private Platform platform; @NotNull diff --git a/api/src/main/java/fr/gameovergne/api/repository/app/PlatformRepository.java b/api/src/main/java/fr/gameovergne/api/repository/app/PlatformRepository.java new file mode 100644 index 0000000..5e58792 --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/repository/app/PlatformRepository.java @@ -0,0 +1,11 @@ +package fr.gameovergne.api.repository.app; + +import fr.gameovergne.api.model.app.Platform; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface PlatformRepository extends JpaRepository { + Optional findById(Long id); + Optional findByName(String name); +} diff --git a/api/src/main/java/fr/gameovergne/api/service/app/BrandService.java b/api/src/main/java/fr/gameovergne/api/service/app/BrandService.java index f8008ef..c19a8b9 100644 --- a/api/src/main/java/fr/gameovergne/api/service/app/BrandService.java +++ b/api/src/main/java/fr/gameovergne/api/service/app/BrandService.java @@ -1,11 +1,13 @@ package fr.gameovergne.api.service.app; import fr.gameovergne.api.model.app.Brand; +import fr.gameovergne.api.model.app.Platform; import fr.gameovergne.api.repository.app.BrandRepository; import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -42,7 +44,20 @@ public class BrandService { public Optional updateBrand(Brand brand) { return brandRepository.findById(brand.getId()).map(existingBrand -> { existingBrand.setName(brand.getName()); - existingBrand.setPlatforms(brand.getPlatforms()); + + List newPlatforms = brand.getPlatforms(); + if (newPlatforms != null) { + if (existingBrand.getPlatforms() == null) { + existingBrand.setPlatforms(new ArrayList<>()); + } else { + existingBrand.getPlatforms().clear(); + } + for (Platform p : newPlatforms) { + p.setBrand(existingBrand); + existingBrand.getPlatforms().add(p); + } + } + return brandRepository.save(existingBrand); }); } diff --git a/api/src/main/java/fr/gameovergne/api/service/app/PlatformService.java b/api/src/main/java/fr/gameovergne/api/service/app/PlatformService.java new file mode 100644 index 0000000..0a7bb2d --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/service/app/PlatformService.java @@ -0,0 +1,71 @@ +package fr.gameovergne.api.service.app; + +import fr.gameovergne.api.model.app.Platform; +import fr.gameovergne.api.model.app.Product; +import fr.gameovergne.api.repository.app.PlatformRepository; +import jakarta.transaction.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +public class PlatformService { + + private final PlatformRepository platformRepository; + + @Autowired + public PlatformService(PlatformRepository platformRepository) { + this.platformRepository = platformRepository; + } + + @Transactional + public void savePlatform(Platform platform) { + if (platform.getId() == null) { + platformRepository.save(platform); + } + } + + public List getAllPlatforms() { + return platformRepository.findAll(); + } + + public Optional getPlatformById(Long id) { + return platformRepository.findById(id); + } + + public Optional getPlatformByName(String name) { + return platformRepository.findByName(name); + } + + @Transactional + public Optional updatePlatform(Platform platform) { + return platformRepository.findById(platform.getId()).map(existingPlatform -> { + existingPlatform.setName(platform.getName()); + existingPlatform.setBrand(platform.getBrand()); + List newProducts = platform.getProducts(); + if (newProducts != null) { + if (existingPlatform.getProducts() == null) { + existingPlatform.setProducts(new ArrayList<>()); + } else { + existingPlatform.getProducts().clear(); + } + for (Product p : newProducts) { + p.setPlatform(existingPlatform); + existingPlatform.getProducts().add(p); + } + } + + return platformRepository.save(existingPlatform); + }); + } + + @Transactional + public Optional deletePlatformById(Long id) { + Optional platform = platformRepository.findById(id); + platform.ifPresent(platformRepository::delete); + return platform; + } +} diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index bffd692..4a85a12 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.application.name=api server.port=3000 -spring.datasource.url=jdbc:mysql://192.168.20.112:3306/gameovergne_app?useSSL=false&allowPublicKeyRetrieval=true +spring.datasource.url=jdbc:mysql://localhost:3306/gameovergne_app?useSSL=false&allowPublicKeyRetrieval=true spring.datasource.username=gameovergne spring.datasource.password=gameovergne