using Microsoft.Extensions.Configuration; using Microsoft.Graph; using Microsoft.Identity.Client; using rgbc_sds.dal.DB; using rgbc_sds.services.Models; using System.Net.Http.Headers; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.IdentityModel.Tokens; using static System.Net.WebRequestMethods; namespace rgbc_sds.services.Services { public class SharePointService { private readonly IConfiguration _configuration; private readonly IConfidentialClientApplication _confidentialClientApp; private readonly rgbc_sdsContext _context; public SharePointService(IConfiguration configuration, rgbc_sdsContext context) { _configuration = configuration; _confidentialClientApp = ConfidentialClientApplicationBuilder.Create(_configuration["SharePointCredentials:CLIENT_ID"]) .WithClientSecret(_configuration["SharePointCredentials:CLIENT_SECRET"]) .WithAuthority(new Uri($"https://login.microsoftonline.com/{_configuration["SharePointCredentials:TENANT_ID"]}")) .Build(); _context = context; } /// /// Retrieving the access token that is used as authentication. /// /// public async Task RetrieveAccessTokenAsync() { var scopes = new[] { _configuration["SharePointCredentials:SCOPE"] }; var authResult = await _confidentialClientApp.AcquireTokenForClient(scopes).ExecuteAsync(); return authResult.AccessToken; } /// /// Configuration of the graph client that is used for all sharepoint actions. /// /// public async Task ConfigureGraphClient() { var accessToken = await RetrieveAccessTokenAsync(); var graphClient = new GraphServiceClient( new DelegateAuthenticationProvider((requestMessage) => { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); return Task.CompletedTask; })); return graphClient; } /// /// Method that handles the upload of a file to a document type that already has a file uploaded. /// It checks if there is a file uploaded and deletes the file before uploading the new file. /// /// /// /// public async Task UploadFilesAsync(sdsShipment s, List files) { foreach (var file in files) { var fileName = $"{s.indent_number}_{file.File.FileName}"; var folderPath = $"/Shipment Checklist/{s.indent_number}"; using var stream = new MemoryStream(); await file.File.CopyToAsync(stream); stream.Seek(0, SeekOrigin.Begin); //Check if file exists try { // check if file has been uploaded for the document type switch (file.DocumentType) { case "ClampingRequest": if (!string.IsNullOrEmpty(s.clamping_request_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // upload new file await UploadFileHelper(folderPath, fileName, stream); } break; case "SupplierInvoice": if (!string.IsNullOrEmpty(s.supplier_invoice_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "BillOfLading": if (!string.IsNullOrEmpty(s.bill_of_lading_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "ArrivalInvoice": if (!string.IsNullOrEmpty(s.arrival_invoice_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "ArrivalInvoice2": if (!string.IsNullOrEmpty(s.arrival_invoice_file2)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "CerificateOfOrigin": if (!string.IsNullOrEmpty(s.certificate_of_origin_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "PackingList": if (!string.IsNullOrEmpty(s.packing_list_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "DROToTransport": if (!string.IsNullOrEmpty(s.dro_to_transport_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "CertificateOfRemoval": if (!string.IsNullOrEmpty(s.certificate_of_removal_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "ExtendedDetention": if (!string.IsNullOrEmpty(s.extended_detention_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "VOC": if (!string.IsNullOrEmpty(s.voc_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "DeptOfHealth": if (!string.IsNullOrEmpty(s.dept_of_health_inspection_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "SARSDocuments": if (!string.IsNullOrEmpty(s.sars_documents_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "GRVCompleteRGBC": if (!string.IsNullOrEmpty(s.grv_complete_RGBC_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "GRVEdwardSnell": if (!string.IsNullOrEmpty(s.grv_edward_snell_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; case "ACCPACReceipts": if (!string.IsNullOrEmpty(s.accpac_receipts_file)) { // delete existing file await DeleteFileHelper(folderPath, $"{s.indent_number}_{file.OldFileName}"); // deleting the file that was uploaded to replace with new file await UploadFileHelper(folderPath, fileName, stream); } break; default: break; } } catch (ServiceException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) { //File does not exist, no action needed } } } /// /// Uploads the file to sharepoint. /// /// /// /// /// public async Task UploadFileHelper(string folderPath, string fileName, MemoryStream stream) { try { var graphClient = await ConfigureGraphClient(); //Upload new file await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]] .Drive .Root .ItemWithPath($"{folderPath}/{fileName}") .Content .Request() .PutAsync(stream); } catch (Exception ex) { throw; } } /// /// Deletes an existing file. /// /// /// /// public async Task DeleteFileHelper(string folderPath, string fileName) { var graphClient = await ConfigureGraphClient(); try { var existingFile = await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]] .Drive .Root .ItemWithPath($"{folderPath}/{fileName}") .Request() .GetAsync(); //If exists, delete the existing file if (existingFile != null) { await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]] .Drive .Items[existingFile.Id] .Request() .DeleteAsync(); } } catch (ServiceException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) { //File does not exist, no action needed } } /// /// Retrieves the URL for the user to be able to view the uploaded files. /// /// /// /// public async Task GetSharepointPreviewURL(string folderPath, string fileName) { var graphClient = await ConfigureGraphClient(); try { ItemPreviewInfo preview = await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]] .Drive .Root .ItemWithPath($"{folderPath}/{fileName}") .Preview() .Request() .PostAsync(); return preview.GetUrl; } catch (ServiceException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) { return "File not Found"; } } /// /// Gets all files in a specific folder. /// /// /// public async Task> GetFilesInFolder(string folderId) { var graphClient = await ConfigureGraphClient(); var items = await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]].Drive.Items[folderId].Children.Request().GetAsync(); return items.CurrentPage.ToList(); } /// /// Gets all files within a specific folder path. /// /// /// /// public async Task GetFolderIdByNameInRoot(string folderName, string folderPath) { var graphClient = await ConfigureGraphClient(); // Fetch root items in the document library var items = await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]].Drive.Root.ItemWithPath($"{folderPath}").Children.Request().GetAsync(); var folder = items.CurrentPage.FirstOrDefault(i => i.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase)); return folder?.Id; // Return folder ID or null if not found } /// /// Method that handles the moving of files. /// /// /// /// /// /// public async Task RenameFoldersFiles(string sourceFolderName, string rootFolderName, string newFolderName, IList fileNames) { var graphClient = await ConfigureGraphClient(); // get folder to rename var sourceFolderId = await GetFolderIdByNameInRoot(sourceFolderName, rootFolderName); // get files within this folder to rename var sourceFileList = await GetFilesInFolder(sourceFolderId); // rename the files var renameFiles = await RenameFiles(sourceFileList, fileNames, newFolderName); // rename folder with new indent number var message = await RenameFolder(sourceFolderId, newFolderName); } /// /// Rename a folder /// /// /// /// public async Task RenameFolder(string folderId, string folderName) { var graphClient = await ConfigureGraphClient(); var driveItem = new DriveItem { Name = folderName, }; await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]].Drive.Items[folderId] .Request() .UpdateAsync(driveItem); return "Folder renamed successfully"; } /// /// Rename files /// /// /// /// public async Task RenameFiles(IList files, IList fileNames, string folderName) { var graphClient = await ConfigureGraphClient(); foreach (var file in files) { foreach (var sharepointFile in fileNames) { if (file.Name.Contains(sharepointFile)) { var updatedFile = new DriveItem { Name = folderName + "_" + sharepointFile }; await graphClient.Sites[_configuration["SharePointCredentials:SITE_ID"]].Drive.Items[file.Id] .Request() .UpdateAsync(updatedFile); } } } return "Folder renamed successfully"; } } }