public with sharing class AWSS3Feature extends CloudStorageBase { private static String SERVER_URL = System.Label.Ngrok; public override OperationResult listFiles(Map params) { List> resultFiles = new List>(); try { String endpoint = SERVER_URL + '/api/v1/s3/all'; System.debug('Endpoint: ' + endpoint); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); Map payload = (Map) params.get('payload'); String key = (String) params.get('key'); // String requestBody = '{"aws": ' + JSON.serialize(payload) + ', "key": '+ key + '}'; Map body = new Map(); body.put('aws', payload); body.put('key', key); String requestBody = JSON.serialize(body); System.debug('requestBody: ' + requestBody); Map headers = new Map{ 'Content-Type' => 'application/json' }; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'POST'); System.debug('Status Code: ' + res.getStatusCode()); System.debug('Response Body: ' + res.getBody()); if(res.getStatusCode() == 200) { System.debug('response body: '+ res.getBody()); List fileList = (List) JSON.deserializeUntyped(res.getBody()); processItems(fileList, resultFiles); } else { System.debug('response body after fail: '+ res.getBody()); System.debug('S3 call failed!'); return OperationResult.error('Someting went wrong'); } } catch (Exception e) { throw new AuraHandledException('Exception: ' + e.getMessage()); } System.debug('Final resultFiles: ' + JSON.serializePretty(resultFiles)); return OperationResult.success(resultFiles); } @AuraEnabled public static OperationResult storeAwsS3Credentials(Boolean isAdminCred, Map payload){ try { System.debug('method in AWS S3 for token store'); String userId = SalesforceEnvironmentUtil.getUserId(); String accessKey = (String) payload.get('accessKey'); String secretAccessKey = (String) payload.get('secretAccessKey'); String region = (String) payload.get('region'); String bucketName = (String) payload.get('bucketName'); Map tokenMap = new Map(); tokenMap.put('HIC_FilesME__Auth_Provider_Name__c', 'AwsS3'); // tokenMap.put('HIC_FilesME__External_Storage_Type__c', 'AwsS3'); //added tokenMap.put('HIC_FilesME__Provider__c', 'AwsS3'); tokenMap.put('HIC_FilesME__Access_Key__c', accessKey); tokenMap.put('HIC_FilesME__Secret_Access_Key__c', secretAccessKey); tokenMap.put('HIC_FilesME__Region__c', region); tokenMap.put('HIC_FilesME__Bucket__c', bucketName); tokenMap.put('HIC_FilesME__Is_Admin_level_Credentials__c', isAdminCred); tokenMap.put('HIC_FilesME__User__c', userId); Map body = new Map(); body.put('aws', payload); body.put('key', ''); String requestBody = JSON.serialize(body); System.debug('requestBody: ' + requestBody); Map headers = new Map{ 'Content-Type' => 'application/json' }; String endpoint = SERVER_URL + '/api/v1/s3/all'; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'POST'); if(res.getStatusCode() == 200){ System.debug('Storing token'); OAuthTokenManager.storeToken(tokenMap); List record = [ SELECT id FROM HIC_FilesME__External_Token__c WHERE HIC_FilesME__Is_Admin_level_Credentials__c = :isAdminCred AND HIC_FilesME__Provider__c = 'AwsS3' ]; System.debug('record size-> '+ record.size()); if(record != null && record.size() > 0) { return OperationResult.success('Credentials stored'); } else { return OperationResult.error('Credentials not stored'); } } else { System.debug('Invalid credentials'); return OperationResult.error('Invalid credentials'); } } catch(Exception e){ throw new AuraHandledException('Exception occoured: '+ e.getMessage()); } } private static void processItems(List items, List> resultFiles) { for (Object item : items) { Map fileMap = (Map) item; String id = (String) fileMap.get('name'); String name = (String) fileMap.get('name'); name = name.removeEnd('/'); List nameSplit = name.split('/'); name = nameSplit[nameSplit.size()-1]; String type = (String) fileMap.get('type'); Boolean isFolder = type != null && type.toLowerCase() == 'folder'; String iconName = (String) fileMap.get('value'); if(iconName == null && isFolder){ iconName = 'doctype:folder'; } Map fileData = new Map{ 'id' => id, 'path' => id, 'name' => name, 'type' => type, 'iconName' => iconName, 'mimeType' => iconName, 'isFolder' => String.valueOf(isFolder) }; resultFiles.add(fileData); if (isFolder && fileMap.containsKey('children')) { List children = (List) fileMap.get('children'); if (children != null && !children.isEmpty()) { processItems(children, resultFiles); } } } } //to delete public override OperationResult deleteFile(Map params) { try { System.debug('>>>entered deleteFile SFTP'); String key = (String) params.get('fileId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); Map payload = (Map) params.get('payload'); Map body = new Map(); body.put('aws', payload); body.put('key', key); String requestBody = JSON.serialize(body); String endpoint = SERVER_URL + '/api/v1/s3'; System.debug('Create Request Body: ' + requestBody); Map headers = new Map{ 'Content-Type' => 'application/json', 'accept' => '*/*' }; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'DELETE'); System.debug('>>>res=' + res.getBody()); System.debug('>>>res.getStatusCode()=' + res.getStatusCode()); if (res.getStatusCode() == 200 || res.getStatusCode() == 204) { return OperationResult.success(res.getBody()); } else { return OperationResult.error(res.getBody()); } } catch (Exception e) { System.debug('>>>error=' + e.getMessage()); throw new AuraHandledException(e.getMessage()); } } //to create public override OperationResult createFolder(Map params) { Map resultMap = new Map(); System.debug('Inside createFolder'); try { String parentFolderId = (String) params.get('parentFolderId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String folderName = (String) params.get('folderName'); String key = (String) params.get('key'); Map payload = (Map) params.get('payload'); Map body = new Map(); body.put('aws', payload); body.put('key', key); String encodedFolderName = EncodingUtil.urlEncode(folderName, 'UTF-8'); String endpoint = SERVER_URL + '/api/v1/s3/' + folderName; System.debug('Create Request Body: ' + JSON.serializePretty(body)); String requestBody = JSON.Serialize(body); Map headers = new Map{ 'Content-Type' => 'application/json', 'accept' => '*/*' }; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'POST'); System.debug('>>>res=' + res.getBody()); System.debug('>>>res.getStatusCode()=' + res.getStatusCode()); if (res.getStatusCode() != 200 && res.getStatusCode() != 201) { return OperationResult.error('Error: ' + res.getStatusCode() + ' - ' + res.getBody()); } String responseBody = res.getBody(); // if(res.getBody() != null){ // resultMap = (Map) JSON.deserializeUntyped(responseBody); // } resultMap.put('code', '200'); System.debug('>>>resultMap=' + resultMap); return OperationResult.success(resultMap); } catch (Exception e) { throw new AuraHandledException('AWS S3 Folder Creation Failed: ' + e.getMessage()); } } //rename public override OperationResult renameFile(Map params) { Map resultMap = new Map(); System.debug('Inside renameFolder'); try { String fileId = (String) params.get('fileId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String newFileName = (String) params.get('newFileName'); Map payload = (Map) params.get('payload'); String endpoint = SERVER_URL + '/api/v1/s3/rename'; if(fileId.endsWith('/')){ fileId = fileId.substring(0, fileId.length() - 1); } if(newFileName.endsWith('/')){ newFileName = newFileName.substring(0, newFileName.length() - 1); } Map body = new Map(); body.put('aws', payload); body.put('oldName', fileId); body.put('newName', newFileName); String requestBody = JSON.serialize(body); System.debug('Rename Request Body: ' + requestBody); Map headers = new Map{ 'Content-Type' => 'application/json', 'accept' => '*/*' }; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'POST'); if (res.getStatusCode() != 200) { return OperationResult.error('Error: ' + res.getStatusCode() + ' - ' + res.getBody()); } String responseBody = res.getBody(); resultMap = (Map) JSON.deserializeUntyped(responseBody); resultMap.put('code', '200'); return OperationResult.success(resultMap); } catch (Exception e) { throw new AuraHandledException('SFTP Folder Rename Failed: ' + e.getMessage()); } } public override OperationResult moveFileAndFolder(Map params) { Map resultMap = new Map(); System.debug('Inside moveFileAndFolder'); try { Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String sourceKey = (String) params.get('oldFolderId'); String destinationKey = (String) params.get('newFolderId'); Map payload = (Map) params.get('payload'); String endpoint = SERVER_URL + '/api/v1/s3/move'; Map body = new Map(); body.put('aws', payload); body.put('sourceKey', sourceKey); body.put('destinationKey', destinationKey); body.put('overwrite', true); String requestBody = JSON.serialize(body); System.debug('Move Request Body: ' + requestBody); Map headers = new Map{ 'Content-Type' => 'application/json', 'accept' => '*/*' }; HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, endpoint, headers, 'POST'); if (res.getStatusCode() != 200) { return OperationResult.error('Error: ' + res.getStatusCode() + ' - ' + res.getBody()); } String responseBody = res.getBody(); resultMap = (Map) JSON.deserializeUntyped(responseBody); resultMap.put('code', '200'); return OperationResult.success(resultMap); } catch (Exception e) { throw new AuraHandledException('SFTP Folder Move Failed: ' + e.getMessage()); } } // download public override OperationResult downloadFile(Map params) { System.debug('AWSS3Feature.downloadFile'); OperationResult result; try { Blob fileBlob = fetchFileAndConvertToBase64(params); if (fileBlob != null) { result = OperationResult.success(EncodingUtil.base64Encode(fileBlob)); System.debug('File downloaded successfully.'); } else { result = OperationResult.error('Failed to download file'); } } catch (Exception e) { result = OperationResult.error('Error downloading file: ' + e.getMessage()); FME_Logger.error(e.getMessage(), 'AWSS3Feature' + e.getLineNumber(), 'downloadFile'); } return result; } public static Blob fetchFileAndConvertToBase64(Map params) { Blob fileBlob; try { Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String fileId = (String) params.get('fileId'); String accessToken = (String) params.get('accessToken'); String userId = (String) SalesforceEnvironmentUtil.getUserId(); Map payload = (Map) params.get('payload'); // 2. AWS S3 download endpoint String downloadUrl = SERVER_URL + '/api/v1/s3/download'; Map headers = new Map{ 'Content-Type' => 'application/json', 'accept' => '*/*' }; Map body = new Map { 'aws'=> payload, 'key'=> fileId }; String requestBody = JSON.serialize(body); // 3. Download file HttpResponse res = CloudStorageUtlilty.makeCallout(requestBody, downloadUrl, headers, 'POST'); // 5. Success if (res.getStatusCode() == 200) { fileBlob = res.getBodyAsBlob(); } else { System.debug('AWS S3 download failed: ' + res.getStatusCode() + ' | ' + res.getBody()); } } catch (Exception e) { System.debug( 'Error in fetchFileAndConvertToBase64: ' + e.getMessage() + ' | Line: ' + e.getLineNumber() ); FME_Logger.error( e.getMessage(), 'AWSS3Feature' + e.getLineNumber(), 'fetchFileAndConvertToBase64' ); } return fileBlob; } public override OperationResult linkFiles(String recordId) { List> resultFolders = new List>(); try { List linkedFolders = [ SELECT Id,Name,CreatedDate,CreatedBy.Name,HIC_FilesME__External_Folder_ID__c, HIC_FilesME__Folder_Name__c, HIC_FilesME__Folder_URL__c, HIC_FilesME__Storage_Provider__c, HIC_FilesME__Access_Level__c, HIC_FilesME__Connected_Username__c FROM HIC_FilesME__Linked_Folder__c WHERE HIC_FilesME__Linked_Record__c = :recordId AND HIC_FilesME__Is_Active__c = true ]; for (HIC_FilesME__Linked_Folder__c folder : linkedFolders) { Map folderData = new Map(); folderData.put('id', folder.HIC_FilesME__External_Folder_ID__c); folderData.put('recordId', folder.Id); folderData.put('name', folder.HIC_FilesME__Folder_Name__c); folderData.put('externalStorageType', folder.HIC_FilesME__Storage_Provider__c); folderData.put('accessLevel', folder.HIC_FilesME__Access_Level__c); folderData.put('createdTime', String.valueOf(folder.CreatedDate)); folderData.put('createdBy', folder.CreatedBy != null ? folder.CreatedBy.Name : '-'); folderData.put('linkedBy', folder.HIC_FilesME__Connected_Username__c); folderData.put('url', folder.HIC_FilesME__Folder_URL__c); resultFolders.add(folderData); } System.debug('resultFolders >>>> ' + resultFolders); return OperationResult.success(resultFolders); } catch (Exception e) {FME_Logger.error(e.getMessage(),'LinkedFolderFeature' + e.getLineNumber(),'linkFiles'); return OperationResult.error('Failed to fetch linked folders. ' + e.getMessage()); } } public override OperationResult toLinkFiles(String recordId,String folderDetails,String providerType) { try { System.debug('providerType >>>> ' + providerType); System.debug('recordId >>>> ' + recordId); System.debug('JSON.deserializeUntyped folderDetails >>>> ' + JSON.deserializeUntyped(folderDetails)); Map folderMap = (Map) JSON.deserializeUntyped(folderDetails); HIC_FilesME__Linked_Folder__c linkedFolder = new HIC_FilesME__Linked_Folder__c(); linkedFolder.HIC_FilesME__Linked_Record__c = recordId; linkedFolder.HIC_FilesME__External_Folder_ID__c = (String) folderMap.get('id'); linkedFolder.HIC_FilesME__Folder_Name__c = (String) folderMap.get('name'); //add linkedFolder.HIC_FilesME__Created__c = UserInfo.getUserId(); linkedFolder.HIC_FilesME__Created_Date__c = System.now(); linkedFolder.HIC_FilesME__Connected_Username__c = (String) folderMap.get('linkedBy'); linkedFolder.HIC_FilesME__Folder_URL__c = (String) folderMap.get('url'); linkedFolder.HIC_FilesME__Storage_Provider__c = providerType; // linkedFolder.HIC_FilesME__Access_Level__c = (String) folderMap.get('accessLevel'); linkedFolder.HIC_FilesME__Is_Active__c = true; String key = providerType +' '+ recordId +' '+ (String) folderMap.get('id'); linkedFolder.HIC_FilesME__Key__c = key; upsert linkedFolder HIC_FilesME__Key__c; // insert linkedFolder; System.debug('linkedFolder >>>> ' + linkedFolder); return OperationResult.success(linkedFolder); } catch (Exception e) { FME_Logger.error(e.getMessage(),'LinkedFolderFeature' + e.getLineNumber(),'toLinkFiles' ); return OperationResult.error('Error linking folder: ' + e.getMessage()); } } public override OperationResult unlinkFiles(String recordId, String filesId, Boolean deleteFromDrive) { System.debug('recordId >>>> ' + recordId); System.debug('filesId >>>> ' + filesId); System.debug('deleteFromDrive >>>> ' + deleteFromDrive); OperationResult result; try { List fileLinks = [SELECT Id FROM HIC_FilesME__Linked_Folder__c WHERE HIC_FilesME__Linked_Record__c = :recordId AND HIC_FilesME__External_Folder_ID__c = :filesId]; if (fileLinks.size() > 0) { delete fileLinks; // if (deleteFromDrive) { // deleteFile(filesId, true, null); // } result = OperationResult.success(null); } else { result = OperationResult.error('No record found'); } } catch (Exception e) { result = OperationResult.error('Error unlinking file: ' + e.getMessage()); FME_Logger.error(e.getMessage(), 'AWSS3Feature' + e.getLineNumber(), 'unlinkFiles'); } return result; } //send email public override OperationResult emailFile(Map params) { OperationResult result; try { //maildetails Map mailDetails =(Map) JSON.deserializeUntyped(JSON.serialize(params.get('mailDetails'))); String fileId = (String) params.get('fileId'); String fileName = (String) params.get('fileName'); String mimeType = (String) params.get('toSendFileNameMimeType'); String senderId = (String) mailDetails.get('fromUser'); String toUser = (String) mailDetails.get('toUser'); String ccUser = (String) mailDetails.get('ccUser'); String bccUser = (String) mailDetails.get('bccUser'); String subject = (String) mailDetails.get('subject'); String body = (String) mailDetails.get('body'); Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); // Required mail.setToAddresses(new List{ toUser }); // Optional if (String.isNotBlank(ccUser)) mail.setCcAddresses(new List{ ccUser }); if (String.isNotBlank(bccUser)) mail.setBccAddresses(new List{ bccUser }); mail.setSubject(subject); // Remove HTML tags safely mail.setPlainTextBody(body != null ? body.replaceAll('<[^>]+>', '') : ''); if (String.isNotBlank(senderId) && senderId.startsWith('0D2')) { mail.setOrgWideEmailAddressId(senderId); } Map downloadParams = new Map(params); downloadParams.put('fileId', fileId); downloadParams.put('fileName', fileName); OperationResult op = downloadFile(downloadParams); if (op != null && op.data != null) { Blob fileBlob = EncodingUtil.base64Decode((String) op.data); Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment(); attachment.setFileName(fileName); attachment.setBody(fileBlob); attachment.setContentType(String.isNotBlank(mimeType) ? mimeType: 'application/octet-stream'); mail.setFileAttachments(new List{ attachment }); } Messaging.SendEmailResult[] results = Messaging.sendEmail( new List{ mail }); if (!results.isEmpty() && results[0].isSuccess()) { result = OperationResult.success(null); System.debug(' Email sent successfully'); } else { String errMsg = (!results.isEmpty() && results[0].getErrors().size() > 0)? results[0].getErrors()[0].getMessage(): 'Unknown send failure'; result = OperationResult.error(errMsg); } } catch (Exception e) { FME_Logger.error(e.getMessage(),'EmailFeature ' + e.getLineNumber(),'emailFile'); result = OperationResult.error('Error sending email: ' + e.getMessage()); } System.debug('result:' + result); return result; } }