diff --git a/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java b/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java
index 32fec53..a06fe03 100644
--- a/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java
+++ b/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java
@@ -2,21 +2,22 @@ package fr.gameovergne.api.service.prestashop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.io.ByteArrayResource;
-import org.springframework.http.*;
-import org.springframework.http.client.MultipartBodyBuilder;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
-import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;
-import java.io.IOException;
+import java.io.*;
+import java.net.HttpURLConnection;
import java.net.URI;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@@ -232,8 +233,6 @@ public class PrestashopClient {
/**
* Upload d'une image produit vers PrestaShop :
* POST /api/images/products/{productId}
- *
- * On envoie directement les bytes du fichier avec le bon content-type (image/jpeg, image/png, ...).
*/
public ResponseEntity uploadProductImage(
@@ -242,7 +241,7 @@ public class PrestashopClient {
MultipartFile imageFile
) {
try {
- // Construire l’URL Presta
+ // Construire l’URL Presta (comme avant)
StringBuilder urlBuilder = new StringBuilder(baseUrl)
.append("/images/products/")
.append(productId);
@@ -252,7 +251,7 @@ public class PrestashopClient {
}
String url = urlBuilder.toString();
- byte[] bytes = imageFile.getBytes();
+ byte[] fileBytes = imageFile.getBytes();
String originalFilename = imageFile.getOriginalFilename();
if (originalFilename == null || originalFilename.isBlank()) {
@@ -261,42 +260,86 @@ public class PrestashopClient {
String contentType = imageFile.getContentType();
if (contentType == null || contentType.isBlank()) {
- contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
+ contentType = "application/octet-stream";
}
log.info(
- "[PrestaShop] POST (image multipart) {} (size={} bytes, contentType={}, filename={})",
- url, bytes.length, contentType, originalFilename
+ "[PrestaShop] POST (image multipart - manual) {} (size={} bytes, contentType={}, filename={})",
+ url, fileBytes.length, contentType, originalFilename
);
- // Resource avec filename pour que PHP le traite comme un fichier dans $_FILES["image"]
- String finalOriginalFilename = originalFilename;
- ByteArrayResource imageResource = new ByteArrayResource(bytes) {
- @Override
- public String getFilename() {
- return finalOriginalFilename;
+ // -------- Construction du multipart "à la main" --------
+ String boundary = "----PrestashopBoundary" + System.currentTimeMillis();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.UTF_8);
+ PrintWriter writer = new PrintWriter(osw, true);
+
+ // Début de la part "image"
+ writer.append("--").append(boundary).append("\r\n");
+ writer.append("Content-Disposition: form-data; name=\"image\"; filename=\"")
+ .append(originalFilename)
+ .append("\"\r\n");
+ writer.append("Content-Type: ").append(contentType).append("\r\n");
+ writer.append("\r\n");
+ writer.flush();
+
+ // Données binaires du fichier
+ baos.write(fileBytes);
+ baos.write("\r\n".getBytes(StandardCharsets.UTF_8));
+
+ // Fin du multipart
+ writer.append("--").append(boundary).append("--").append("\r\n");
+ writer.flush();
+
+ byte[] multipartBytes = baos.toByteArray();
+
+ // -------- Envoi via HttpURLConnection --------
+ URL targetUrl = URI.create(url).toURL();
+ HttpURLConnection conn = (HttpURLConnection) targetUrl.openConnection();
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+ conn.setRequestProperty("Accept", "application/xml, text/xml, */*;q=0.1");
+
+ // Important : pas de chunked, on envoie une taille fixe
+ conn.setFixedLengthStreamingMode(multipartBytes.length);
+
+ try (OutputStream os = conn.getOutputStream()) {
+ os.write(multipartBytes);
+ }
+
+ int status = conn.getResponseCode();
+
+ InputStream is = (status >= 200 && status < 300)
+ ? conn.getInputStream()
+ : conn.getErrorStream();
+
+ String responseBody;
+ if (is != null) {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+ StringBuilder sb = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ responseBody = sb.toString();
}
+ } else {
+ responseBody = "";
+ }
- @Override
- public long contentLength() {
- return bytes.length;
- }
- };
+ log.info("[PrestaShop] Image upload response status={}, body={}", status, responseBody);
- // body multipart : la clé "image" => part nommée "image"
- MultiValueMap body = new LinkedMultiValueMap<>();
- body.add("image", imageResource);
+ HttpStatus springStatus = HttpStatus.resolve(status);
+ if (springStatus == null) {
+ springStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+ }
- return client.post()
- .uri(URI.create(url))
- .contentType(MediaType.MULTIPART_FORM_DATA)
- .body(body)
- .retrieve()
- .toEntity(String.class);
+ return new ResponseEntity<>(responseBody, springStatus);
} catch (IOException e) {
- log.error("[PrestaShop] Erreur lecture fichier image", e);
- throw new RuntimeException("Erreur lors de la lecture du fichier image", e);
+ log.error("[PrestaShop] Erreur lors de l'upload d'image", e);
+ throw new RuntimeException("Erreur lors de l'upload d'image vers PrestaShop", e);
}
}
}
\ No newline at end of file