235 lines
8.5 KiB
C#

using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using Marco.Pms.Model.Utilities;
using MarcoBMS.Services.Service;
using Microsoft.Extensions.Options;
using MimeDetective;
namespace Marco.Pms.Services.Service
{
public class S3UploadService
{
private readonly IAmazonS3 _s3Client;
private readonly string _bucketName = "your-bucket-name";
private readonly ILoggingService _logger;
private readonly IConfiguration _configuration;
public S3UploadService(IOptions<AWSSettings> awsOptions, ILoggingService logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
var settings = awsOptions.Value;
var region = Amazon.RegionEndpoint.GetBySystemName(settings.Region);
_bucketName = settings.BucketName;
_s3Client = new AmazonS3Client(settings.AccessKey, settings.SecretKey, region);
}
//public async Task<string> UploadFileAsync(string fileName, string contentType)
public async Task<string> UploadFileAsync(string base64Data, int tenantId, string tag)
{
byte[] fileBytes;
//If base64 has a data URI prefix, strip it
var base64 = base64Data.Contains(",")
? base64Data.Substring(base64Data.IndexOf(",") + 1)
: base64Data;
var allowedFilesType = _configuration.GetSection("WhiteList:ContentType")
.GetChildren()
.Select(x => x.Value)
.ToList();
string fileType = GetContentTypeFromBase64(base64);
if (allowedFilesType != null && allowedFilesType.Contains(fileType))
{
string fileName = GenerateFileName(fileType, tenantId, tag);
fileBytes = Convert.FromBase64String(base64);
using var fileStream = new MemoryStream(fileBytes);
// Generate a unique object key (you can customize this)
var objectKey = $"{fileName}";
var uploadRequest = new TransferUtilityUploadRequest
{
InputStream = fileStream,
Key = objectKey,
BucketName = _bucketName,
ContentType = fileType,
AutoCloseStream = true
};
try
{
var transferUtility = new TransferUtility(_s3Client);
await transferUtility.UploadAsync(uploadRequest);
_logger.LogInfo("File uploaded to Amazon S3");
return objectKey;
}
catch (Exception ex)
{
_logger.LogError("{error} while uploading file to S3", ex.Message);
return string.Empty;
}
}
throw new InvalidOperationException("Unsupported file type.");
}
public string GeneratePreSignedUrlAsync(string objectKey)
{
int expiresInMinutes = 10;
var request = new GetPreSignedUrlRequest
{
BucketName = _bucketName,
Key = objectKey,
Expires = DateTime.UtcNow.AddMinutes(expiresInMinutes),
Verb = HttpVerb.GET // for download
};
try
{
string url = _s3Client.GetPreSignedURL(request);
_logger.LogInfo("Requested presigned url from Amazon S3");
return url;
}
catch (Exception ex)
{
_logger.LogError("{error} while requesting presigned url from Amazon S3", ex.Message);
return string.Empty;
}
}
public async Task<bool> DeleteFileAsync(string objectKey)
{
try
{
var deleteRequest = new DeleteObjectRequest
{
BucketName = _bucketName,
Key = objectKey
};
var response = await _s3Client.DeleteObjectAsync(deleteRequest);
_logger.LogInfo("File deleted from Amazon S3");
return response.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
}
catch (Exception ex)
{
_logger.LogError("{error} while deleting from Amazon S3", ex.Message);
return false;
}
}
public string GenerateFileName(string contentType, int tenantId, string? name)
{
string extenstion = GetExtensionFromMimeType(contentType);
if (string.IsNullOrEmpty(name))
return $"{tenantId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}";
return $"{name}_{tenantId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}";
}
public string GetExtensionFromMimeType(string contentType)
{
switch (contentType.ToLowerInvariant())
{
case "application/pdf":
return ".pdf";
case "application/msword":
return ".doc";
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
return ".docx";
case "application/vnd.ms-excel":
return ".xls";
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
return ".xlsx";
case "application/mspowerpoint":
return ".ppt";
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
return ".pptx";
case "text/plain":
return ".txt";
case "application/rtf":
return ".rtf";
case "image/jpeg":
return ".jpg";
case "image/png":
return ".png";
case "image/gif":
return ".gif";
case "image/bmp":
return ".bmp";
case "text/csv":
return ".csv";
default:
return ""; // or ".bin", or throw an error, based on your needs
}
}
public string GetContentTypeFromBase64(string base64String)
{
if (string.IsNullOrEmpty(base64String))
{
return string.Empty; // Or handle the empty case as needed
}
try
{
// 1. Decode the Base64 string to a byte array
byte[] decodedBytes = Convert.FromBase64String(base64String);
// 2. Create a ContentInspector (using default definitions for this example)
var inspector = new ContentInspectorBuilder()
{
Definitions = MimeDetective.Definitions.DefaultDefinitions.All()
}.Build();
// 3. Inspect the byte array to determine the content type
var results = inspector.Inspect(decodedBytes);
if (results.Any())
{
var bestMatch = results
.OrderByDescending(r => r.Points)
.FirstOrDefault();
if (bestMatch?.Definition?.File?.MimeType != null)
{
return bestMatch.Definition.File.MimeType;
}
else
{
_logger.LogError("Warning: Could not find MimeType, Type, or ContentType property in Definition.");
return "application/octet-stream";
}
}
else
{
return "application/octet-stream"; // Default if type cannot be determined
}
}
catch (FormatException)
{
// Handle cases where the input string is not valid Base64
Console.WriteLine("Error: Invalid Base64 string.");
return null;
}
catch (Exception ex)
{
// Handle other potential errors during decoding or inspection
Console.WriteLine($"An error occurred: {ex.Message}");
return null;
}
}
}
}