Resolved conflict
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
package net.gepafin.tendermanagement.util;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3URI;
|
||||
import com.amazonaws.services.s3.model.S3Object;
|
||||
import net.gepafin.tendermanagement.model.request.AttachmentRequest;
|
||||
import org.apache.poi.xwpf.usermodel.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.Base64;
|
||||
|
||||
public class S3DocxProcessor {
|
||||
|
||||
private final AmazonS3 s3Client;
|
||||
|
||||
public static final Logger log = LoggerFactory.getLogger(S3DocxProcessor.class);
|
||||
|
||||
|
||||
public S3DocxProcessor(AmazonS3 s3Client) {
|
||||
this.s3Client = s3Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches DOCX files from S3, replaces placeholders, and returns updated files
|
||||
* as AttachmentRequest objects (ready for PEC API).
|
||||
*
|
||||
* @param s3Urls List of S3 file URLs
|
||||
* @param replacements Map of placeholder -> value
|
||||
* @return Map of original file name -> AttachmentRequest
|
||||
* @throws IOException
|
||||
*/
|
||||
public Map<String, AttachmentRequest> processFiles(List<String> s3Urls,
|
||||
Map<String, String> replacements) throws IOException {
|
||||
Map<String, AttachmentRequest> processedFiles = new HashMap<>();
|
||||
|
||||
for (String s3Url : s3Urls) {
|
||||
// Extract bucket & key from URL
|
||||
AmazonS3URI s3Uri = new AmazonS3URI(s3Url);
|
||||
String bucket = s3Uri.getBucket();
|
||||
String key = s3Uri.getKey();
|
||||
try (S3Object s3Object = s3Client.getObject(bucket, key);
|
||||
InputStream originalStream = new BufferedInputStream(s3Object.getObjectContent())) {
|
||||
byte[] updatedBytes=null;
|
||||
if (isDocxFile(originalStream)) {
|
||||
log.warn("Skipping non-DOCX file from S3: bucket={}, key={}", bucket, key);
|
||||
updatedBytes = replacePlaceholders(originalStream, replacements);
|
||||
}else {
|
||||
// non-DOCX → just copy raw stream
|
||||
updatedBytes = originalStream.readAllBytes();
|
||||
log.info("Skipped placeholder replacement, copied file as-is: {}", key);
|
||||
}
|
||||
|
||||
// convert to base64
|
||||
String base64 = Base64.getEncoder().encodeToString(updatedBytes);
|
||||
String fileString = "data:application/octet-stream;base64," + base64;
|
||||
|
||||
// create attachment request
|
||||
AttachmentRequest attachment = new AttachmentRequest();
|
||||
attachment.setName(extractFileName(key));
|
||||
attachment.setFile(fileString);
|
||||
|
||||
processedFiles.put(key, attachment);
|
||||
}
|
||||
}
|
||||
|
||||
return processedFiles;
|
||||
}
|
||||
|
||||
|
||||
private byte[] replacePlaceholders(InputStream docInputStream,
|
||||
Map<String, String> replacements) throws IOException {
|
||||
try (XWPFDocument document = new XWPFDocument(docInputStream);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
|
||||
// replace in body paragraphs
|
||||
replaceInParagraphs(document.getParagraphs(), replacements);
|
||||
|
||||
// replace inside tables
|
||||
for (XWPFTable table : document.getTables()) {
|
||||
for (XWPFTableRow row : table.getRows()) {
|
||||
for (XWPFTableCell cell : row.getTableCells()) {
|
||||
replaceInParagraphs(cell.getParagraphs(), replacements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.write(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceInParagraphs(List<XWPFParagraph> paragraphs, Map<String, String> replacements) {
|
||||
for (XWPFParagraph paragraph : paragraphs) {
|
||||
String paragraphText = paragraph.getText();
|
||||
|
||||
if (paragraphText != null && !paragraphText.isEmpty()) {
|
||||
// Apply all replacements
|
||||
for (Map.Entry<String, String> entry : replacements.entrySet()) {
|
||||
paragraphText = paragraphText.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// Remove old runs
|
||||
int runCount = paragraph.getRuns().size();
|
||||
for (int i = runCount - 1; i >= 0; i--) {
|
||||
paragraph.removeRun(i);
|
||||
}
|
||||
|
||||
// Add one new run with replaced text
|
||||
XWPFRun newRun = paragraph.createRun();
|
||||
newRun.setText(paragraphText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String extractFileName(String key) {
|
||||
int lastSlash = key.lastIndexOf('/');
|
||||
if (lastSlash >= 0 && lastSlash < key.length() - 1) {
|
||||
return key.substring(lastSlash + 1);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private boolean isDocxFile(InputStream inputStream) throws IOException {
|
||||
inputStream.mark(4);
|
||||
byte[] header = new byte[2];
|
||||
int read = inputStream.read(header, 0, 2);
|
||||
inputStream.reset();
|
||||
|
||||
// DOCX = ZIP = should start with PK (0x50 0x4B)
|
||||
return read == 2 && header[0] == 0x50 && header[1] == 0x4B;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user