public with sharing class BoxFeature extends CloudStorageBase { private static final String BOX_API_URL = 'https://api.box.com/2.0'; private static String externalStorage = 'Box'; //List Done // public override OperationResult listFiles(Boolean isServiceMode,Boolean myDrive,String userId,Boolean isRootFolder,String folderId,String accessToken,String level) { public override OperationResult listFiles(Map params) { List> resultFiles = new List>(); OperationResult result; List fileIdList = new list(); try { Boolean isServiceMode = (Boolean) params.get('isServiceMode'); Boolean myDrive = (Boolean) params.get('myDrive'); Boolean isRootFolder = (Boolean) params.get('isRootFolder'); String folderId = (String) params.get('folderId'); String accessToken = (String) params.get('accessToken'); String level = (String) params.get('level'); System.debug('isServiceMode ' + isServiceMode); System.debug('accessToken ' + accessToken); System.debug('--Folder ID-- ' + folderId); // Normalize folderId for Box API if (folderId != null) { if (folderId.startsWith('folder:')) { folderId = folderId.replace('folder:', ''); } else if (folderId.startsWith('file:')) { folderId = folderId.replace('file:', ''); } } // Box root folder is always 0 at root level String boxFolderId; if ((folderId == null || folderId == '') && isRootFolder) { boxFolderId = '0'; } else { boxFolderId = folderId; } System.debug('boxFolderId ' + boxFolderId); // Endpoint String endpoint = BOX_API_URL +'/folders/' + boxFolderId + '/items?fields=id,name,type,created_at,created_by'; Map header = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Content-Type' => 'application/json' }; System.debug('endpoint=' + endpoint); HttpResponse res = CloudStorageUtlilty.makeCallout(null, endpoint, header, 'GET'); System.debug('api status ' + res.getStatusCode()); System.debug('body ' + res.getBody()); // Success if (res.getStatusCode() == 200) { Map resultMap = (Map) JSON.deserializeUntyped(res.getBody()); List entries = (List) resultMap.get('entries'); //Loop to get the fileid to find out tag data for (Object file : entries) { Map fileDetails = (Map) file; fileIdList.add((String) fileDetails.get('id')); } Map> fileIdVsTagListMap = new map>(); for(HIC_FilesME__Tags_Data__c tag :[select id,HIC_FilesME__Tags__c,HIC_FilesME__FileId__c from HIC_FilesME__Tags_Data__c where HIC_FilesME__FileId__c in:fileIdList AND HIC_FilesME__Tags__c != null]){ for(String tagValue : tag.HIC_FilesME__Tags__c.split(';')){ if(fileIdVsTagListMap.containsKey(tag.HIC_FilesME__FileId__c)){ List taglist = fileIdVsTagListMap.get(tag.HIC_FilesME__FileId__c); taglist.add(tagValue); fileIdVsTagListMap.put(tag.HIC_FilesME__FileId__c,taglist); }else{ List taglist = new list(); taglist.add(tagValue); fileIdVsTagListMap.put(tag.HIC_FilesME__FileId__c,taglist); } } } for (Object obj : entries) { Map fileDetails = (Map) obj; Map fileData = new Map(); String fileId = (String) fileDetails.get('id'); String type = (String) fileDetails.get('type'); if(fileIdVsTagListMap.containsKey(fileId)){ fileData.put('tagData',fileIdVsTagListMap.get(fileId)); }else{ fileData.put('tagData',new list()); } String rawId = (String) fileDetails.get('id'); fileData.put('id', rawId); fileData.put('name', (String) fileDetails.get('name')); // fileData.put('mimeType', type); fileData.put('mimeType', type == 'folder' ? 'folder' : 'file'); // Created Date if (fileDetails.containsKey('created_at')) { fileData.put( 'createdTime',(String) fileDetails.get('created_at')); } else { fileData.put('createdTime', '-'); } // Created By if (fileDetails.containsKey('created_by')) { Map createdBy = (Map) fileDetails.get('created_by'); if (createdBy != null) { fileData.put('createdBy',(String) createdBy.get('name')); } } // Parent (Box does not return parents array) fileData.put('parents', boxFolderId); // Path display (Box doesn’t provide full path directly) fileData.put('path_display', null); if (type == 'folder') { fileData.put('mimeType', 'doctype:folder'); fileData.put('url', 'https://app.box.com/folder/' + rawId); } else { fileData.put('mimeType', 'doctype:unknown'); fileData.put('url', 'https://app.box.com/file/' + rawId); } resultFiles.add(fileData); } System.debug('>>>>resultFiles=' + resultFiles); result = OperationResult.success(resultFiles); } else { return OperationResult.error('Failed to list Box files.'); } return result; } catch (Exception e) { System.debug('Error occurred: ' + e.getMessage()); FME_Logger.error('Error in listing Box files: ' + e.getMessage(),'BoxFeature','listFiles'); return OperationResult.error(e.getMessage()); } } //List Linkfiles Done // change custom object -- linkedFolder 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 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('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()); } } //To Link Done // change custom object -- linkedFolder 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__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()); } } // Create Done public override OperationResult createFolder(Map params) { Map resultMap = new Map(); String refreshToken; OperationResult result; try { String parentFolderId = (String) params.get('parentFolderId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String folderName = (String) params.get('folderName'); String userId = (String) SalesforceEnvironmentUtil.getUserId(); String accessToken = (String) params.get('accessToken'); // Normalize parentFolderId System.debug('Raw parentFolderId ---> ' + parentFolderId); if (parentFolderId != null) { if (parentFolderId.startsWith('folder:')) { parentFolderId = parentFolderId.replace('folder:', ''); } else if (parentFolderId.startsWith('file:')) { parentFolderId = parentFolderId.replace('file:', ''); } } // Box root folder ID is always "0" String boxParentFolderId = (String.isBlank(parentFolderId)) ? '0' : parentFolderId; System.debug('Normalized boxParentFolderId ---> ' + boxParentFolderId); // Request Body String folderMetadata = JSON.serialize(new Map{ 'name' => folderName, 'parent' => new Map{ 'id' => boxParentFolderId } }); // Headers Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Content-Type' => 'application/json' }; String endpoint = 'https://api.box.com/2.0/folders'; HttpResponse res = CloudStorageUtlilty.makeCallout(folderMetadata,endpoint,headers,'POST'); System.debug('Create Folder STATUS ---> ' + res.getStatusCode()); System.debug('Create Folder BODY ---> ' + res.getBody()); if (res.getStatusCode() == 201) { resultMap = (Map) JSON.deserializeUntyped(res.getBody()); resultMap.put('code', '201'); result = OperationResult.success(resultMap); } else { result = OperationResult.error('Failed to create Box folder: ' + res.getBody()); } } catch (Exception e) { FME_Logger.error(e.getMessage(),'BoxFeature:' + e.getLineNumber(),'createFolder'); result = OperationResult.error( 'Error creating Box folder: ' + e.getMessage() ); } System.debug('createFolder result ---> ' + result); return result; } //Delete Done // public override OperationResult deleteFile(Map params) { // try { // String fileId = (String) params.get('fileId'); // Boolean isServiceMode = (Boolean) params.get('isServiceMode'); // String accessToken = (String) params.get('accessToken'); // String type = (String) params.get('type'); // String userId = SalesforceEnvironmentUtil.getUserId(); // if (String.isBlank(fileId)) { // return OperationResult.error('FileId is required'); // } // String endpoint; // if (type.containsIgnoreCase('file')) { // endpoint = 'https://api.box.com/2.0/files/' + fileId; // } else if (type.containsIgnoreCase('folder')) { // endpoint = 'https://api.box.com/2.0/folders/' + fileId + '?recursive=true'; // } else { // return OperationResult.error('Unsupported Box item type'); // } // Map headers = new Map{ // 'Authorization' => 'Bearer ' + accessToken // }; // HttpResponse res = CloudStorageUtlilty.makeCallout(null, endpoint, headers, 'DELETE'); // if (res.getStatusCode() == 204) { // return OperationResult.success('Deleted successfully'); // } else { // return OperationResult.error(res.getBody()); // } // } catch (Exception e) { // FME_Logger.error( // e.getMessage(), // 'BoxFeature.deleteFile line ' + e.getLineNumber(), // 'deleteFile' // ); // return OperationResult.error( // 'Error deleting Box item: ' + e.getMessage() // ); // } // } //changes public override OperationResult deleteFile(Map params) { try { String fileId = (String) params.get('fileId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String accessToken = (String) params.get('accessToken'); Boolean isFolder = (Boolean) params.get('isFolder'); String userId = SalesforceEnvironmentUtil.getUserId(); System.debug('>>>fileId=' + fileId); System.debug('>>>isServiceMode=' + isServiceMode); System.debug('>>>accessToken=' + accessToken); System.debug('>>>isFolder=' + isFolder); System.debug('>>>userId=' + userId); // System.debug('>>>type=' + params); if (String.isBlank(fileId)) { return OperationResult.error('FileId is required'); } if (isFolder == null) { return OperationResult.error('Item type is required'); } if (String.isBlank(accessToken)) { return OperationResult.error('Access token is missing'); } String endpoint; if (isFolder) { endpoint = 'https://api.box.com/2.0/folders/' + fileId + '?recursive=true'; } else { endpoint = 'https://api.box.com/2.0/files/' + fileId; } Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken }; HttpResponse res = CloudStorageUtlilty.makeCallout(null, endpoint, headers, 'DELETE'); if (res.getStatusCode() == 204) { return OperationResult.success('Deleted successfully'); } else { return OperationResult.error(res.getBody()); } } catch (Exception e) { FME_Logger.error( e.getMessage(), 'BoxFeature.deleteFile line ' + e.getLineNumber(), 'deleteFile' ); return OperationResult.error( 'Error deleting Box item: ' + e.getMessage() ); } } //Rename Done public override OperationResult renameFile(Map params) { OperationResult result; try { String fileId = (String) params.get('fileId'); String type = (String) params.get('type'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String newFileName = (String) params.get('newFileName'); String accessToken = (String) params.get('accessToken'); if (String.isBlank(fileId) || String.isBlank(newFileName)) { return OperationResult.error('FileId and newFileName are required'); } String endpoint; if (type.containsIgnoreCase('file')) { endpoint = 'https://api.box.com/2.0/files/' + fileId; } else if (type.containsIgnoreCase('folder')) { endpoint = 'https://api.box.com/2.0/folders/' + fileId; } else { return OperationResult.error('Unsupported Box item type'); } String body = JSON.serialize(new Map{ 'name' => newFileName }); Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Content-Type' => 'application/json' }; HttpResponse res = CloudStorageUtlilty.makeCallout(body, endpoint, headers, 'PUT'); if (res.getStatusCode() == 200) { result = OperationResult.success(res.getBody()); } else { result = OperationResult.error(res.getBody()); } } catch (Exception e) { FME_Logger.error( e.getMessage(), 'BoxFeature.renameFile line ' + e.getLineNumber(), 'renameFile' ); result = OperationResult.error( 'Error renaming Box item: ' + e.getMessage() ); } return result; } //Move Done public override OperationResult moveFileAndFolder(Map params) { OperationResult result; try { String fileId = (String) params.get('fileId'); Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String newFolderId = (String) params.get('newFolderId'); String oldFolderId = (String) params.get('oldFolderId'); String type = (String) params.get('type'); String accessToken = (String) params.get('accessToken'); String userId = (String) SalesforceEnvironmentUtil.getUserId(); // Normalize IDs (strip prefixes) // Boolean isFolder = false; // if (fileId.startsWith('folder:')) { // isFolder = true; // fileId = fileId.replace('folder:', ''); // } else if (fileId.startsWith('file:')) { // fileId = fileId.replace('file:', ''); // } // if (newFolderId != null && newFolderId.startsWith('folder:')) { // newFolderId = newFolderId.replace('folder:', ''); // } // Endpoint String endpoint; if (type != null && type.containsIgnoreCase('folder')) { endpoint = BOX_API_URL + '/folders/' + fileId; } else { endpoint = BOX_API_URL + '/files/' + fileId; } // Body → change parent String body = '{ "parent": { "id": "' + newFolderId + '" } }'; Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Content-Type' => 'application/json' }; System.debug('BOX MOVE endpoint => ' + endpoint); System.debug('BOX MOVE body => ' + body); HttpResponse res = CloudStorageUtlilty.makeCallout(body, endpoint, headers, 'PUT'); if (res.getStatusCode() >= 200 && res.getStatusCode() < 300) { System.debug('Box move success => ' + res.getBody()); result = OperationResult.success(res.getBody()); } else { System.debug('Box move failed => ' + res.getBody()); result = OperationResult.error(res.getBody()); } } catch (Exception e) { FME_Logger.error(e.getMessage(),'BoxFeature','moveFileAndFolder'); result = OperationResult.error(e.getMessage()); } return result; } public override OperationResult downloadFile(Map params) { System.debug('BOX downloadFile fileId =' ); try { Blob fileBlob = fetchBoxFile(params); System.debug('BOX downloadFile fileBlob =' + fileBlob + ' fileBlob.size()=' + fileBlob.size()); if (fileBlob != null && fileBlob.size() > 0) { // return base-64 encoded payload return OperationResult.success(EncodingUtil.base64Encode(fileBlob)); } return OperationResult.error('Failed to download Box file and fileId is'); } catch (Exception e) { return OperationResult.error('Box download error: ' + e.getMessage()); } } //changes private static Blob fetchBoxFile(Map params) { Blob fileBlob; try { Boolean isServiceMode = (Boolean) params.get('isServiceMode'); String fileId = (String) params.get('fileId'); String fileName = (String) params.get('fileName'); String accessToken = (String) params.get('accessToken'); System.debug('BOX | params=' + params); System.debug('BOX | accessToken=' + accessToken); if (String.isBlank(accessToken)) { throw new CalloutException('Box access token is null'); } String endpoint = 'https://api.box.com/2.0/files/' + fileId + '/content'; Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Accept' => 'application/octet-stream' }; HttpResponse res = CloudStorageUtlilty.makeCallout(null, endpoint, headers, 'GET'); System.debug('BOX first response status: ' + res.getStatusCode()); if (res.getStatusCode() == 200) { fileBlob = res.getBodyAsBlob(); } else if (res.getStatusCode() == 302) { String redirectUrl = res.getHeader('location'); if (String.isBlank(redirectUrl)) { throw new CalloutException('Redirect URL missing'); } HttpResponse cdnRes = CloudStorageUtlilty.makeCallout( null, redirectUrl, headers, 'GET' ); if (cdnRes.getStatusCode() == 200) { fileBlob = cdnRes.getBodyAsBlob(); } else { throw new CalloutException( 'CDN download failed: ' + cdnRes.getStatusCode() ); } } else { throw new CalloutException( 'Box download failed: ' + res.getStatusCode() + ' body=' + res.getBody() ); } } catch (Exception e) { System.debug('Error in fetchBoxFile: ' + e.getMessage()); FME_Logger.error(e.getMessage(), 'BoxFeature', 'fetchBoxFile'); } return fileBlob; } //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; } //unlinkfile 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(), 'GoogleDriveFeature' + e.getLineNumber(), 'unlinkFiles'); } return result; } }