diff --git a/webapi/Services/ImageService/Class1.cs b/webapi/Services/ImageService/Class1.cs
new file mode 100644
index 0000000..9aad34a
--- /dev/null
+++ b/webapi/Services/ImageService/Class1.cs
@@ -0,0 +1,5 @@
+namespace ImageService {
+ public class Class1 {
+
+ }
+}
\ No newline at end of file
diff --git a/webapi/Services/ImageService/ImageService.csproj b/webapi/Services/ImageService/ImageService.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/webapi/Services/ImageService/ImageService.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/webapi/WeatherForecast.sln b/webapi/WeatherForecast.sln
index d349497..d59ef98 100644
--- a/webapi/WeatherForecast.sln
+++ b/webapi/WeatherForecast.sln
@@ -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}
diff --git a/webapi/WeatherForecast/Controllers/BlogItemController.cs b/webapi/WeatherForecast/Controllers/BlogItemController.cs
index d3c58d0..fad234d 100644
--- a/webapi/WeatherForecast/Controllers/BlogItemController.cs
+++ b/webapi/WeatherForecast/Controllers/BlogItemController.cs
@@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class BlogItemController : ControllerBase {
- private readonly ILogger _logger;
private readonly IBlogItemService _blogItemService;
///
///
///
- ///
///
public BlogItemController(
- ILogger logger,
IBlogItemService blogItemService
) {
- _logger = logger;
_blogItemService = blogItemService;
}
diff --git a/webapi/WeatherForecast/Controllers/BlogItemsController.cs b/webapi/WeatherForecast/Controllers/BlogItemsController.cs
index 43f832a..6230e07 100644
--- a/webapi/WeatherForecast/Controllers/BlogItemsController.cs
+++ b/webapi/WeatherForecast/Controllers/BlogItemsController.cs
@@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers;
[Route("api/[controller]")]
public class BlogItemsController : ControllerBase {
- private readonly ILogger _logger;
private readonly IBlogItemsService _blogItemsService;
///
///
///
- ///
///
public BlogItemsController(
- ILogger logger,
IBlogItemsService blogItemsService
) {
- _logger = logger;
_blogItemsService = blogItemsService;
}
diff --git a/webapi/WeatherForecast/Controllers/CategoryItemController.cs b/webapi/WeatherForecast/Controllers/CategoryItemController.cs
index 17b2e33..a0efb1f 100644
--- a/webapi/WeatherForecast/Controllers/CategoryItemController.cs
+++ b/webapi/WeatherForecast/Controllers/CategoryItemController.cs
@@ -16,18 +16,14 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class CategoryItemController : ControllerBase {
- private readonly ILogger _logger;
private readonly ICategoryItemService _categoryItemService;
///
///
///
- ///
///
public CategoryItemController(
- ILogger logger,
ICategoryItemService categoryItemService) {
- _logger = logger;
_categoryItemService = categoryItemService;
}
diff --git a/webapi/WeatherForecast/Controllers/CategoryItemsController.cs b/webapi/WeatherForecast/Controllers/CategoryItemsController.cs
index 02ab1dd..96270b8 100644
--- a/webapi/WeatherForecast/Controllers/CategoryItemsController.cs
+++ b/webapi/WeatherForecast/Controllers/CategoryItemsController.cs
@@ -15,22 +15,16 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class CategoryItemsController : ControllerBase {
- private readonly ILogger _logger;
private readonly ICategoryItemsService _categoryItemsService;
///
///
///
- ///
///
public CategoryItemsController(
- ILogger logger,
ICategoryItemsService categoryItemsService
) {
- _logger = logger;
_categoryItemsService = categoryItemsService;
-
-
}
///
diff --git a/webapi/WeatherForecast/Controllers/ContentController.cs b/webapi/WeatherForecast/Controllers/ContentController.cs
index 67a2419..5e55410 100644
--- a/webapi/WeatherForecast/Controllers/ContentController.cs
+++ b/webapi/WeatherForecast/Controllers/ContentController.cs
@@ -15,7 +15,6 @@ namespace WeatherForecast.Controllers;
[Route("api/[controller]")]
public class ContentController : ControllerBase {
- private readonly ILogger _logger;
private readonly IContentService _contentService;
///
@@ -24,10 +23,8 @@ public class ContentController : ControllerBase {
///
///
public ContentController(
- ILogger logger,
IContentService contentService
) {
- _logger = logger;
_contentService = contentService;
}
diff --git a/webapi/WeatherForecast/Controllers/FileController.cs b/webapi/WeatherForecast/Controllers/FileController.cs
index 86ea2fb..79c5343 100644
--- a/webapi/WeatherForecast/Controllers/FileController.cs
+++ b/webapi/WeatherForecast/Controllers/FileController.cs
@@ -30,6 +30,19 @@ namespace WeatherForecast.Controllers {
///
///
///
+ ///
+ ///
+ ///
+ [HttpPost("{siteId}/{userId}")]
+ public IActionResult Post([FromRoute] Guid siteId, [FromRoute] Guid userId, IFormFile file) {
+ var result = _fileService.Post(siteId, userId, file);
+ return result.ToActionResult();
+ }
+
+ ///
+ /// https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/
+ ///
+ ///
///
///
///
diff --git a/webapi/WeatherForecast/Controllers/ShopCartItemController.cs b/webapi/WeatherForecast/Controllers/ShopCartItemController.cs
index bbc169c..dd0ac2d 100644
--- a/webapi/WeatherForecast/Controllers/ShopCartItemController.cs
+++ b/webapi/WeatherForecast/Controllers/ShopCartItemController.cs
@@ -17,19 +17,15 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class ShopCartItemController : ControllerBase {
- private readonly ILogger _logger;
private readonly IShopCartItemService _shopCartItemService;
///
///
///
- ///
///
public ShopCartItemController(
- ILogger logger,
IShopCartItemService shopCartItemService
) {
- _logger = logger;
_shopCartItemService = shopCartItemService;
}
diff --git a/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs b/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs
index c494b95..0e84366 100644
--- a/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs
+++ b/webapi/WeatherForecast/Controllers/ShopCartItemsController.cs
@@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class ShopCartItemsController : ControllerBase {
- private readonly ILogger _logger;
private readonly IShopCartItemsService _shopCartItemsService;
///
///
///
- ///
///
public ShopCartItemsController(
- ILogger logger,
IShopCartItemsService shopCartItemsService
) {
- _logger = logger;
_shopCartItemsService = shopCartItemsService;
}
diff --git a/webapi/WeatherForecast/Controllers/ShopItemController.cs b/webapi/WeatherForecast/Controllers/ShopItemController.cs
index 7b4e865..01de26b 100644
--- a/webapi/WeatherForecast/Controllers/ShopItemController.cs
+++ b/webapi/WeatherForecast/Controllers/ShopItemController.cs
@@ -16,19 +16,15 @@ namespace WeatherForecast.Controllers {
[Route("api/[controller]")]
public class ShopItemController : ControllerBase {
- private readonly ILogger _logger;
private readonly IShopItemService _shopItemService;
///
///
///
- ///
///
public ShopItemController(
- ILogger logger,
IShopItemService shopItemService
) {
- _logger = logger;
_shopItemService = shopItemService;
}
diff --git a/webapi/WeatherForecast/Controllers/ShopItemsController.cs b/webapi/WeatherForecast/Controllers/ShopItemsController.cs
index b91eac7..b89a615 100644
--- a/webapi/WeatherForecast/Controllers/ShopItemsController.cs
+++ b/webapi/WeatherForecast/Controllers/ShopItemsController.cs
@@ -15,19 +15,15 @@ namespace WeatherForecast.Controllers;
[Route("api/[controller]")]
public class ShopItemsController : ControllerBase {
- private readonly ILogger _logger;
private readonly IShopItemsService _shopItemsService;
///
///
///
- ///
///
public ShopItemsController(
- ILogger logger,
IShopItemsService shopCatalogService
) {
- _logger = logger;
_shopItemsService = shopCatalogService;
}
diff --git a/webapi/WeatherForecast/Controllers/WeatherForecastController.cs b/webapi/WeatherForecast/Controllers/WeatherForecastController.cs
index 9b51b2a..e74f658 100644
--- a/webapi/WeatherForecast/Controllers/WeatherForecastController.cs
+++ b/webapi/WeatherForecast/Controllers/WeatherForecastController.cs
@@ -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 _logger;
+ private static readonly string[] Summaries = new[] {
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ };
///
///
///
- ///
- public WeatherForecastController(ILogger logger) {
- _logger = logger;
- }
+ public WeatherForecastController() { }
///
///
diff --git a/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs b/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs
new file mode 100644
index 0000000..d1bb4ea
--- /dev/null
+++ b/webapi/WeatherForecast/Services/Abstractions/FileServiceBase.cs
@@ -0,0 +1,217 @@
+using DomainResults.Common;
+using ExtensionMethods;
+
+namespace WeatherForecast.Services.Abstractions {
+
+ ///
+ ///
+ ///
+ public enum FileCategory {
+ ///
+ ///
+ ///
+ Document,
+
+ ///
+ ///
+ ///
+ Image,
+
+ ///
+ ///
+ ///
+ Video
+ }
+
+ ///
+ ///
+ ///
+ public class FileSignature {
+
+ ///
+ ///
+ ///
+ public List Signatures { get; private set; }
+
+ ///
+ ///
+ ///
+ public string ContentType { get; private set; }
+
+ ///
+ ///
+ ///
+ public FileCategory FileCategory { get; private set; }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public FileSignature(List signatures, string contentType, FileCategory fileCategory) {
+ Signatures = signatures;
+ ContentType = contentType;
+ FileCategory = fileCategory;
+ }
+ }
+
+ ///
+ ///
+ ///
+ public abstract class FileServiceBase {
+
+ ///
+ /// https://gist.github.com/qti3e/6341245314bf3513abb080677cd1c93b
+ ///
+ private readonly Dictionary _data = new() {
+ #region Documents
+ {
+ ".pdf",
+ new FileSignature(new List {
+ "0,25504446"
+ }, "application/pdf", FileCategory.Document)
+ },
+ {
+ ".rtf",
+ new FileSignature(new List {
+ "0,7B5C72746631"
+ }, "application/rtf", FileCategory.Document)
+ },
+ {
+ ".doc",
+ new FileSignature(new List {
+ "0,0D444F43",
+ "0,CF11E0A1B11AE100",
+ "0,D0CF11E0A1B11AE1",
+ "0,DBA52D00",
+ "512,ECA5C100"
+ }, "application/msword", FileCategory.Document)
+ },
+ {
+ ".xls",
+ new FileSignature(new List {
+ "512,0908100000060500",
+ "0,D0CF11E0A1B11AE1",
+ "512,FDFFFFFF04",
+ "512,FDFFFFFF20000000"
+ }, "application/vnd.ms-excel", FileCategory.Document)
+ },
+ {
+ ".ppt",
+ new FileSignature(new List {
+ "512,006E1EF0",
+ "512,0F00E803",
+ "512,A0461DF0",
+ "0,D0CF11E0A1B11AE1",
+ "512,FDFFFFFF04"
+ }, "application/vnd.ms-powerpoint", FileCategory.Document)
+ },
+ {
+ ".docx",
+ new FileSignature(new List {
+ "0,504B030414000600"
+ }, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", FileCategory.Document)
+ },
+ {
+ ".xlsx",
+ new FileSignature(new List {
+ "0,504B030414000600"
+ }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", FileCategory.Document)
+ },
+ {
+ ".pptx",
+ new FileSignature(new List {
+ "0,504B030414000600"
+ }, "application/vnd.openxmlformats-officedocument.presentationml.presentation", FileCategory.Document)
+ },
+ #endregion
+
+ #region Images
+ {
+ ".jpg",
+ new FileSignature(new List {
+ "0,FFD8"
+ }, "image/jpeg", FileCategory.Image)
+ },
+ {
+ ".jpeg",
+ new FileSignature(new List {
+ "0,FFD8"
+ }, "image/jpeg", FileCategory.Image)
+ },
+ {
+ ".jpe",
+ new FileSignature(new List {
+ "0,FFD8"
+ }, "image/jpeg", FileCategory.Image)
+ },
+ {
+ ".jfif",
+ new FileSignature(new List {
+ "0,FFD8"
+ }, "image/jpeg", FileCategory.Image)
+ },
+
+ {
+ ".png",
+ new FileSignature(new List {
+ "0,89504E470D0A1A0A"
+ }, "image/png", FileCategory.Image)
+ },
+
+ {
+ ".webp",
+ new FileSignature(new List {
+ "0,52494646"
+ }, "image/webp", FileCategory.Image)
+ }
+ #endregion
+ };
+
+
+ ///
+ /// Don't rely on or trust the FileName property without validation.
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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();
+
+ // check content type
+ if (contentType != data.ContentType)
+ return IDomainResult.Failed();
+
+ // 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(); ;
+ }
+ }
+}
diff --git a/webapi/WeatherForecast/Services/BlogItemService.cs b/webapi/WeatherForecast/Services/BlogItemService.cs
index baf2f7c..b72408d 100644
--- a/webapi/WeatherForecast/Services/BlogItemService.cs
+++ b/webapi/WeatherForecast/Services/BlogItemService.cs
@@ -128,6 +128,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(id);
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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(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(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(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);
}
}
diff --git a/webapi/WeatherForecast/Services/BlogItemsService.cs b/webapi/WeatherForecast/Services/BlogItemsService.cs
index 278bc1f..f11734a 100644
--- a/webapi/WeatherForecast/Services/BlogItemsService.cs
+++ b/webapi/WeatherForecast/Services/BlogItemsService.cs
@@ -103,6 +103,7 @@ namespace WeatherForecast.Services {
: IDomainResult.NotFound();
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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);
}
}
diff --git a/webapi/WeatherForecast/Services/CategoryItemService.cs b/webapi/WeatherForecast/Services/CategoryItemService.cs
index 4ae0e88..5bf4ed8 100644
--- a/webapi/WeatherForecast/Services/CategoryItemService.cs
+++ b/webapi/WeatherForecast/Services/CategoryItemService.cs
@@ -101,6 +101,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(id);
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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(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(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(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);
}
}
diff --git a/webapi/WeatherForecast/Services/CategoryItemsService.cs b/webapi/WeatherForecast/Services/CategoryItemsService.cs
index bf219eb..393de15 100644
--- a/webapi/WeatherForecast/Services/CategoryItemsService.cs
+++ b/webapi/WeatherForecast/Services/CategoryItemsService.cs
@@ -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?>(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);
}
}
diff --git a/webapi/WeatherForecast/Services/ContentService.cs b/webapi/WeatherForecast/Services/ContentService.cs
index 5c1a0be..fcdcaa4 100644
--- a/webapi/WeatherForecast/Services/ContentService.cs
+++ b/webapi/WeatherForecast/Services/ContentService.cs
@@ -57,6 +57,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(new ContentResponseModel(content));
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(ex.Message);
}
}
diff --git a/webapi/WeatherForecast/Services/FileService.cs b/webapi/WeatherForecast/Services/FileService.cs
index c634a61..46f89a8 100644
--- a/webapi/WeatherForecast/Services/FileService.cs
+++ b/webapi/WeatherForecast/Services/FileService.cs
@@ -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 {
///
///
public interface IFileService {
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ (Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file);
+
///
///
///
@@ -30,7 +42,7 @@ namespace WeatherForecast.Services {
///
///
///
- public class FileService : IFileService {
+ public class FileService : FileServiceBase, IFileService {
private readonly ILogger _logger;
private readonly IImagesBucketDataProvider _imageBucketDataProvider;
@@ -48,6 +60,51 @@ namespace WeatherForecast.Services {
_imageBucketDataProvider = imageBucketDataProvider;
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public (Guid?, IDomainResult) Post(Guid siteId, Guid userId, IFormFile file) {
+ try {
+ if (!(file.Length > 0))
+ return IDomainResult.Failed();
+
+ 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();
+
+ 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();
+ }
+
+ if (!result.IsSuccess || fileId == null)
+ return IDomainResult.Failed();
+
+ return IDomainResult.Success(fileId);
+ }
+ catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
+ return IDomainResult.Failed(ex.Message);
+ }
+ }
+
///
///
///
@@ -64,6 +121,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(file);
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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);
}
}
diff --git a/webapi/WeatherForecast/Services/FilesService.cs b/webapi/WeatherForecast/Services/FilesService.cs
index 76767c1..673cc9f 100644
--- a/webapi/WeatherForecast/Services/FilesService.cs
+++ b/webapi/WeatherForecast/Services/FilesService.cs
@@ -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 {
///
///
///
- public class FilesService : IFilesService {
+ public class FilesService : FileServiceBase, IFilesService {
private readonly ILogger _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?>();
+
var newFiles = new List();
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?> (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);
}
}
diff --git a/webapi/WeatherForecast/Services/ShopCartItemService.cs b/webapi/WeatherForecast/Services/ShopCartItemService.cs
index 30077b6..5956275 100644
--- a/webapi/WeatherForecast/Services/ShopCartItemService.cs
+++ b/webapi/WeatherForecast/Services/ShopCartItemService.cs
@@ -108,6 +108,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(id);
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(ex.Message);
}
}
@@ -138,6 +139,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(new ShopCartItemResponseModel(item, cartItem, Enumeration.FromDisplayName(locale ?? "en-US")));
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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(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);
}
}
diff --git a/webapi/WeatherForecast/Services/ShopCartItemsService.cs b/webapi/WeatherForecast/Services/ShopCartItemsService.cs
index 3e4d6e5..13e82b6 100644
--- a/webapi/WeatherForecast/Services/ShopCartItemsService.cs
+++ b/webapi/WeatherForecast/Services/ShopCartItemsService.cs
@@ -88,6 +88,7 @@ namespace WeatherForecast.Services {
: IDomainResult.NotFound?>();
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed?>(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);
}
}
diff --git a/webapi/WeatherForecast/Services/ShopItemService.cs b/webapi/WeatherForecast/Services/ShopItemService.cs
index 2f36382..705e6c3 100644
--- a/webapi/WeatherForecast/Services/ShopItemService.cs
+++ b/webapi/WeatherForecast/Services/ShopItemService.cs
@@ -133,6 +133,7 @@ namespace WeatherForecast.Services {
return IDomainResult.Success(id);
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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(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(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(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);
}
}
diff --git a/webapi/WeatherForecast/Services/ShopItemsService.cs b/webapi/WeatherForecast/Services/ShopItemsService.cs
index c8086d0..4951bda 100644
--- a/webapi/WeatherForecast/Services/ShopItemsService.cs
+++ b/webapi/WeatherForecast/Services/ShopItemsService.cs
@@ -105,6 +105,7 @@ namespace WeatherForecast.Services {
: IDomainResult.NotFound();
}
catch (Exception ex) {
+ _logger.LogError(ex, "Unhandled exception");
return IDomainResult.Failed(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);
}
}