From 28faf2ed2b31e09ffdacc1ac1aac0e13c3742b5a Mon Sep 17 00:00:00 2001 From: Vincent Guillet Date: Tue, 2 Dec 2025 16:28:27 +0100 Subject: [PATCH] Refactor PrestashopClient to improve URI building and parameter encoding --- .../api/service/PrestashopClient.java | 92 ++++++++++++------- 1 file changed, 60 insertions(+), 32 deletions(-) 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 86b2b7a..c7524f6 100644 --- a/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java +++ b/api/src/main/java/fr/gameovergne/api/service/PrestashopClient.java @@ -7,10 +7,11 @@ import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; -import org.springframework.web.util.UriComponentsBuilder; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.Base64; +import java.util.List; +import java.util.Map; @Service @Slf4j @@ -25,7 +26,7 @@ public class PrestashopClient { ) { this.baseUrl = baseUrl; - String basicAuth = Base64.getEncoder() + String basicAuth = java.util.Base64.getEncoder() .encodeToString((apiKey + ":").getBytes(StandardCharsets.UTF_8)); this.client = RestClient.builder() @@ -36,16 +37,64 @@ public class PrestashopClient { log.info("[PrestaShop] API key length = {}", apiKey.length()); } + /** + * Construit l’URL complète en encodant proprement les query params + * (y compris les crochets utilisés par PrestaShop : [id,name,...]). + */ private String buildUri(String path, MultiValueMap params) { - UriComponentsBuilder builder = UriComponentsBuilder - .fromHttpUrl(baseUrl + path); - if (params != null && !params.isEmpty()) { - builder.queryParams(params); - } - return builder.build(true).toUriString(); - } + StringBuilder sb = new StringBuilder(); - // -------- Méthodes "typed" JSON / XML utilisées par ps-admin -------- + // baseUrl (ex: https://shop.gameovergne.fr/api) + sb.append(baseUrl); + + // path (on gère proprement le /) + if (path != null && !path.isEmpty()) { + if (path.charAt(0) == '/') { + sb.append(path); + } else { + sb.append('/').append(path); + } + } + + // query params + if (params != null && !params.isEmpty()) { + boolean first = true; + + for (Map.Entry> entry : params.entrySet()) { + String key = entry.getKey(); + List values = entry.getValue(); + + if (values == null || values.isEmpty()) { + continue; + } + + // encode la clé + String encodedKey = URLEncoder.encode(key, StandardCharsets.UTF_8); + + for (String rawValue : values) { + if (first) { + sb.append('?'); + first = false; + } else { + sb.append('&'); + } + + // encode la valeur (crochets, %, espaces, etc.) + String encodedValue = rawValue == null + ? "" + : URLEncoder.encode(rawValue, StandardCharsets.UTF_8); + + sb.append(encodedKey) + .append('=') + .append(encodedValue); + } + } + } + + String finalUri = sb.toString(); + log.info("[PrestaShop] built URI = {}", finalUri); + return finalUri; + } public String getJson(String path, MultiValueMap params) { String uri = buildUri(path, params); @@ -97,25 +146,4 @@ public class PrestashopClient { .retrieve() .toBodilessEntity(); } - - // -------- Méthode générique utilisée par le proxy /api/ps/** -------- - - /** - * Proxy brut : on lui donne le path Presta (ex: "/categories") et la query string déjà encodée. - * On récupère un ResponseEntity pour pouvoir propager le status code. - */ - public ResponseEntity getWithRawQuery(String path, String rawQuery) { - String uri = baseUrl + path; - if (rawQuery != null && !rawQuery.isBlank()) { - uri = uri + "?" + rawQuery; - } - - log.info("[PrestaShop] GET (proxy) {}", uri); - - return client.get() - .uri(uri) - .accept(MediaType.APPLICATION_JSON) - .retrieve() - .toEntity(String.class); - } } \ No newline at end of file