package net.gepafin.tendermanagement.service.impl; import com.amazonaws.AmazonServiceException; import com.amazonaws.SdkClientException; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import lombok.extern.slf4j.Slf4j; import net.gepafin.tendermanagement.dao.S3PathConfig; import net.gepafin.tendermanagement.entities.DocumentEntity; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.repositories.ApplicationRepository; import net.gepafin.tendermanagement.repositories.ApplicationSignedDocumentRepository; import net.gepafin.tendermanagement.repositories.DocumentRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; @Slf4j @Service public class S3ReUploadMigrationService { private static final String OLD_BUCKET = "mementoresources"; private static final String SECURE_KEY = "267163962963"; @Autowired private DocumentRepository documentRepository; @Autowired private AmazonS3Client s3Client; @Autowired private S3PathConfig s3ConfigBean; @Autowired private ApplicationRepository applicationRepository; @Autowired private ApplicationSignedDocumentRepository applicationSignedDocumentRepository; @Autowired private AmazonS3 amazonS3; @Value("${aws.s3.url}") private String s3Url; private boolean migrationCompleted = false; public String reUploadAndMigrateDocuments(String providedKey) { if (migrationCompleted) { return "Migration already completed."; } // Validate the provided key if (!isValidKey(providedKey)) { return "Invalid or missing migration key."; } List documents = documentRepository.findAllByIsDeleteFalse(); if (documents.isEmpty()) { return "No documents found to migrate."; } for (DocumentEntity document : documents) { String oldUrl = document.getFilePath(); // This should contain the full URL log.info("Processing {}", oldUrl); try { File localFile = downloadFileFromS3(oldUrl); String newKey = generateNewS3Path(document); // Make sure this generates the correct new path String uploadedPath = uploadFileToNewBucket(localFile, newKey); updateDocumentPathAndNameEntry(document, uploadedPath); } catch (Exception e) { log.error("Error processing document {}: {}", document.getId(), e.getMessage()); } } return "Migrated Successfully."; } private boolean isValidKey(String providedKey) { return providedKey != null && providedKey.equals(SECURE_KEY); } private File downloadFileFromS3(String fileUrl) throws Exception { String key = extractS3KeyFromUrl(fileUrl); // Get the S3 key from the URL File localFile = new File("/tmp/" + extractFileName(key)); // Save file locally GetObjectRequest getObjectRequest = new GetObjectRequest(OLD_BUCKET, key); // Use the key try (InputStream s3Stream = s3Client.getObject(getObjectRequest).getObjectContent(); FileOutputStream outputStream = new FileOutputStream(localFile)) { s3Stream.transferTo(outputStream); } log.info("Downloaded file from old S3 bucket: {}", key); return localFile; } private String extractS3KeyFromUrl(String url) { // Assuming the URL structure is consistent return url.replace("https://mementoresources.s3.eu-west-1.amazonaws.com/", ""); } private String uploadFileToNewBucket(File localFile, String s3Folder) { InputStream inputStream = null; // Declare the InputStream here for cleanup try { // Extract file name from the local file String fileName = extractFileName(localFile.getAbsolutePath()); // Get the file name String path = s3Folder + "/" + fileName; // Construct the S3 path // Create InputStream from the local file inputStream = new FileInputStream(localFile); // Set up object metadata ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType("application/octet-stream"); objectMetadata.setContentLength(localFile.length()); // Upload to S3 s3Client.putObject(OLD_BUCKET, path, inputStream, objectMetadata); // Construct the full S3 URL String fullUrl = String.format("https://%s.s3.%s.amazonaws.com/%s", OLD_BUCKET, "eu-west-1", path); log.info("File '{}' uploaded successfully to Amazon S3 with URL: {}", fileName, fullUrl); return fullUrl; } catch (IOException e) { log.error("IOException occurred during file upload for '{}': {}", localFile.getName(), e.getMessage()); throw new RuntimeException("Upload failed for: " + s3Folder + "/" + localFile.getName(), e); } catch (AmazonServiceException e) { log.error("Amazon service exception while uploading file '{}': {}", localFile.getName(), e.getMessage()); throw new RuntimeException("Upload failed for: " + s3Folder + "/" + localFile.getName(), e); } catch (SdkClientException e) { log.error("SDK client exception while uploading file '{}': {}", localFile.getName(), e.getMessage()); throw new RuntimeException("Upload failed for: " + s3Folder + "/" + localFile.getName(), e); } finally { // Close InputStream if it was opened if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { log.warn("Failed to close InputStream for file '{}': {}", localFile.getName(), e.getMessage()); } } } } private String generateNewS3Path(DocumentEntity document) { DocumentSourceTypeEnum sourceType = DocumentSourceTypeEnum.valueOf(document.getSource()); Long callId; if (sourceType.equals(DocumentSourceTypeEnum.CALL)) { return s3ConfigBean.generateDocumentPath(sourceType, document.getSourceId(), 0L); } else { callId = applicationRepository.findCallIdById(document.getSourceId()); return s3ConfigBean.generateDocumentPath(sourceType, callId, document.getSourceId()); } } private String extractFileName(String filePath) { String[] parts = filePath.split("/"); return parts[parts.length - 1]; } private void updateDocumentPathAndNameEntry(DocumentEntity document, String newPath) { String fileName = extractFileName(newPath); document.setFilePath(newPath); document.setFileName(fileName); documentRepository.save(document); log.info("Migrated document ID: {} to new path: {}", document.getId(), newPath); } }