(refactor): code review
This commit is contained in:
parent
6e37619ac0
commit
d6fcf34bf6
5
webapi/Services/ImageService/Class1.cs
Normal file
5
webapi/Services/ImageService/Class1.cs
Normal file
@ -0,0 +1,5 @@
|
||||
namespace ImageService {
|
||||
public class Class1 {
|
||||
|
||||
}
|
||||
}
|
||||
9
webapi/Services/ImageService/ImageService.csproj
Normal file
9
webapi/Services/ImageService/ImageService.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExtensionsTests", "Tests\Ex
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\CoreTests.csproj", "{04CB9827-AA6D-4708-A26D-8420C842506D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageService", "Services\ImageService\ImageService.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -73,6 +75,10 @@ Global
|
||||
{04CB9827-AA6D-4708-A26D-8420C842506D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04CB9827-AA6D-4708-A26D-8420C842506D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16552644-D7EE-4B4A-A725-79909A8103DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16552644-D7EE-4B4A-A725-79909A8103DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16552644-D7EE-4B4A-A725-79909A8103DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16552644-D7EE-4B4A-A725-79909A8103DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -82,6 +88,7 @@ Global
|
||||
{B717D8BD-BCCA-4515-9A62-CA3BE802D0F7} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||
{43315A1D-9E09-4398-84B9-A9D9D623AE5A} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||
{04CB9827-AA6D-4708-A26D-8420C842506D} = {216302C2-64DE-4AE7-BC14-BDAC5B732472}
|
||||
{16552644-D7EE-4B4A-A725-79909A8103DE} = {113EE574-E047-4727-AA36-841F845504D5}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E2805D02-2425-424C-921D-D97341B76F73}
|
||||
|
||||
@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class BlogItemController : ControllerBase {
|
||||
|
||||
private readonly ILogger<BlogItemController> _logger;
|
||||
private readonly IBlogItemService _blogItemService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="blogItemService"></param>
|
||||
public BlogItemController(
|
||||
ILogger<BlogItemController> logger,
|
||||
IBlogItemService blogItemService
|
||||
) {
|
||||
_logger = logger;
|
||||
_blogItemService = blogItemService;
|
||||
}
|
||||
|
||||
|
||||
@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class BlogItemsController : ControllerBase {
|
||||
|
||||
private readonly ILogger<BlogItemsController> _logger;
|
||||
private readonly IBlogItemsService _blogItemsService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="blogItemsService"></param>
|
||||
public BlogItemsController(
|
||||
ILogger<BlogItemsController> logger,
|
||||
IBlogItemsService blogItemsService
|
||||
) {
|
||||
_logger = logger;
|
||||
_blogItemsService = blogItemsService;
|
||||
}
|
||||
|
||||
|
||||
@ -16,18 +16,14 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class CategoryItemController : ControllerBase {
|
||||
|
||||
private readonly ILogger<CategoryItemController> _logger;
|
||||
private readonly ICategoryItemService _categoryItemService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="categoryItemService"></param>
|
||||
public CategoryItemController(
|
||||
ILogger<CategoryItemController> logger,
|
||||
ICategoryItemService categoryItemService) {
|
||||
_logger = logger;
|
||||
_categoryItemService = categoryItemService;
|
||||
}
|
||||
|
||||
|
||||
@ -15,22 +15,16 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class CategoryItemsController : ControllerBase {
|
||||
|
||||
private readonly ILogger<CategoryItemsController> _logger;
|
||||
private readonly ICategoryItemsService _categoryItemsService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="categoryItemsService"></param>
|
||||
public CategoryItemsController(
|
||||
ILogger<CategoryItemsController> logger,
|
||||
ICategoryItemsService categoryItemsService
|
||||
) {
|
||||
_logger = logger;
|
||||
_categoryItemsService = categoryItemsService;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -15,7 +15,6 @@ namespace WeatherForecast.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class ContentController : ControllerBase {
|
||||
|
||||
private readonly ILogger<ContentController> _logger;
|
||||
private readonly IContentService _contentService;
|
||||
|
||||
/// <summary>
|
||||
@ -24,10 +23,8 @@ public class ContentController : ControllerBase {
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="contentService"></param>
|
||||
public ContentController(
|
||||
ILogger<ContentController> logger,
|
||||
IContentService contentService
|
||||
) {
|
||||
_logger = logger;
|
||||
_contentService = contentService;
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,19 @@ namespace WeatherForecast.Controllers {
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{siteId}/{userId}")]
|
||||
public IActionResult Post([FromRoute] Guid siteId, [FromRoute] Guid userId, IFormFile file) {
|
||||
var result = _fileService.Post(siteId, userId, file);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class ShopCartItemController : ControllerBase {
|
||||
|
||||
private readonly ILogger<ContentController> _logger;
|
||||
private readonly IShopCartItemService _shopCartItemService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="shopCartItemService"></param>
|
||||
public ShopCartItemController(
|
||||
ILogger<ContentController> logger,
|
||||
IShopCartItemService shopCartItemService
|
||||
) {
|
||||
_logger = logger;
|
||||
_shopCartItemService = shopCartItemService;
|
||||
}
|
||||
|
||||
|
||||
@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class ShopCartItemsController : ControllerBase {
|
||||
|
||||
private readonly ILogger<ContentController> _logger;
|
||||
private readonly IShopCartItemsService _shopCartItemsService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="shopCartItemsService"></param>
|
||||
public ShopCartItemsController(
|
||||
ILogger<ContentController> logger,
|
||||
IShopCartItemsService shopCartItemsService
|
||||
) {
|
||||
_logger = logger;
|
||||
_shopCartItemsService = shopCartItemsService;
|
||||
}
|
||||
|
||||
|
||||
@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers {
|
||||
[Route("api/[controller]")]
|
||||
public class ShopItemController : ControllerBase {
|
||||
|
||||
private readonly ILogger<ShopItemController> _logger;
|
||||
private readonly IShopItemService _shopItemService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="shopItemService"></param>
|
||||
public ShopItemController(
|
||||
ILogger<ShopItemController> logger,
|
||||
IShopItemService shopItemService
|
||||
) {
|
||||
_logger = logger;
|
||||
_shopItemService = shopItemService;
|
||||
}
|
||||
|
||||
|
||||
@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers;
|
||||
[Route("api/[controller]")]
|
||||
public class ShopItemsController : ControllerBase {
|
||||
|
||||
private readonly ILogger<ShopItemsController> _logger;
|
||||
private readonly IShopItemsService _shopItemsService;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="shopCatalogService"></param>
|
||||
public ShopItemsController(
|
||||
ILogger<ShopItemsController> logger,
|
||||
IShopItemsService shopCatalogService
|
||||
) {
|
||||
_logger = logger;
|
||||
_shopItemsService = shopCatalogService;
|
||||
}
|
||||
|
||||
|
||||
@ -10,20 +10,14 @@ namespace WeatherForecast.Controllers;
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase {
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
private static readonly string[] Summaries = new[] {
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger) {
|
||||
_logger = logger;
|
||||
}
|
||||
public WeatherForecastController() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
||||
217
webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs
Normal file
217
webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using DomainResults.Common;
|
||||
using ExtensionMethods;
|
||||
|
||||
namespace WeatherForecast.Services.Abstractions {
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum FileCategory {
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Document,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Image,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Video
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class FileSignature {
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public List<string> Signatures { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string ContentType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public FileCategory FileCategory { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="signatures"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="fileCategory"></param>
|
||||
public FileSignature(List<string> signatures, string contentType, FileCategory fileCategory) {
|
||||
Signatures = signatures;
|
||||
ContentType = contentType;
|
||||
FileCategory = fileCategory;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class FileServiceBase {
|
||||
|
||||
/// <summary>
|
||||
/// https://gist.github.com/qti3e/6341245314bf3513abb080677cd1c93b
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, FileSignature> _data = new() {
|
||||
#region Documents
|
||||
{
|
||||
".pdf",
|
||||
new FileSignature(new List<string> {
|
||||
"0,25504446"
|
||||
}, "application/pdf", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".rtf",
|
||||
new FileSignature(new List<string> {
|
||||
"0,7B5C72746631"
|
||||
}, "application/rtf", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".doc",
|
||||
new FileSignature(new List<string> {
|
||||
"0,0D444F43",
|
||||
"0,CF11E0A1B11AE100",
|
||||
"0,D0CF11E0A1B11AE1",
|
||||
"0,DBA52D00",
|
||||
"512,ECA5C100"
|
||||
}, "application/msword", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".xls",
|
||||
new FileSignature(new List<string> {
|
||||
"512,0908100000060500",
|
||||
"0,D0CF11E0A1B11AE1",
|
||||
"512,FDFFFFFF04",
|
||||
"512,FDFFFFFF20000000"
|
||||
}, "application/vnd.ms-excel", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".ppt",
|
||||
new FileSignature(new List<string> {
|
||||
"512,006E1EF0",
|
||||
"512,0F00E803",
|
||||
"512,A0461DF0",
|
||||
"0,D0CF11E0A1B11AE1",
|
||||
"512,FDFFFFFF04"
|
||||
}, "application/vnd.ms-powerpoint", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".docx",
|
||||
new FileSignature(new List<string> {
|
||||
"0,504B030414000600"
|
||||
}, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".xlsx",
|
||||
new FileSignature(new List<string> {
|
||||
"0,504B030414000600"
|
||||
}, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", FileCategory.Document)
|
||||
},
|
||||
{
|
||||
".pptx",
|
||||
new FileSignature(new List<string> {
|
||||
"0,504B030414000600"
|
||||
}, "application/vnd.openxmlformats-officedocument.presentationml.presentation", FileCategory.Document)
|
||||
},
|
||||
#endregion
|
||||
|
||||
#region Images
|
||||
{
|
||||
".jpg",
|
||||
new FileSignature(new List<string> {
|
||||
"0,FFD8"
|
||||
}, "image/jpeg", FileCategory.Image)
|
||||
},
|
||||
{
|
||||
".jpeg",
|
||||
new FileSignature(new List<string> {
|
||||
"0,FFD8"
|
||||
}, "image/jpeg", FileCategory.Image)
|
||||
},
|
||||
{
|
||||
".jpe",
|
||||
new FileSignature(new List<string> {
|
||||
"0,FFD8"
|
||||
}, "image/jpeg", FileCategory.Image)
|
||||
},
|
||||
{
|
||||
".jfif",
|
||||
new FileSignature(new List<string> {
|
||||
"0,FFD8"
|
||||
}, "image/jpeg", FileCategory.Image)
|
||||
},
|
||||
|
||||
{
|
||||
".png",
|
||||
new FileSignature(new List<string> {
|
||||
"0,89504E470D0A1A0A"
|
||||
}, "image/png", FileCategory.Image)
|
||||
},
|
||||
|
||||
{
|
||||
".webp",
|
||||
new FileSignature(new List<string> {
|
||||
"0,52494646"
|
||||
}, "image/webp", FileCategory.Image)
|
||||
}
|
||||
#endregion
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Don't rely on or trust the FileName property without validation.
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="bytes"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <returns></returns>
|
||||
private protected (FileCategory?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType) {
|
||||
|
||||
var data = _data.SingleOrDefault(x => x.Key == Path.GetExtension(fileName).ToLower()).Value;
|
||||
|
||||
if (data == null)
|
||||
return IDomainResult.NotFound<FileCategory?>();
|
||||
|
||||
// check content type
|
||||
if (contentType != data.ContentType)
|
||||
return IDomainResult.Failed<FileCategory?>();
|
||||
|
||||
// check signatures
|
||||
foreach (var signature in data.Signatures) {
|
||||
var splitString = signature.Split(",");
|
||||
|
||||
var offset = splitString[0].ToInt();
|
||||
var signBytes = Enumerable.Range(0, splitString[1].Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(splitString[1].Substring(x, 2), 16))
|
||||
.ToArray();
|
||||
|
||||
var sample = new byte[signBytes.Length];
|
||||
Buffer.BlockCopy(bytes, offset, sample, 0, signBytes.Length);
|
||||
|
||||
int x = sample.Length ^ signBytes.Length;
|
||||
|
||||
// https://www.syncfusion.com/succinctly-free-ebooks/application-security-in-net-succinctly/comparing-byte-arrays
|
||||
for (int i = 0; i < sample.Length && i < signBytes.Length; ++i) {
|
||||
x |= sample[i] ^ signBytes[i];
|
||||
}
|
||||
|
||||
if (x == 0) return IDomainResult.Success(data.FileCategory); ;
|
||||
}
|
||||
|
||||
return IDomainResult.Failed<FileCategory?>(); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,6 +128,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -160,6 +161,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new BlogItemResponseModel(item, categories));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<BlogItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -194,6 +196,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new BlogItemResponseModel(item, categories, locale));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<BlogItemResponseModel>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -229,6 +232,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(item.Id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -253,6 +257,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +103,7 @@ namespace WeatherForecast.Services {
|
||||
: IDomainResult.NotFound<BlogItemsResponseModel?>();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<BlogItemsResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -117,6 +118,7 @@ namespace WeatherForecast.Services {
|
||||
return _blogCatalogDataProvider.DeleteAll(siteId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +101,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -120,6 +121,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new CategoryItemResponseModel(item));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<CategoryItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -141,6 +143,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new CategoryItemResponseModel(item, locale));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<CategoryItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -172,6 +175,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(item.Id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -195,6 +199,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,6 +71,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(items.Select(x => new CategoryItemResponseModel(x)).ToList());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<List<CategoryItemResponseModel>?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -85,6 +86,7 @@ namespace WeatherForecast.Services {
|
||||
return _categoryDataProvider.DeleteAll(siteId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new ContentResponseModel(content));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<ContentResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using DataProviders;
|
||||
using Core;
|
||||
using DataProviders;
|
||||
using DataProviders.Buckets;
|
||||
using DomainResults.Common;
|
||||
using WeatherForecast.Services.Abstractions;
|
||||
|
||||
namespace WeatherForecast.Services {
|
||||
|
||||
@ -8,6 +10,16 @@ namespace WeatherForecast.Services {
|
||||
///
|
||||
/// </summary>
|
||||
public interface IFileService {
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
(Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -30,7 +42,7 @@ namespace WeatherForecast.Services {
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class FileService : IFileService {
|
||||
public class FileService : FileServiceBase, IFileService {
|
||||
|
||||
private readonly ILogger<FilesService> _logger;
|
||||
private readonly IImagesBucketDataProvider _imageBucketDataProvider;
|
||||
@ -48,6 +60,51 @@ namespace WeatherForecast.Services {
|
||||
_imageBucketDataProvider = imageBucketDataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="siteId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public (Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file) {
|
||||
try {
|
||||
if (!(file.Length > 0))
|
||||
return IDomainResult.Failed<Guid?>();
|
||||
|
||||
using var ms = new MemoryStream();
|
||||
file.CopyTo(ms);
|
||||
var bytes = ms.ToArray();
|
||||
|
||||
var (fileCategory, signatureResult) = CheckFileSignature(file.FileName, bytes, file.ContentType);
|
||||
|
||||
if(!signatureResult.IsSuccess || fileCategory == null)
|
||||
return IDomainResult.Failed<Guid?>();
|
||||
|
||||
var bucketFile = new BucketFile(file.FileName, bytes, file.ContentType);
|
||||
|
||||
IDomainResult result;
|
||||
Guid? fileId;
|
||||
|
||||
switch (fileCategory) {
|
||||
case FileCategory.Image:
|
||||
(fileId, result) = _imageBucketDataProvider.Upload(siteId, userId, bucketFile);
|
||||
break;
|
||||
default:
|
||||
return IDomainResult.Failed<Guid?>();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess || fileId == null)
|
||||
return IDomainResult.Failed<Guid?>();
|
||||
|
||||
return IDomainResult.Success(fileId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -64,6 +121,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(file);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<BucketFile?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -80,6 +138,7 @@ namespace WeatherForecast.Services {
|
||||
return _imageBucketDataProvider.DeleteOne(siteId, userId, fileId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
using DataProviders;
|
||||
using DataProviders.Buckets;
|
||||
using DomainResults.Common;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WeatherForecast.Services.Abstractions;
|
||||
|
||||
namespace WeatherForecast.Services {
|
||||
|
||||
@ -31,7 +31,7 @@ namespace WeatherForecast.Services {
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class FilesService : IFilesService {
|
||||
public class FilesService : FileServiceBase, IFilesService {
|
||||
|
||||
private readonly ILogger<FilesService> _logger;
|
||||
private readonly IImagesBucketDataProvider _imageBucketDataProvider;
|
||||
@ -60,14 +60,15 @@ namespace WeatherForecast.Services {
|
||||
try {
|
||||
// Don't rely on or trust the FileName property without validation.
|
||||
|
||||
if(files.Any(x => !(x.Length > 0)))
|
||||
return IDomainResult.Failed<List<Guid>?>();
|
||||
|
||||
var newFiles = new List<BucketFile>();
|
||||
foreach (var formFile in files) {
|
||||
if (formFile.Length > 0) {
|
||||
using var ms = new MemoryStream();
|
||||
formFile.CopyTo(ms);
|
||||
using var ms = new MemoryStream();
|
||||
formFile.CopyTo(ms);
|
||||
|
||||
newFiles.Add(new BucketFile(formFile.FileName, ms.ToArray(), formFile.ContentType));
|
||||
}
|
||||
newFiles.Add(new BucketFile(formFile.FileName, ms.ToArray(), formFile.ContentType));
|
||||
}
|
||||
|
||||
var (list, result) = _imageBucketDataProvider.UploadMany(siteId, userId, newFiles);
|
||||
@ -78,6 +79,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(list);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<List<Guid>?> (ex.Message);
|
||||
}
|
||||
}
|
||||
@ -93,6 +95,7 @@ namespace WeatherForecast.Services {
|
||||
return _imageBucketDataProvider.DeletMany(siteId, userId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,6 +108,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -138,6 +139,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new ShopCartItemResponseModel(item, cartItem, Enumeration.FromDisplayName<Locales>(locale ?? "en-US")));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<ShopCartItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -173,6 +175,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(item.Id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -197,6 +200,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +88,7 @@ namespace WeatherForecast.Services {
|
||||
: IDomainResult.NotFound<List<ShopCartItemResponseModel>?>();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<List<ShopCartItemResponseModel>?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -103,6 +104,7 @@ namespace WeatherForecast.Services {
|
||||
return _shopCartDataProvider.DeleteAll(siteId, userId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +133,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
|
||||
@ -166,6 +167,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new ShopItemResponseModel(item, categories));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<ShopItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -199,6 +201,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(new ShopItemResponseModel(item, categories, locale));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<ShopItemResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -233,6 +236,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success(item.Id);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<Guid?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -256,6 +260,7 @@ namespace WeatherForecast.Services {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,6 +105,7 @@ namespace WeatherForecast.Services {
|
||||
: IDomainResult.NotFound<ShopItemsResponseModel?>();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed<ShopItemsResponseModel?>(ex.Message);
|
||||
}
|
||||
}
|
||||
@ -119,6 +120,7 @@ namespace WeatherForecast.Services {
|
||||
return _shopCatalogDataProvider.DeleteAll(siteId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Unhandled exception");
|
||||
return IDomainResult.Failed(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user