diff --git a/api/src/main/java/fr/gameovergne/api/config/PrestashopProperties.java b/api/src/main/java/fr/gameovergne/api/config/PrestashopProperties.java new file mode 100644 index 0000000..da083ca --- /dev/null +++ b/api/src/main/java/fr/gameovergne/api/config/PrestashopProperties.java @@ -0,0 +1,13 @@ +package fr.gameovergne.api.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "prestashop") +@Getter +@Setter +public class PrestashopProperties { + private String baseUrl; + private String apiKey; +} \ No newline at end of file diff --git a/api/src/main/java/fr/gameovergne/api/controller/PrestashopProxyController.java b/api/src/main/java/fr/gameovergne/api/controller/PrestashopProxyController.java index 9905740..7f7f50c 100644 --- a/api/src/main/java/fr/gameovergne/api/controller/PrestashopProxyController.java +++ b/api/src/main/java/fr/gameovergne/api/controller/PrestashopProxyController.java @@ -1,95 +1,48 @@ -package fr.gameovergne.api.controller; +package fr.gameovergne.api.controller;// package fr.gameovergne.api.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import fr.gameovergne.api.service.PrestashopClient; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; + +import java.util.Map; +import java.util.stream.Collectors; @RestController -@RequestMapping("/api/ps") +@RequestMapping("/prestashop") +@RequiredArgsConstructor public class PrestashopProxyController { private final PrestashopClient prestashopClient; - public PrestashopProxyController(PrestashopClient prestashopClient) { - this.prestashopClient = prestashopClient; + @GetMapping("/categories") + public String getCategories(@RequestParam Map params) { + String query = buildQuery(params); + return prestashopClient.get("/categories" + query); } - // ---------- utilitaire pour extraire le path Presta ---------- + @GetMapping("/manufacturers") + public String getManufacturers(@RequestParam Map params) { + String query = buildQuery(params); + return prestashopClient.get("/manufacturers" + query); + } - private String extractPrestaPath(HttpServletRequest request) { - // Traefik strip déjà /gameovergne-api, donc Spring voit /api/ps/... - String uri = request.getRequestURI(); // ex: /api/ps/categories - String prefix = "/api/ps"; - String path = uri.startsWith(prefix) ? uri.substring(prefix.length()) : uri; - if (path.isEmpty()) { - path = "/"; + @GetMapping("/suppliers") + public String getSuppliers(@RequestParam Map params) { + String query = buildQuery(params); + return prestashopClient.get("/suppliers" + query); + } + + private String buildQuery(Map params) { + if (params == null || params.isEmpty()) { + return ""; } - return path; - } - - // ---------- GET : /api/ps/** -> Presta GET ---------- - - @GetMapping("/**") - public ResponseEntity proxyGet(HttpServletRequest request) { - String path = extractPrestaPath(request); // ex: "/categories" - String query = request.getQueryString(); // ex: "display=[id,name]&output_format=JSON" - - String body = prestashopClient.get(path, query); - - // Presta renvoie du JSON (output_format=JSON), donc on force application/json - return ResponseEntity - .ok() - .contentType(MediaType.APPLICATION_JSON) - .body(body); - } - - // ---------- POST : /api/ps/** -> Presta POST ---------- - - @PostMapping("/**") - public ResponseEntity proxyPost(HttpServletRequest request, - @RequestBody(required = false) String xmlBody) { - String path = extractPrestaPath(request); - String query = request.getQueryString(); - - String responseBody = prestashopClient.post(path, query, xmlBody != null ? xmlBody : ""); - - // Les POST/PUT/DELETE Presta renvoient typiquement de l’XML - return ResponseEntity - .ok() - .contentType(MediaType.APPLICATION_XML) - .body(responseBody); - } - - // ---------- PUT : /api/ps/** -> Presta PUT ---------- - - @PutMapping("/**") - public ResponseEntity proxyPut(HttpServletRequest request, - @RequestBody(required = false) String xmlBody) { - String path = extractPrestaPath(request); - String query = request.getQueryString(); - - String responseBody = prestashopClient.put(path, query, xmlBody != null ? xmlBody : ""); - - return ResponseEntity - .ok() - .contentType(MediaType.APPLICATION_XML) - .body(responseBody); - } - - // ---------- DELETE : /api/ps/** -> Presta DELETE ---------- - - @DeleteMapping("/**") - public ResponseEntity proxyDelete(HttpServletRequest request) { - String path = extractPrestaPath(request); - String query = request.getQueryString(); - - String responseBody = prestashopClient.delete(path, query); - - return ResponseEntity - .ok() - .contentType(MediaType.APPLICATION_XML) - .body(responseBody); + String queryString = params.entrySet().stream() + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining("&")); + return "?" + queryString; } } \ No newline at end of file diff --git a/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java b/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java index cd56372..e79680e 100644 --- a/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java +++ b/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java @@ -1,186 +1,70 @@ package fr.gameovergne.api.service; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.*; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -import java.util.List; +@Slf4j @Service public class PrestashopClient { - private static final Logger log = LoggerFactory.getLogger(PrestashopClient.class); - - private final RestTemplate restTemplate = new RestTemplate(); + private final RestTemplate restTemplate; private final String baseUrl; - private final String basicAuth; // base64 SANS le "Basic " public PrestashopClient( @Value("${prestashop.base-url}") String baseUrl, - @Value("${prestashop.basic-auth}") String basicAuth + @Value("${prestashop.api-key}") String rawApiKey, + RestTemplateBuilder builder ) { + // Normalisation baseUrl (pas de / final) + if (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + } this.baseUrl = baseUrl; - this.basicAuth = basicAuth; - } - // ========== GET ========== + String apiKey = rawApiKey == null ? null : rawApiKey.trim(); + + if (apiKey == null || apiKey.isBlank()) { + throw new IllegalStateException( + "PrestaShop API key is null/blank (prestashop.api-key)." + ); + } + + // Logs pour contrôle visuel + log.info("[PrestaShop] API key length = {}", apiKey.length()); + log.info("[PrestaShop] API key prefix = {}****", apiKey.substring(0, 4)); + + // IMPORTANT : Basic Auth = username = clé, password = vide + this.restTemplate = builder + .basicAuthentication(apiKey, "") + .build(); + } /** - * @param path ex: "/categories", "/products/12" - * @param rawQuery ex: "display=[id,name]&output_format=JSON&filter[active]=1", ou null + * Appel simple GET PrestaShop. + * Exemple d'appel depuis le controller : + * client.get("/categories?display=[id,name,active]&output_format=JSON"); */ - public String get(String path, String rawQuery) { - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl) - .path("/api") - .path(path); + public String get(String pathAndQuery) { + String url; - if (rawQuery != null && !rawQuery.isBlank()) { - // On laisse le caller (notre proxy / Angular via Spring) décider des paramètres - builder.query(rawQuery); + // On accepte soit un chemin relatif, soit une URL complète (au cas où) + if (pathAndQuery.startsWith("http://") || pathAndQuery.startsWith("https://")) { + url = pathAndQuery; + } else if (pathAndQuery.startsWith("/")) { + url = baseUrl + pathAndQuery; } else { - // fallback par défaut si aucun paramètre reçu - builder - .queryParam("output_format", "JSON") - .queryParam("display", "full"); + url = baseUrl + "/" + pathAndQuery; } - String url = builder.build(true).toUriString(); log.info("[PrestaShop] GET {}", url); - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - - HttpEntity entity = new HttpEntity<>(headers); - - ResponseEntity response = restTemplate.exchange( - url, - HttpMethod.GET, - entity, - String.class - ); - - log.info("[PrestaShop] Réponse GET {} pour {}", response.getStatusCode(), url); - - if (!response.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("PrestaShop returned non-2xx status: " - + response.getStatusCode() + " for URL " + url); - } - - return response.getBody(); - } - - // ========== POST ========== - public String post(String path, String query, String xmlBody) { - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl) - .path("/api") - .path(path); - - if (query != null && !query.isBlank()) { - builder.query(query); - } - - String url = builder.build(true).toUriString(); - log.info("[PrestaShop] POST {}", url); - - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - headers.setContentType(MediaType.APPLICATION_XML); // XML obligatoire - headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - - HttpEntity entity = new HttpEntity<>(xmlBody, headers); - - ResponseEntity response = restTemplate.exchange( - url, - HttpMethod.POST, - entity, - String.class - ); - log.info("[PrestaShop] Réponse POST {} pour {}", response.getStatusCode(), url); - - if (!response.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("PrestaShop returned non-2xx status: " - + response.getStatusCode() + " for URL " + url); - } - - return response.getBody(); - } - - // ========== PUT ========== - public String put(String path, String query, String xmlBody) { - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl) - .path("/api") - .path(path); - - if (query != null && !query.isBlank()) { - builder.query(query); - } - - String url = builder.build(true).toUriString(); - log.info("[PrestaShop] PUT {}", url); - - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - headers.setContentType(MediaType.APPLICATION_XML); - headers.setAccept(List.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)); - - HttpEntity entity = new HttpEntity<>(xmlBody, headers); - - ResponseEntity response = restTemplate.exchange( - url, - HttpMethod.PUT, - entity, - String.class - ); - log.info("[PrestaShop] Réponse PUT {} pour {}", response.getStatusCode(), url); - - if (!response.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("PrestaShop returned non-2xx status: " - + response.getStatusCode() + " for URL " + url); - } - - return response.getBody(); - } - - // ========== DELETE ========== - public String delete(String path, String query) { - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl) - .path("/api") - .path(path); - - if (query != null && !query.isBlank()) { - builder.query(query); - } - - String url = builder.build(true).toUriString(); - log.info("[PrestaShop] DELETE {}", url); - - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - - HttpEntity entity = new HttpEntity<>(headers); - - ResponseEntity response = restTemplate.exchange( - url, - HttpMethod.DELETE, - entity, - String.class - ); - log.info("[PrestaShop] Réponse DELETE {} pour {}", response.getStatusCode(), url); - - if (!response.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("PrestaShop returned non-2xx status: " - + response.getStatusCode() + " for URL " + url); - } - - return response.getBody(); + return restTemplate + .exchange(url, HttpMethod.GET, HttpEntity.EMPTY, String.class) + .getBody(); } } \ No newline at end of file diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index 5387071..1fd482a 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -13,5 +13,4 @@ spring.jpa.show-sql=true jwt.secret=a23ac96ce968bf13099d99410b951dd498118851bdfc996a3f844bd68b1b2afd prestashop.base-url=https://shop.gameovergne.fr -prestashop.basic-auth=2AQPG13MJ8X117U6FJ5NGHPS93HE34AB -#prestashop.basic-auth=Basic MkFRUEcxM01KOFgxMTdVNkZKNU5HSFBTOTNIRTM0QUI= \ No newline at end of file +prestashop.api-key=${PRESTASHOP_API_KEY} \ No newline at end of file