235 lines
8.5 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |