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'; public override OperationResult listFiles(Boolean isServiceMode,Boolean myDrive,String userId,Boolean isRootFolder,String folderId,String accessToken,String level) { List> resultFiles = new List>(); OperationResult result; try { System.debug('isServiceMode ' + isServiceMode); System.debug('accessToken ' + accessToken); System.debug('--Folder ID-- ' + folderId); // Box root folder is always 0 at root level String boxFolderId; if ((folderId == null || folderId == '') && isRootFolder) { System.debug('Root Folder Box'); boxFolderId = '0'; } else { boxFolderId = folderId; } // 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'); for (Object obj : entries) { Map fileDetails = (Map) obj; Map fileData = new Map(); String type = (String) fileDetails.get('type'); // fileData.put('id', (String) fileDetails.get('id')); // changes // For files fileData.put('id', 'file:' + (String) fileDetails.get('id')); // For folders fileData.put('id', 'folder:' + (String) fileDetails.get('id')); 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); String rawId = (String) fileDetails.get('id'); fileData.put('id', rawId); fileData.put('name', (String) fileDetails.get('name')); 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()); } } // 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()); } } // 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; 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 createFolder(String parentFolderId,Boolean isServiceMode,String folderName,String userId) { Map resultMap = new Map(); Map accessTokenMap = new Map(); String refreshToken; OperationResult result; try { String accessToken; // Get access token accessTokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode, userId, externalStorage); accessToken = (String) accessTokenMap.get('ACCESS_TOKEN'); refreshToken = (String) accessTokenMap.get('REFRESH_TOKEN'); // Box parent folder // Root folder ID = "0" String boxParentFolderId = (parentFolderId != null && parentFolderId != '') ? parentFolderId : '0'; String folderMetadata = '{' + '"name": "' + folderName + '",' + '"parent": {' + '"id": "' + boxParentFolderId + '"' + '}' + '}'; // Headers Map headers = new Map{ 'Authorization' => 'Bearer ' + accessToken, 'Content-Type' => 'application/json' }; // Callout String endpoint = 'https://api.box.com/2.0/folders'; HttpResponse res = CloudStorageUtlilty.makeCallout(folderMetadata, endpoint, headers, 'POST'); System.debug('STATUS ---> ' + res.getStatusCode()); System.debug('BODY ---> ' + res.getBody()); // Success if (res.getStatusCode() == 201) { resultMap = (Map) JSON.deserializeUntyped(res.getBody()); resultMap.put('code', '201'); result = OperationResult.success(resultMap); // String userName = UserInfo.getName(); // String logMsg = userName + ' created folder "' + folderName + // '" under parentId ' + boxParentFolderId; // FME_Logger.audit('Create Folder', logMsg, 'BoxFeature', 'createFolder'); } else { System.debug('Failed to create Box folder: ' + res.getBody()); result = OperationResult.error(res.getBody()); } } catch (Exception e) { FME_Logger.error(e.getMessage(),'BoxFeature' + e.getLineNumber(),'createFolder'); result = OperationResult.error('Error creating Box folder: ' + e.getMessage()); } finally { if (accessTokenMap.containsKey('newAccessToken')) { CloudStorageUtlilty.updateAccessToken(isServiceMode,userId,refreshToken,externalStorage); } } System.debug('result: ' + result); return result; } public override OperationResult deleteFile(String fileId, Boolean isServiceMode, String userId) { Map accessTokenMap = new Map(); String refreshToken; try { accessTokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode,userId, externalStorage); System.debug('accessTokenMap: ' + accessTokenMap); String accessToken = accessTokenMap.get('ACCESS_TOKEN'); refreshToken = accessTokenMap.get('REFRESH_TOKEN'); if (String.isBlank(fileId)) { return OperationResult.error('FileId is required'); } // Expecting format: file:{id} OR folder:{id} List parts = fileId.split(':'); System.debug('parts: ' + parts); if (parts.size() != 2) { return OperationResult.error('Invalid Box fileId format'); } String type = parts[0]; // file | folder String id = parts[1]; String endpoint; if (type == 'file') { endpoint = 'https://api.box.com/2.0/files/' + id; } else if (type == 'folder') { endpoint = 'https://api.box.com/2.0/folders/' + id + '?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() ); } finally { if (accessTokenMap.containsKey('newAccessToken')) { CloudStorageUtlilty.updateAccessToken( isServiceMode, userId, refreshToken, externalStorage ); } } } public override OperationResult renameFile(String fileId,Boolean isServiceMode,String userId,String newFileName) { String accessToken; String refreshToken; Map accessTokenMap = new Map(); OperationResult result; try { accessTokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode,userId,externalStorage); accessToken = accessTokenMap.get('ACCESS_TOKEN'); refreshToken = accessTokenMap.get('REFRESH_TOKEN'); if (String.isBlank(fileId) || String.isBlank(newFileName)) { return OperationResult.error('FileId and newFileName are required'); } List parts = fileId.split(':'); if (parts.size() != 2) { return OperationResult.error('Invalid Box fileId format'); } String type = parts[0]; String id = parts[1]; String endpoint; if (type == 'file') { endpoint = 'https://api.box.com/2.0/files/' + id; } else if (type == 'folder') { endpoint = 'https://api.box.com/2.0/folders/' + id; } 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() ); } finally { if (accessTokenMap.containsKey('newAccessToken')) { CloudStorageUtlilty.updateAccessToken( isServiceMode, userId, refreshToken, externalStorage ); } } return result; } }