Commit 24de3ed6 authored by hasan khaddour's avatar hasan khaddour

final commit

parent 0b7ddf50
......@@ -17,6 +17,7 @@ namespace PSManagement.Api.DI
services
.AddApiSwagger()
.AddApiCors()
.AddMyMiddlewares()
;
return services;
......@@ -87,6 +88,14 @@ namespace PSManagement.Api.DI
}
#endregion Cors
#region Middlewares
private static IServiceCollection AddMyMiddlewares(this IServiceCollection services) {
return services;
}
#endregion Middlewares
}
......
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PSManagement.Api.Middleware.ExceptionHandler
{
public class ExceptionHandlingMidllerware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMidllerware> _logger;
public ExceptionHandlingMidllerware(
RequestDelegate next,
ILogger<ExceptionHandlingMidllerware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception exception)
{
_logger.LogError(exception, "Exception occurred: {Message}", exception.Message);
var exceptionDetails = GetExceptionDetails(exception);
var problemDetails = new ProblemDetails
{
Status = exceptionDetails.Status,
Type = exceptionDetails.Type,
Title = exceptionDetails.Title,
Detail = exceptionDetails.Detail
};
if (exceptionDetails.Errors is not null)
{
problemDetails.Extensions["errors"] = exceptionDetails.Errors;
}
context.Response.StatusCode = exceptionDetails.Status;
await context.Response.WriteAsJsonAsync(problemDetails);
}
}
private static ExceptionDetails GetExceptionDetails(Exception exception)
{
return exception switch
{
_ => new ExceptionDetails(
StatusCodes.Status500InternalServerError,
"ServerError",
"Server error",
"An unexpected error has occurred",
null)
};
}
internal record ExceptionDetails(
int Status,
string Type,
string Title,
string Detail,
IEnumerable<object>? Errors);
}
}
......@@ -32,8 +32,4 @@
<ProjectReference Include="..\PSManagement.SharedKernel\PSManagement.SharedKernel.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Middleware\ExceptionHandler\" />
</ItemGroup>
</Project>
......@@ -15,6 +15,7 @@ using System.Threading.Tasks;
using PSManagement.Infrastructure.Persistence.DI;
using PSManagement.Api.DI;
using PSManagement.Presentation.DependencyInjection;
using PSManagement.Api.Middleware.ExceptionHandler;
namespace PSManagement.Api
{
......@@ -50,6 +51,10 @@ namespace PSManagement.Api
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PSManagement.Api v1"));
}
else {
app.UseMiddleware<ExceptionHandlingMidllerware>();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
......
......@@ -2,6 +2,7 @@
using PSManagement.Application.FinancialSpends.Common;
using PSManagement.Application.FinancialSpends.UseCases.Commands.CreateFinancialSpendItem;
using PSManagement.Domain.FinancialSpends.Entities;
using PSManagement.Application.FinancialSpends.UseCases.Commands.UpateFinancialSpendingItem;
namespace PSManagement.Application.Mappers
{
......@@ -27,6 +28,10 @@ namespace PSManagement.Application.Mappers
))
;
CreateMap<UpdateFinancialSpendItemCommand, FinancialSpending>()
;
}
}
......
......@@ -50,7 +50,15 @@ namespace PSManagement.Application.FinancialSpends.UseCases.Commands.UpateFinanc
{
return Result.NotFound();
}
await _spendRepository.UpdateAsync(_mapper.Map<FinancialSpending>(request));
// System.Console.WriteLine(request);
spending.ExternalPurchase=request.ExternalPurchase;
spending.LocalPurchase=request.LocalPurchase;
spending.CostType=request.CostType;
spending.Description=request.Description;
spending.ExpectedSpendingDate=request.ExpectedSpendingDate;
await _spendRepository.UpdateAsync(spending);
await _unitOfWork.SaveChangesAsync();
return Result.Success();
......
......@@ -37,6 +37,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.AddAttachment
public async Task<Result<int>> Handle(AddAttachmentCommand request, CancellationToken cancellationToken)
{
_unitOfWork.BeginTransaction();
_specification.AddInclude(e => e.Attachments);
// save the file on the uploaded files
......@@ -52,7 +53,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.AddAttachment
// checking if the project exist
if (project is null)
{
await _unitOfWork.Rollback();
return Result.Invalid(ProjectsErrors.InvalidEntryError);
}
......@@ -65,6 +66,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.AddAttachment
}
else {
await _unitOfWork.Rollback();
return Result.Invalid(pathResult.ValidationErrors);
}
}
......
......@@ -41,6 +41,8 @@ namespace PSManagement.Application.Projects.UseCases.Commands.AddParticipant
public async Task<Result> Handle(AddParticipantCommand request, CancellationToken cancellationToken)
{
_unitOfWork.BeginTransaction();
_specification.AddInclude(e => e.EmployeeParticipates);
Project project =await _projectsRepository.GetByIdAsync(request.ProjectId,_specification);
......@@ -51,7 +53,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.AddParticipant
if (project.HasParticipant(request.ParticipantId))
{
await _unitOfWork.Rollback();
return Result.Invalid(ProjectsErrors.ParticipantExistError);
}
else {
......
......@@ -33,6 +33,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.CreateProject
public async Task<Result<int>> Handle(CreateProjectCommand request, CancellationToken cancellationToken)
{
_unitOfWork.BeginTransaction();
var type = await _projectTypesRepository.GetByIdAsync(request.ProjectTypeId);
if (type is null) {
......@@ -67,6 +68,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.CreateProject
await _unitOfWork.SaveChangesAsync();
return Result.Success(project.Id);
}
......
......@@ -8,6 +8,7 @@ using PSManagement.SharedKernel.CQRS.Command;
using PSManagement.SharedKernel.Specification;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
namespace PSManagement.Application.ProjectsTypes.UseCases.Commands.CreateNewType
{
......@@ -27,15 +28,17 @@ namespace PSManagement.Application.ProjectsTypes.UseCases.Commands.CreateNewType
public async Task<Result> Handle(RemoveTypeCommand request, CancellationToken cancellationToken)
{
_specification.AddInclude(e => e.Projects);
var result = await _projectTypesRepository.GetByIdAsync(request.typeId ,_specification);
if (result is null)
{
return Result.Invalid(ProjectTypesErrors.InvalidEntryError);
}
if (result.Projects is not null )
if (result.Projects.Count()!=0 )
{
return Result.Invalid(ProjectTypesErrors.InvalidEntryError);
return Result.Invalid(ProjectTypesErrors.UnEmptyProjects);
}
await _projectTypesRepository.DeleteAsync(result);
......
......@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace PSManagement.Domain.Identity.Constants
{
/// <summary>
/// Provide a role nmaes
/// Provide a role names
/// </summary>
/// this classs provide a contant role names
/// gathering the roles source in a one place make change roles easier
......
......@@ -278,8 +278,12 @@ namespace PSManagement.Domain.Projects.Entities
var participate = EmployeeParticipates.Where(e => e.EmployeeId == participantId).FirstOrDefault();
AddDomainEvent(new ParticipationChangedEvent(
participantId,
participate.PartialTimeRatio, partialTimeRation,
role, participate.Role, Id, DateTime.Now));
participate.PartialTimeRatio,
partialTimeRation,
participate.Role,
role,
Id,
DateTime.Now));
participate.Role = role;
......
......@@ -4,7 +4,9 @@ namespace PSManagement.Domain.Projects.DomainErrors
{
public class ProjectTypesErrors
{
public static DomainError InvalidEntryError { get; } = new("ProjectErrors.InvalidEntry.", "Invalid Step Data");
public static DomainError InvalidEntryError { get; } = new("ProjectErrors.InvalidEntry.", "Invalid project type Data");
public static DomainError InvalidName { get; } = new("ProjectErrors.InvalidEntry.", "the name is already exist");
public static DomainError UnEmptyProjects { get; } = new("ProjectErrors.InvalidEntry.", "the type already has a projects ");
}
}
......@@ -57,6 +57,8 @@ namespace PSManagement.Infrastructure.Services.Storage
{
return Result.Invalid(new ValidationError("File not found."));
}
// Get the content type based on the file extension
var contentType = GetContentType(filePath);
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
......@@ -69,10 +71,28 @@ namespace PSManagement.Infrastructure.Services.Storage
IFormFile formFile = new FormFile(memoryStream, 0, memoryStream.Length, null, Path.GetFileName(filePath))
{
Headers = new HeaderDictionary(),
ContentType = "application/octet-stream"
ContentType = contentType
};
return Result.Success(formFile);
}
private string GetContentType(string filePath)
{
var extension = Path.GetExtension(filePath).ToLowerInvariant();
return extension switch
{
".pdf" => "application/pdf",
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".doc" or ".docx" => "application/msword",
".xls" or ".xlsx" => "application/vnd.ms-excel",
".txt" => "text/plain",
_ => "application/octet-stream",
};
}
}
}
using AutoMapper;
using MediatR;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Mvc;
using PSManagement.Application.Projects.UseCases.Commands.AddAttachment;
using PSManagement.Application.Projects.UseCases.Commands.CreateProject;
......@@ -343,9 +346,20 @@ namespace PSManagement.Presentation.Controllers.Projects
{
var query = _mapper.Map<GetFileByUrlQuery>(request);
var result = await _sender.Send(query);
if(result.IsSuccess){
return HandleResult(_mapper.Map<Result<FileAttachmentResponse>>(result));
var fileAttachment = result.Value;
// Return the file with the correct content type and file name
var memoryStream = new MemoryStream();
await fileAttachment.File.CopyToAsync(memoryStream);
memoryStream.Position = 0; // Reset the stream position to the beginning
// Return the file with the correct content type and file name
return File(memoryStream, fileAttachment.File.ContentType, fileAttachment.AttachmentName);
}
return BadRequest();
}
#endregion Attachments Management
}
......
......@@ -22,19 +22,25 @@ using System.Threading.Tasks;
using PSManagement.Application.Tracks.UseCaes.Queries.GetTracksByFilter;
namespace PSManagement.Presentation.Controllers.Tracks
{
[Route("api/[controller]")]
public class TracksController : APIController
{
#region Dependencies
private readonly IMapper _mapper;
private readonly IMediator _sender;
#endregion Dependencies
#region Constructor
public TracksController(IMediator sender, IMapper mapper)
{
_sender = sender;
_mapper = mapper;
}
#endregion Constructor
#region Queries On Tracks
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
......@@ -97,7 +103,9 @@ namespace PSManagement.Presentation.Controllers.Tracks
return HandleResult(result);
}
#endregion Queries On Tracks
#region Step Tracks
[HttpPost("AddStepTrack")]
public async Task<IActionResult> PostStepTrack(AddStepTrackRequest request)
{
......@@ -108,6 +116,21 @@ namespace PSManagement.Presentation.Controllers.Tracks
return HandleResult(result);
}
[HttpPut("UpdateStepTrack")]
public async Task<IActionResult> PutStepTrack(UpdateStepTrackRequest request)
{
var command = _mapper.Map<UpdateStepTrackCommand>(request);
var result = await _sender.Send(command);
return HandleResult(result);
}
#endregion Step Tracks
#region Employee Tracks
[HttpPost("AddEmployeeTrack")]
public async Task<IActionResult> PostEmployeeTrack(AddEmployeeTrackRequest request)
{
......@@ -118,6 +141,23 @@ namespace PSManagement.Presentation.Controllers.Tracks
return HandleResult(result);
}
[HttpPut("UpdateEmployeeWorkTrack")]
public async Task<IActionResult> PutEmployeeWorkTrack(UpdateEmployeeWorkTrackRequest request)
{
var command = _mapper.Map<UpdateEmployeeWorkTrackCommand>(request);
var result = await _sender.Send(command);
return HandleResult(result);
}
#endregion Employee Tracks
#region Tracks Management
[HttpPost("CompleteTrack")]
public async Task<IActionResult> PostCompleteTrack(CompleteTrackRequest request)
{
......@@ -161,28 +201,7 @@ namespace PSManagement.Presentation.Controllers.Tracks
}
}
[HttpPut("UpdateEmployeeWorkTrack")]
public async Task<IActionResult> PutEmployeeWorkTrack(UpdateEmployeeWorkTrackRequest request)
{
var command = _mapper.Map<UpdateEmployeeWorkTrackCommand>(request);
var result = await _sender.Send(command);
return HandleResult(result);
}
[HttpPut("UpdateStepTrack")]
public async Task<IActionResult> PutStepTrack(UpdateStepTrackRequest request)
{
var command = _mapper.Map<UpdateStepTrackCommand>(request);
var result = await _sender.Send(command);
return HandleResult(result);
}
#endregion Tracks Management
}
}
# Project Status Managment Server
> in this file we will explain the solution\
> and discuss the used patterns and architecture
___
## Table Of Contents
1. Theoretical Introduction
2. Sotuion Components
3. Shared Kernel
4. Domain Layer
5. Applciation Layer
6. Presentaion Layer
7. Infratstucture Layer
8. Architecture Tests
9. Integeration With LDAP Explaination
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment