Refactor: extract shared helpers, fix field drift, add assembly services
- IJobItemAssemblyService / IQuotePricingAssemblyService: centralize job item and quote pricing construction that was duplicated across create, rework copy, and quote-to-job conversion paths - BlobFileHelper: single ValidateUpload/GetContentType/SanitizeFileName used by 6 blob services (JobPhoto, QuotePhoto, ProfilePhoto, CompanyLogo, Equipment, Catalog) and BillsController + ExpensesController, removing 8 private copies - PagedResult<T>.From(): static factory eliminates 6-line boilerplate in 11 controllers (Appointments, Customers, Equipment, Inventory, Invoices, Jobs, Maintenance, CompanyUsers, PlatformUsers, Quotes, Vendors) - AccountingDropdownHelper: single LoadAsync() call replaces duplicate vendor/account/job queries in BillsController and ExpensesController - JobTemplateItem: add IsSalesItem + Sku fields with migration; propagate through JobTemplatesController snapshot copy and GetTemplatesJson projection, and JobsController template-application path - Test assertions updated for standardized BlobFileHelper error messages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,19 +50,13 @@ public class QuotePhotoService : IQuotePhotoService
|
||||
public async Task<(bool Success, string TempId, string FilePath, string ErrorMessage)> SaveTempPhotoAsync(
|
||||
IFormFile file, int companyId)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
return (false, string.Empty, string.Empty, "No file provided.");
|
||||
|
||||
if (file.Length > MaxFileSizeBytes)
|
||||
return (false, string.Empty, string.Empty, "File exceeds the 10 MB limit.");
|
||||
|
||||
var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
|
||||
if (!AllowedExtensions.Contains(ext))
|
||||
return (false, string.Empty, string.Empty, $"File type '{ext}' is not allowed.");
|
||||
var (isValid, ext, validationError) = BlobFileHelper.ValidateUpload(file, AllowedExtensions, MaxFileSizeBytes);
|
||||
if (!isValid)
|
||||
return (false, string.Empty, string.Empty, validationError);
|
||||
|
||||
var tempId = Guid.NewGuid().ToString("N");
|
||||
var blobName = $"temp/{tempId}/{Guid.NewGuid():N}{ext}";
|
||||
var contentType = GetContentType(ext);
|
||||
var contentType = BlobFileHelper.GetContentType(ext);
|
||||
|
||||
using var stream = file.OpenReadStream();
|
||||
var result = await _blobService.UploadAsync(_settings.Containers.QuoteImages, blobName, stream, contentType);
|
||||
@@ -100,7 +94,7 @@ public class QuotePhotoService : IQuotePhotoService
|
||||
return (false, string.Empty, "Failed to read temp photo.");
|
||||
|
||||
using var ms = new MemoryStream(download.Content);
|
||||
var upload = await _blobService.UploadAsync(_settings.Containers.QuoteImages, destBlob, ms, GetContentType(ext));
|
||||
var upload = await _blobService.UploadAsync(_settings.Containers.QuoteImages, destBlob, ms, BlobFileHelper.GetContentType(ext));
|
||||
if (!upload.Success)
|
||||
return (false, string.Empty, "Failed to save permanent photo.");
|
||||
|
||||
@@ -173,12 +167,4 @@ public class QuotePhotoService : IQuotePhotoService
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetContentType(string ext) => ext switch
|
||||
{
|
||||
".jpg" or ".jpeg" => "image/jpeg",
|
||||
".png" => "image/png",
|
||||
".gif" => "image/gif",
|
||||
".webp" => "image/webp",
|
||||
_ => "image/jpeg"
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user