refactoring some of codes
All checks were successful
Build and Deploy LSFE / build-and-deploy (push) Successful in 1m43s
All checks were successful
Build and Deploy LSFE / build-and-deploy (push) Successful in 1m43s
This commit is contained in:
parent
15656becac
commit
015422a507
2
.gitignore
vendored
2
.gitignore
vendored
@ -361,3 +361,5 @@ MigrationBackup/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
**/appsettings.Production.json
|
||||
|
||||
12
LSFE.Application/Common/Exceptions/BusinessRuleException.cs
Normal file
12
LSFE.Application/Common/Exceptions/BusinessRuleException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Exceptions
|
||||
{
|
||||
public class BusinessRuleException : Exception
|
||||
{
|
||||
public BusinessRuleException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
}
|
||||
12
LSFE.Application/Common/Exceptions/ForbiddenException.cs
Normal file
12
LSFE.Application/Common/Exceptions/ForbiddenException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Exceptions
|
||||
{
|
||||
public class ForbiddenException : Exception
|
||||
{
|
||||
public ForbiddenException()
|
||||
: base("You do not have permission to perform this action.") { }
|
||||
}
|
||||
}
|
||||
12
LSFE.Application/Common/Exceptions/NotFoundException.cs
Normal file
12
LSFE.Application/Common/Exceptions/NotFoundException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Exceptions
|
||||
{
|
||||
public class NotFoundException : Exception
|
||||
{
|
||||
public NotFoundException(string name, object key)
|
||||
: base($"Entity '{name}' with key '{key}' was not found.") { }
|
||||
}
|
||||
}
|
||||
12
LSFE.Application/Common/Exceptions/UnauthorizedException.cs
Normal file
12
LSFE.Application/Common/Exceptions/UnauthorizedException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Exceptions
|
||||
{
|
||||
public class UnauthorizedException : Exception
|
||||
{
|
||||
public UnauthorizedException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
}
|
||||
20
LSFE.Application/Common/Exceptions/ValidationException.cs
Normal file
20
LSFE.Application/Common/Exceptions/ValidationException.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using FluentValidation.Results;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Exceptions
|
||||
{
|
||||
public class ValidationException : Exception
|
||||
{
|
||||
public IDictionary<string, string[]> Errors { get; }
|
||||
|
||||
public ValidationException(IEnumerable<ValidationFailure> failures)
|
||||
: base("One or more validation errors occurred.")
|
||||
{
|
||||
Errors = failures
|
||||
.GroupBy(f => f.PropertyName, f => f.ErrorMessage)
|
||||
.ToDictionary(g => g.Key, g => g.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
14
LSFE.Application/Common/Models/ErrorResponse.cs
Normal file
14
LSFE.Application/Common/Models/ErrorResponse.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LSFE.Application.Common.Models
|
||||
{
|
||||
public class ErrorResponse
|
||||
{
|
||||
public int StatusCode { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public IDictionary<string, string[]>? Errors { get; set; }
|
||||
public string? StackTrace { get; set; }
|
||||
}
|
||||
}
|
||||
13
LSFE.Application/LSFE.Application.csproj
Normal file
13
LSFE.Application/LSFE.Application.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation" Version="12.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -30,7 +30,6 @@ namespace LSFE.Infrastructure.Converter
|
||||
}
|
||||
else if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
// Handle object format if needed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
LSFE.sln
6
LSFE.sln
@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sql", "Sql", "{F7832112-A88
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LSFE.MobApp", "LSFE.MobApp\LSFE.MobApp.csproj", "{7AD0D34F-BE46-4141-8D95-9870FE8C1FEC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LSFE.Application", "LSFE.Application\LSFE.Application.csproj", "{478AA6B2-E2AA-4ED5-B266-936F913D4996}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -41,6 +43,10 @@ Global
|
||||
{7AD0D34F-BE46-4141-8D95-9870FE8C1FEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7AD0D34F-BE46-4141-8D95-9870FE8C1FEC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7AD0D34F-BE46-4141-8D95-9870FE8C1FEC}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{478AA6B2-E2AA-4ED5-B266-936F913D4996}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{478AA6B2-E2AA-4ED5-B266-936F913D4996}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{478AA6B2-E2AA-4ED5-B266-936F913D4996}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{478AA6B2-E2AA-4ED5-B266-936F913D4996}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@ -45,8 +45,6 @@ namespace LSFE.API.Controllers.Account
|
||||
[HttpPost("Login")]
|
||||
public async Task<IActionResult> Login([FromBody] Users model,
|
||||
[FromServices] IAccountService tokenService)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(model.UserName.ToLower());
|
||||
if (user == null)
|
||||
@ -67,7 +65,7 @@ namespace LSFE.API.Controllers.Account
|
||||
return Ok(new
|
||||
{
|
||||
token,
|
||||
expiration = DateTime.UtcNow.AddMinutes(30),
|
||||
expiration = DateTime.Now.AddMinutes(30),
|
||||
userId = user.Id,
|
||||
userName = user.UserName,
|
||||
fullName = user.FullName,
|
||||
@ -83,20 +81,8 @@ namespace LSFE.API.Controllers.Account
|
||||
|
||||
return await HandleFailedLogin(user, signInResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = ex.InnerException?.Message ?? ex.Message;
|
||||
return BadRequest(new Infrastructure.Model.Response
|
||||
{
|
||||
Success = false,
|
||||
MessCode = 0,
|
||||
Message = message
|
||||
});
|
||||
}
|
||||
}
|
||||
protected async Task HandleSuccessfulLogin(AppsUsers user)
|
||||
{
|
||||
// Unlock if necessary
|
||||
if (user.LockoutEnabled || user.LockoutEnd != null)
|
||||
{
|
||||
await _userManager.SetLockoutEnabledAsync(user, false);
|
||||
@ -104,13 +90,11 @@ namespace LSFE.API.Controllers.Account
|
||||
await _userManager.UpdateAsync(user);
|
||||
}
|
||||
|
||||
// Reset failed attempts
|
||||
await _userManager.ResetAccessFailedCountAsync(user);
|
||||
}
|
||||
protected async Task<IActionResult> HandleFailedLogin(AppsUsers user,
|
||||
Microsoft.AspNetCore.Identity.SignInResult signInResult)
|
||||
{
|
||||
// Increment failed attempts
|
||||
await _userManager.AccessFailedAsync(user);
|
||||
|
||||
if (user.AccessFailedCount > 3 || signInResult.IsLockedOut)
|
||||
|
||||
@ -15,77 +15,17 @@ namespace LSFE.API.Controllers
|
||||
{
|
||||
private readonly IWebHostEnvironment _env;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
// public IConfiguration _configuration;
|
||||
public BaseController(IUnitOfWork unitOfWork,
|
||||
IWebHostEnvironment env)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_env = env;
|
||||
// _configuration = configuration;
|
||||
}
|
||||
/* [NonAction]
|
||||
[AllowAnonymous]
|
||||
[HttpPost("{EMailTemplate}")]
|
||||
public string EMailTemplate(string relativePath, string emailTemplate)
|
||||
{
|
||||
try
|
||||
{
|
||||
string templateFolderPath = Path.Combine(_webHostEnvironment.ContentRootPath, relativePath);
|
||||
string templateFilePath = Path.Combine(templateFolderPath, emailTemplate);
|
||||
|
||||
if (System.IO.File.Exists(templateFilePath))
|
||||
{
|
||||
string body = System.IO.File.ReadAllText(templateFilePath);
|
||||
return body;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"File not found: {templateFilePath}");
|
||||
return "Template file not found";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = ex.ToString() ?? ex.InnerException.ToString();
|
||||
*//* PostErrorMessage(errorMessage, "WebApi");*//*
|
||||
throw;
|
||||
}
|
||||
}*/
|
||||
/* [NonAction]
|
||||
[AllowAnonymous]
|
||||
[HttpPost("{GetRelativePath}")]
|
||||
public string GetRelativePath(string relativePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string templateFolderPath = Path.Combine(_webHostEnvironment.ContentRootPath, relativePath);
|
||||
return templateFolderPath;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}*/
|
||||
/* [NonAction]
|
||||
[HttpPost("{ErrMessage}")]
|
||||
public async Task PostErrorMessage(string errMessage, string appName)
|
||||
{
|
||||
var errorMessage = new ErrorMessage
|
||||
{
|
||||
CreatedDate = DateTime.Now,
|
||||
Message = errMessage,
|
||||
Application = appName,
|
||||
CreatedBy = appName
|
||||
|
||||
};
|
||||
await ErrorMessageService.PostErrorMessage(errorMessage);
|
||||
}*/
|
||||
[NonAction]
|
||||
[HttpPost("{ErrorHandling}")]
|
||||
protected async Task<IActionResult> ExecuteWithErrorHandling<T>(
|
||||
Func<Task<T>> operation, string methodName, bool isPost)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await operation();
|
||||
if (isPost)
|
||||
@ -93,14 +33,6 @@ namespace LSFE.API.Controllers
|
||||
return Ok(new { success = true, messCode = 1, message = "Operation completed successfully", data = result });
|
||||
}
|
||||
return Ok(result);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorMessage = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
||||
// await PostErrorMessage(errorMessage, $"WebApi {methodName}");
|
||||
return BadRequest(new { success = false, messCode = 0, message = errorMessage });
|
||||
}
|
||||
}
|
||||
[NonAction]
|
||||
public async Task<IActionResult> LogAndReturnBadRequest(string message, string? userId)
|
||||
|
||||
@ -109,8 +109,6 @@ namespace LSFE.API.Controllers
|
||||
#region Get
|
||||
[HttpGet("inventory")]
|
||||
public async Task<IActionResult> GetInventory([FromQuery] InventoryDto dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inventory = await _unitOfWork.Inventory.GetAllAsync();
|
||||
var filtered = dto.UserRole == "ADMIN" || dto.UserRole == "DSM"
|
||||
@ -119,13 +117,6 @@ namespace LSFE.API.Controllers
|
||||
|
||||
return Ok(filtered);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.ToString();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,10 +99,8 @@ namespace LSFE.API.Controllers
|
||||
}
|
||||
else if (dto.ProductId == 0 || dto.ProductId == null)
|
||||
{
|
||||
// Only generate GUID for new products without file
|
||||
dto.ProductLink = Guid.NewGuid().ToString();
|
||||
}
|
||||
// For updates without new file, keep existing ProductLink
|
||||
|
||||
var response = await _unitOfWork.Products.AddOrUpdateAsync(dto);
|
||||
if (response.Success)
|
||||
@ -215,12 +213,9 @@ namespace LSFE.API.Controllers
|
||||
}
|
||||
|
||||
[HttpGet("productFile/{fileName}")]
|
||||
[ResponseCache(Duration = 3600)] // Cache for 1 hour
|
||||
[ResponseCache(Duration = 3600)]
|
||||
public async Task<IActionResult> GetProductFile(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Validate filename
|
||||
if (string.IsNullOrWhiteSpace(fileName) || fileName.Contains(".."))
|
||||
{
|
||||
return BadRequest("Invalid file name");
|
||||
@ -230,18 +225,11 @@ namespace LSFE.API.Controllers
|
||||
var filePath = Path.Combine(uploadsPath, fileName);
|
||||
|
||||
ContentTypeHelper.ValidateFile(filePath, uploadsPath);
|
||||
|
||||
// Stream the file instead of loading entirely into memory
|
||||
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var contentType = ContentTypeHelper.GetContentType(fileName);
|
||||
|
||||
return File(fileStream, contentType, fileName, enableRangeProcessing: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, "Error retrieving file");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("areas/{id:int}")]
|
||||
public async Task<IActionResult> GetAreaById(int id)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using LSFE.Domain.Contracts;
|
||||
using LSFE.Domain.Helpers;
|
||||
using LSFE.Infrastructure.Dto;
|
||||
using LSFE.Infrastructure.Dto.Reports;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LSFE.Application\LSFE.Application.csproj" />
|
||||
<ProjectReference Include="..\LSFE.Domain\LSFE.Domain.csproj" />
|
||||
<ProjectReference Include="..\LSFE.Infrastructure\LSFE.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
80
LSFE/Middleware/GlobalExceptionMiddleware.cs
Normal file
80
LSFE/Middleware/GlobalExceptionMiddleware.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using LSFE.Application.Common.Exceptions;
|
||||
using LSFE.Application.Common.Models;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LSFE.API.Middleware
|
||||
{
|
||||
public class GlobalExceptionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<GlobalExceptionMiddleware> _logger;
|
||||
private readonly IHostEnvironment _env;
|
||||
|
||||
public GlobalExceptionMiddleware(
|
||||
RequestDelegate next,
|
||||
ILogger<GlobalExceptionMiddleware> logger,
|
||||
IHostEnvironment env)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
_env = env;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unhandled exception: {Message}", ex.Message);
|
||||
await HandleExceptionAsync(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleExceptionAsync(HttpContext context, Exception ex)
|
||||
{
|
||||
var (statusCode, message, errors) = ex switch
|
||||
{
|
||||
ValidationException e => (StatusCodes.Status422UnprocessableEntity,
|
||||
e.Message, e.Errors),
|
||||
|
||||
NotFoundException e => (StatusCodes.Status404NotFound,
|
||||
e.Message, null),
|
||||
|
||||
UnauthorizedException e => (StatusCodes.Status401Unauthorized,
|
||||
e.Message, null),
|
||||
|
||||
ForbiddenException e => (StatusCodes.Status403Forbidden,
|
||||
e.Message, null),
|
||||
|
||||
BusinessRuleException e => (StatusCodes.Status409Conflict,
|
||||
e.Message, null),
|
||||
|
||||
UnauthorizedAccessException e => (StatusCodes.Status401Unauthorized,
|
||||
e.Message, null),
|
||||
|
||||
OperationCanceledException _ => (StatusCodes.Status499ClientClosedRequest,
|
||||
"Request was cancelled.", null),
|
||||
|
||||
_ => (StatusCodes.Status500InternalServerError,
|
||||
"An unexpected error occurred. Please try again later.", null)
|
||||
};
|
||||
|
||||
var response = new ErrorResponse
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Message = message,
|
||||
Errors = errors,
|
||||
StackTrace = _env.IsDevelopment() ? ex.StackTrace : null
|
||||
};
|
||||
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.StatusCode = statusCode;
|
||||
|
||||
await context.Response.WriteAsJsonAsync(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user