Backup_FME_personal/force-app/main/default/classes/SharePointFeature.cls

679 lines
25 KiB
OpenEdge ABL

public with sharing class SharePointFeature extends CloudStorageBase {
private static final String SHAREPOINT_API_BASE_URL = 'https://graph.microsoft.com/v1.0';
private static String externalStorage = 'SharePoint';
//List files
public override OperationResult listFiles(Boolean isServiceMode,Boolean myDrive,String userId,Boolean isRootFolder,String folderId, String accessToken, String level) {
try {
// Map<String,String> tokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode, userId, externalStorage);
// String accessToken = tokenMap.get('ACCESS_TOKEN');
//get all sites
if (level == 'getAllSite' || level == 'getSites') {
if(myDrive == true){
return getAllFollowedSites(accessToken);
}
else {
return getAllSharePointSites(accessToken);
}
}
else if (level == 'getDocumentDrive') {
if (String.isBlank(folderId)) {
return OperationResult.error('SiteId required ');
}
return getAllDocumentDrives(accessToken, folderId);
} else if (level == 'getFilesInsideDocDrive') {
if (String.isBlank(folderId)) {
return OperationResult.error('DriveId required');
}
return getFilesInsideDrive(accessToken, folderId);
}
return OperationResult.error('Invalid level provided');
} catch (Exception e) {
return OperationResult.error('ERROR: ' + e.getMessage());
}
}
// all sharepoint sites
private OperationResult getAllSharePointSites(String accessToken) {
String url = SHAREPOINT_API_BASE_URL + '/sites?search=*';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + accessToken);
req.setHeader('Accept', 'application/json');
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() != 200)
return OperationResult.error('Error fetching SharePoint Sites: ' + res.getBody());
Map<String,Object> json = (Map<String,Object>) JSON.deserializeUntyped(res.getBody());
List<Object> siteList = (List<Object>) json.get('value');
System.debug('siteList: ' + siteList);
System.debug('siteList: ' + siteList.size());
List<Map<String,String>> result = new List<Map<String,String>>();
System.debug('result: ' + result);
for (Object allsites : siteList) {
Map<String,Object> site = (Map<String,Object>) allsites;
Map<String,String> row = new Map<String,String>();
// getAllSharePointSites & getAllFollowedSites
row.put('id', (String) site.get('id'));
row.put('name', (String) site.get('displayName'));
row.put('url', (String) site.get('webUrl'));
row.put('type', 'site');
row.put('nextLevel', 'getDocumentDrive');
row.put('disableCheck', 'true');
result.add(row);
}
return OperationResult.success(result);
}
//get the followed sites
private OperationResult getAllFollowedSites(String accessToken) {
String url = SHAREPOINT_API_BASE_URL + '/me/followedSites';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + accessToken);
req.setHeader('Accept', 'application/json');
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() != 200) {
return OperationResult.error(
'Error fetching followed SharePoint Sites: ' + res.getBody()
);
}
Map<String, Object> resbody = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
List<Object> siteList = (List<Object>) resbody.get('value');
List<Map<String, String>> result = new List<Map<String, String>>();
System.debug('result>>>' + result);
for (Object obj : siteList) {
Map<String, Object> s = (Map<String, Object>) obj;
Map<String, String> row = new Map<String, String>();
row.put('id', (String) s.get('id'));
row.put('name', (String) s.get('displayName'));
row.put('url', (String) s.get('webUrl'));
row.put('type', 'followedSite');
row.put('nextLevel', 'getDocumentDrive');
row.put('disableCheck', 'true');
result.add(row);
}
return OperationResult.success(result);
}
// all doc drive
private OperationResult getAllDocumentDrives(String accessToken, String siteId) {
String url = SHAREPOINT_API_BASE_URL + '/sites/' + siteId + '/drives';
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + accessToken);
req.setHeader('Accept', 'application/json');
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() != 200)
return OperationResult.error('Error fetching drives: ' + res.getBody());
Map<String,Object> json = (Map<String,Object>) JSON.deserializeUntyped(res.getBody());
List<Object> driveList = (List<Object>) json.get('value');
List<Map<String,String>> result = new List<Map<String,String>>();
for (Object alldrives : driveList) {
Map<String,Object> drive = (Map<String,Object>) alldrives;
Map<String,String> row = new Map<String,String>();
// getAllDocumentDrives
// row.put('id', (String) drive.get('id'));
//change
row.put('id', drive.get('id') + ':' + siteId);
row.put('name', (String) drive.get('name'));
row.put('driveType', (String) drive.get('driveType'));
row.put('type', 'drive');
row.put('nextLevel', 'getFilesInsideDocDrive');
row.put('disableCheck', 'true');
result.add(row);
}
return OperationResult.success(result);
}
private OperationResult getFilesInsideDrive(String accessToken, String compositeId) {
List<String> parts = compositeId.split(':');
String driveId = parts[0];
String siteId = parts.size() > 1 ? parts[1] : null;
String itemId = parts.size() > 2 ? parts[2] : null;
String url;
// ROOT of document library
if (itemId == null) {
url = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/root/children';
}
// INSIDE a folder
else {
url = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/items/' + itemId + '/children';
}
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + accessToken);
req.setHeader('Accept', 'application/json');
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() != 200) {
return OperationResult.error('Error getting drive items: ' + res.getBody());
}
Map<String,Object> json = (Map<String,Object>) JSON.deserializeUntyped(res.getBody());
List<Object> items = (List<Object>) json.get('value');
List<Map<String,String>> result = new List<Map<String,String>>();
for (Object obj : items) {
Map<String,Object> f = (Map<String,Object>) obj;
Map<String,String> row = new Map<String,String>();
// Preserve composite ID for next navigation
// row.put('id', driveId + ':' + (String) f.get('id'));
//changes
row.put('id', driveId + ':' + siteId + ':' + (String) f.get('id'));
// changes
// NORMALIZED ID (used by download/delete/rename)
// String normalizedFileId = driveId + ':' + (String) f.get('id');
// row.put('id', normalizedFileId);
// String itemGraphId = (String) f.get('id');
// NAVIGATION ID (USED FOR FOLDER CLICK / BACK / BREADCRUMB)
// String navigationId = driveId + ':' + siteId + ':' + itemGraphId;
// row.put('id', navigationId);
// OPERATION ID (USED FOR DOWNLOAD / DELETE / RENAME)
// String normalizedId = driveId + ':' + itemGraphId;
// row.put('normalizedId', normalizedId);
row.put('name', (String) f.get('name'));
row.put('url', (String) f.get('webUrl'));
row.put('createdTime', (String) f.get('createdDateTime'));
row.put('disableCheck', 'false');
row.put('type', f.containsKey('folder') ? 'folder' : 'file');
row.put('nextLevel', 'getFilesInsideDocDrive');
if (f.containsKey('folder')) {
row.put('mimeType', 'doctype:folder');
} else {
Map<String, Object> fileObj = (Map<String, Object>) f.get('file');
row.put('mimeType',
fileObj != null && fileObj.containsKey('mimeType')
? (String) fileObj.get('mimeType')
: 'doctype:unknown'
);
}
Map<String, Object> createdBy = (Map<String, Object>) f.get('createdBy');
if (createdBy != null) {
Map<String, Object> userMap = (Map<String, Object>) createdBy.get('user');
row.put('displayName', userMap != null ? (String) userMap.get('displayName') : '-');
}
result.add(row);
}
return OperationResult.success(result);
}
//adding method to linkfiles
// change custom object -- linkedFolder
public override OperationResult linkFiles(String recordId) {
List<Map<String, String>> resultFolders = new List<Map<String, String>>();
try {
List<HIC_FilesME__Linked_Folder__c> 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<String, String> folderData = new Map<String, String>();
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);
}
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<String, Object> folderMap =
(Map<String, Object>) 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());
}
}
// //to create folder
public override OperationResult createFolder(String parentFolderId, Boolean isServiceMode,String folderName,String userId)
{
Map<String, Object> resultMap = new Map<String, Object>();
Map<String, String> accessTokenMap = new Map<String, String>();
String refreshToken;
OperationResult result;
try {
accessTokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode,userId,externalStorage);
String accessToken = accessTokenMap.get('ACCESS_TOKEN');
refreshToken = accessTokenMap.get('REFRESH_TOKEN');
List<String> ids = parentFolderId != null ? parentFolderId.split(':') : null;
String driveId = ids != null ? ids[0] : null;
String itemId = (ids != null && ids.size() > 2) ? ids[2] : null;
if (String.isBlank(driveId)) {
return OperationResult.error('DriveId is required to create folder in SharePoint');
}
String endpoint;
if (String.isBlank(itemId)) {
endpoint = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/root/children';
} else {
endpoint = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/items/' + itemId + '/children';
}
String folderMetadata = JSON.serialize(new Map<String, Object>{
'name' => folderName,
'folder' => new Map<String, Object>(),
'@microsoft.graph.conflictBehavior' => 'rename'
});
Map<String, String> headers = new Map<String, String>{
'Authorization' => 'Bearer ' + accessToken,
'Content-Type' => 'application/json'
};
HttpResponse res = CloudStorageUtlilty.makeCallout(folderMetadata,endpoint,headers,'POST');
if (res.getStatusCode() == 201 || res.getStatusCode() == 200) {
resultMap = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
resultMap.put('code', '200');
result = OperationResult.success(resultMap);
} else {
System.debug('SharePoint create folder failed: ' + res.getBody());
result = OperationResult.error(res.getBody());
}
} catch (Exception e) {
FME_Logger.error(
e.getMessage(),
'SharePointFeature.createFolder line ' + e.getLineNumber(),
'createFolder'
);
result = OperationResult.error('Error creating SharePoint folder: ' + e.getMessage());
} finally {
if (accessTokenMap.containsKey('newAccessToken')) {
CloudStorageUtlilty.updateAccessToken(isServiceMode,userId,refreshToken,externalStorage);
}
}
System.debug('resultMap >>> ' + resultMap);
System.debug('result >>> ' + result);
return result;
}
//to delete file or folder
public override OperationResult deleteFile(String fileId, Boolean isServiceMode, String userId) {
Map<String, String> accessTokenMap = new Map<String, String>();
String refreshToken;
try {
System.debug('SharePoint delete >>> fileId=' + fileId);
accessTokenMap = CloudStorageUtlilty.getAccessToken(isServiceMode,userId,externalStorage);
String accessToken = accessTokenMap.get('ACCESS_TOKEN');
refreshToken = accessTokenMap.get('REFRESH_TOKEN');
if (String.isBlank(fileId)) {
return OperationResult.error('FileId is required');
}
List<String> ids = fileId.split(':');
if (ids.size() < 2) {
return OperationResult.error('Invalid SharePoint fileId format');
}
String driveId = ids[0];
String itemId = ids[1];
String endpoint = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/items/' + itemId;
System.debug('SharePoint delete endpoint >>> ' + endpoint);
// Headers
Map<String, String> headers = new Map<String, String>();
headers.put('Authorization', 'Bearer ' + accessToken);
HttpResponse res = CloudStorageUtlilty.makeCallout(null,endpoint,headers,'DELETE');
System.debug('Delete response code >>> ' + res.getStatusCode());
if (res.getStatusCode() == 204) {
return OperationResult.success('Deleted successfully');
} else {
return OperationResult.error(res.getBody());
}
} catch (Exception e) {
FME_Logger.error(e.getMessage(),'SharePointFeature.deleteFile line ' + e.getLineNumber(),'deleteFile');
return OperationResult.error(
'Error deleting SharePoint file: ' + e.getMessage()
);
} finally {
if (accessTokenMap.containsKey('newAccessToken')) {
CloudStorageUtlilty.updateAccessToken(isServiceMode,userId,refreshToken,externalStorage);
}
}
}
//rename folder
public override OperationResult renameFile(String fileId,Boolean isServiceMode,String userId,String newFileName) {
String accessToken;
String refreshToken;
OperationResult result;
Map<String, String> accessTokenMap = new Map<String, String>();
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<String> ids = fileId.split(':');
if (ids.size() < 2) {
return OperationResult.error('Invalid SharePoint fileId format');
}
String driveId = ids[0];
String itemId = ids[1];
String url = SHAREPOINT_API_BASE_URL + '/drives/' + driveId + '/items/' + itemId;
System.debug('SharePoint rename url >>> ' + url);
System.debug('New file name >>> ' + newFileName);
String body = JSON.serialize(new Map<String, Object>{
'name' => newFileName
});
Map<String, String> headers = new Map<String, String>{
'Authorization' => 'Bearer ' + accessToken,
'Content-Type' => 'application/json'
};
HttpResponse res = CloudStorageUtlilty.makeCallout(body, url, headers, 'PATCH');
System.debug('Rename response code >>> ' + res.getStatusCode());
if (res.getStatusCode() == 200) {
result = OperationResult.success(res.getBody());
// Optional audit log
// FME_Logger.audit(
// 'Rename',
// 'Renamed SharePoint item ' + fileId + ' to ' + newFileName,
// 'SharePointFeature',
// 'renameFile'
// );
} else {
result = OperationResult.error(res.getBody());
}
} catch (Exception e) {
FME_Logger.error(e.getMessage(),'SharePointFeature.renameFile line ' + e.getLineNumber(),'renameFile');
result = OperationResult.error('Error renaming SharePoint file: ' + e.getMessage());
} finally {
if (accessTokenMap.containsKey('newAccessToken')) {
CloudStorageUtlilty.updateAccessToken(isServiceMode,userId,refreshToken,externalStorage);
}
}
System.debug('SharePoint rename result >>> ' + result);
return result;
}
//add
public static Blob fetchFileAndConvertToBase64(
Boolean isServiceMode,
String userId,
String fileId
) {
Blob fileBlob;
try {
// 1. Access token
Map<String, Object> credentials =
CloudStorageUtlilty.getAccessToken(isServiceMode, userId, externalStorage);
String accessToken = (String) credentials.get('ACCESS_TOKEN');
String refreshToken = (String) credentials.get('REFRESH_TOKEN');
// 2. Split normalized ID
List<String> parts = fileId.split(':');
String driveId = parts[0];
String itemId = parts[1];
Map<String, String> headers = new Map<String, String>{
'Authorization' => 'Bearer ' + accessToken
};
// 🔥 3. GET DOWNLOAD URL (NO REDIRECTS)
String metaUrl =
'https://graph.microsoft.com/v1.0/drives/' +
driveId + '/items/' + itemId +
'?select=@microsoft.graph.downloadUrl';
HttpResponse metaRes =
CloudStorageUtlilty.makeCallout(null, metaUrl, headers, 'GET');
// 4. Refresh token if needed
if (metaRes.getStatusCode() == 401) {
SharePointAuth auth = new SharePointAuth();
String newAccessToken = auth.refreshAccessToken(refreshToken);
CloudStorageUtlilty.updateAccessToken(
isServiceMode, userId, newAccessToken, externalStorage
);
headers.put('Authorization', 'Bearer ' + newAccessToken);
metaRes =
CloudStorageUtlilty.makeCallout(null, metaUrl, headers, 'GET');
}
if (metaRes.getStatusCode() != 200) {
System.debug('Failed to fetch SharePoint download URL');
return null;
}
Map<String, Object> meta =
(Map<String, Object>) JSON.deserializeUntyped(metaRes.getBody());
String downloadUrl =
(String) meta.get('@microsoft.graph.downloadUrl');
// 5. Download file (NO AUTH HEADER)
HttpResponse fileRes =
CloudStorageUtlilty.makeCallout(null, downloadUrl, null, 'GET');
if (fileRes.getStatusCode() == 200) {
fileBlob = fileRes.getBodyAsBlob();
} else {
System.debug('SharePoint download failed: ' + fileRes.getStatusCode());
}
} catch (Exception e) {
System.debug(
'Error in SharePoint fetchFileAndConvertToBase64: ' +
e.getMessage() + ' | Line: ' + e.getLineNumber()
);
}
return fileBlob;
}
public override OperationResult downloadFile(
Boolean isServiceMode,
String userId,
String fileId,
String fileName
) {
System.debug('SharePointFeature.downloadFile');
OperationResult result;
try {
Blob fileBlob =
fetchFileAndConvertToBase64(isServiceMode, userId, fileId);
if (fileBlob != null) {
result =
OperationResult.success(
EncodingUtil.base64Encode(fileBlob)
);
System.debug('SharePoint file downloaded successfully.');
} else {
result =
OperationResult.error(
'Failed to download SharePoint file. fileId: ' + fileId
);
}
} catch (Exception e) {
result =
OperationResult.error(
'Error downloading SharePoint file: ' + e.getMessage()
);
FME_Logger.error(
e.getMessage(),
'SharePointFeature' + e.getLineNumber(),
'downloadFile'
);
}
return result;
}
}