function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ForceRookieForceRookie 

How to upload attachments from SF to AWS?

The scenario is, if Opportunity is Closed Won in Custom Settings, and if the Opportunity will meet the condition, the process will move the Attachments from this record to the AWS and will be deleted from this record.
The files should be uploaded from this path in AWS -- Opportunity/Salesforce Id/Secret Files/filename
Please help me improve my code here:
global class UploadAttachments implements Database.Batchable<sObject> {
	
	global Database.QueryLocator start(Database.BatchableContext BC) {
        String csname = 'OpportunityClosedWon';
		String query = 'SELECT Id, Objects__c, Fields__c, Field_Value__c FROM ForUploadCustomSettings__c WHERE Name = :csname';
		return Database.getQueryLocator(query);
	}

   	global void execute(Database.BatchableContext BC, List<Opportunity> scope) {
        String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z');   
		String host = 's3.amazonaws.com/';
        String method = 'PUT';
        
        HttpRequest req = new HttpRequest();
		Http http = new Http();
        
        Set<Id> Ids = new Set<Id>();
        for (Opportunity opp : [SELECT Id, Name FROM Opportunity WHERE IsClosed = true AND IsWon = true]) {
            Ids.add(opp.Id);
        }
		List<Attachment> att = [SELECT Id, Name, Body, ContentType FROM Attachment WHERE ParentId IN :Ids];
        
        List<AWScredentialsSettings__c> values = [SELECT Id, ClientKey__c, SecretKey__c, BucketName__c FROM AWScredentialsSettings__c LIMIT 1];
        if (!att.isEmpty() && !values.isEmpty()) {
			String bucketname = values[0].BucketName__c;
			String key = values[0].ClientKey__c;
			String secret = values[0].SecretKey__c;
        	String attachmentBody = EncodingUtil.base64Encode(att[0].Body);
            String filename = att[0].Name;
            
            req.setMethod(method);
            req.setEndpoint('https://' + host + bucketname + '/' + filename); // The file should be uploaded to this path in AWS -- Opportunity/Salesforce Id/Secret Files/filename
            req.setHeader('Content-Length', String.valueOf(attachmentBody.length()));
            req.setHeader('Content-Encoding', 'UTF-8');
            req.setHeader('Content-type', att[0].ContentType);
            req.setHeader('Connection', 'keep-alive');
            req.setHeader('Date', formattedDateString);
            req.setHeader('ACL', 'public-read');
            req.setBody(attachmentBody);
            
            String stringToSign = method+'\n\n\n'+ att[0].ContentType + '\n' + formattedDateString +'\n/'+ bucketname +'/' + filename;
            Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
            String signed  = EncodingUtil.base64Encode(mac);
            String authHeader = 'AWS' + ' ' + secret + ':' + signed;
            req.setHeader('Authorization',authHeader);
        }
        
        HTTPResponse res = http.send(req);
        System.debug('*Resp:' + String.ValueOF(res.getBody()));
        System.debug('RESPONSE STRING: ' + res.toString());
        System.debug('RESPONSE STATUS: ' + res.getStatus());
        System.debug('STATUS_CODE: ' + res.getStatusCode());
	}
	
	global void finish(Database.BatchableContext BC) {
		
	}
	
}