Commit 8f8ad4cc authored by hasan khaddour's avatar hasan khaddour

add attchement load from file service

parent fb047242
...@@ -15,7 +15,7 @@ namespace PSManagement.Api ...@@ -15,7 +15,7 @@ namespace PSManagement.Api
public static void Main(string[] args) public static void Main(string[] args)
{ {
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information() .MinimumLevel.Warning()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day) .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger(); .CreateLogger();
......
...@@ -11,6 +11,6 @@ namespace PSManagement.Application.Contracts.Storage ...@@ -11,6 +11,6 @@ namespace PSManagement.Application.Contracts.Storage
public interface IFileService public interface IFileService
{ {
public Task<Result<String>> StoreFile(string fileName,IFormFile file); public Task<Result<String>> StoreFile(string fileName,IFormFile file);
public Task<Result<IFormFile>> RetreiveFile(string fileUrl);
} }
} }
using Microsoft.AspNetCore.Http;
namespace PSManagement.Application.Projects.Common
{
public record FileAttachmentDTO(
string AttachmentName,
string AttachmentDescription,
IFormFile File
);
}
...@@ -32,7 +32,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.ApproveProject ...@@ -32,7 +32,7 @@ namespace PSManagement.Application.Projects.UseCases.Commands.ApproveProject
{ {
_specification.AddInclude(e => e.Steps); _specification.AddInclude(e => e.Steps);
Project project = await _projectsRepository.GetByIdAsync(request.ProjectId); Project project = await _projectsRepository.GetByIdAsync(request.ProjectId,_specification);
if (project is null) if (project is null)
{ {
......
using Ardalis.Result;
using PSManagement.Application.Projects.Common;
using PSManagement.SharedKernel.CQRS.Query;
namespace PSManagement.Application.Projects.UseCases.Queries.GetFileByUrl
{
public record GetFileByUrlQuery(
string FileUrl,
int AttachmentId
) : IQuery<Result<FileAttachmentDTO>>;
}
using Ardalis.Result;
using AutoMapper;
using PSManagement.Application.Contracts.Storage;
using PSManagement.Application.Projects.Common;
using PSManagement.Domain.Projects.Entities;
using PSManagement.SharedKernel.CQRS.Query;
using PSManagement.SharedKernel.Repositories;
using System.Threading;
using System.Threading.Tasks;
namespace PSManagement.Application.Projects.UseCases.Queries.GetFileByUrl
{
public class GetFileByUrlQueryHandler : IQueryHandler<GetFileByUrlQuery, Result<FileAttachmentDTO>>
{
private readonly IRepository<Attachment> _attachmentRepository;
private readonly IFileService _fileService;
private readonly IMapper _mapper;
public GetFileByUrlQueryHandler(
IMapper mapper,
IRepository<Attachment> attachmentRepository,
IFileService fileService)
{
_mapper = mapper;
_attachmentRepository = attachmentRepository;
_fileService = fileService;
}
public async Task<Result<FileAttachmentDTO>> Handle(GetFileByUrlQuery request, CancellationToken cancellationToken)
{
var attachment = await _attachmentRepository.GetByIdAsync(request.AttachmentId);
if (attachment is null)
{
return Result.NotFound("Not found ");
}
var result = await _fileService.RetreiveFile(attachment.AttachmentUrl);
if (!result.IsSuccess)
{
return Result.NotFound("Not Found");
}
return Result.Success(new FileAttachmentDTO(attachment.AttachmentName, attachment.AttachmentDescription, result.Value));
}
}
}
...@@ -8,5 +8,4 @@ namespace PSManagement.Application.Projects.UseCases.Queries.GetParticipants ...@@ -8,5 +8,4 @@ namespace PSManagement.Application.Projects.UseCases.Queries.GetParticipants
public record GetProjectParticipantsQuery( public record GetProjectParticipantsQuery(
int ProjectId int ProjectId
) : IQuery<Result<IEnumerable<EmployeeParticipateDTO>>>; ) : IQuery<Result<IEnumerable<EmployeeParticipateDTO>>>;
} }
...@@ -30,6 +30,8 @@ namespace PSManagement.Application.Projects.UseCases.Queries.GetProject ...@@ -30,6 +30,8 @@ namespace PSManagement.Application.Projects.UseCases.Queries.GetProject
public async Task<Result<ProjectDTO>> Handle(GetProjectByIdQuery request, CancellationToken cancellationToken) public async Task<Result<ProjectDTO>> Handle(GetProjectByIdQuery request, CancellationToken cancellationToken)
{ {
_specification.Includes.Add(p=> p.EmployeeParticipates); _specification.Includes.Add(p=> p.EmployeeParticipates);
_specification.AddInclude("EmployeeParticipates.Employee");
_specification.Includes.Add(p => p.FinancialSpending); _specification.Includes.Add(p => p.FinancialSpending);
_specification.Includes.Add(p => p.ProjectManager.Department); _specification.Includes.Add(p => p.ProjectManager.Department);
_specification.Includes.Add(p => p.Attachments); _specification.Includes.Add(p => p.Attachments);
......
...@@ -56,7 +56,7 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.CompleteTrack ...@@ -56,7 +56,7 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.CompleteTrack
} }
if (track.CheckEmployeeTrack()) { if (!track.CheckEmployeeTrack()) {
return Result.Invalid(TracksErrors.InvailEmployeeTrack); return Result.Invalid(TracksErrors.InvailEmployeeTrack);
} }
......
using Ardalis.Result; using Ardalis.Result;
using PSManagement.Domain.Steps.Repositories; using PSManagement.Domain.Steps.Repositories;
using PSManagement.Domain.Tracking; using PSManagement.Domain.Tracking;
using PSManagement.Domain.Tracking.Entities;
using PSManagement.Domain.Tracking.DomainErrors; using PSManagement.Domain.Tracking.DomainErrors;
using PSManagement.Domain.Tracking.Specification;
using PSManagement.SharedKernel.CQRS.Command; using PSManagement.SharedKernel.CQRS.Command;
using PSManagement.SharedKernel.Interfaces; using PSManagement.SharedKernel.Interfaces;
using PSManagement.SharedKernel.Specification;
using PSManagement.SharedKernel.Repositories;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -13,20 +20,31 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.RemoveTrack ...@@ -13,20 +20,31 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.RemoveTrack
{ {
private readonly ITracksRepository _tracksRepository; private readonly ITracksRepository _tracksRepository;
private readonly IUnitOfWork _unitOfWork; private readonly IUnitOfWork _unitOfWork;
private readonly BaseSpecification<Track> _specification;
private readonly IRepository<StepTrack> _stepTracksRepository;
private readonly IRepository<EmployeeTrack> _employeeTracksRepository;
public RemoveTrackCommandHandler( public RemoveTrackCommandHandler(
IUnitOfWork unitOfWork, IUnitOfWork unitOfWork,
ITracksRepository tracksRepository ITracksRepository tracksRepository,
IRepository<StepTrack> stepTracksRepository,
IRepository<EmployeeTrack> employeeTracksRepository
) )
{ {
_employeeTracksRepository=employeeTracksRepository;
_stepTracksRepository = stepTracksRepository;
_specification = new TrackSpecification();
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_tracksRepository = tracksRepository; _tracksRepository = tracksRepository;
} }
public async Task<Result> Handle(RemoveTrackCommand request, CancellationToken cancellationToken) public async Task<Result> Handle(RemoveTrackCommand request, CancellationToken cancellationToken)
{ {
Track track = await _tracksRepository.GetByIdAsync(request.TrackId); _specification.AddInclude(e => e.StepTracks);
_specification.AddInclude(e => e.EmployeeTracks);
Track track = await _tracksRepository.GetByIdAsync(request.TrackId,_specification);
if (track is null) if (track is null)
{ {
...@@ -35,6 +53,14 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.RemoveTrack ...@@ -35,6 +53,14 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.RemoveTrack
} }
foreach(var emp in track.EmployeeTracks){
await _employeeTracksRepository.DeleteAsync(emp);
}
foreach(var emp in track.StepTracks){
await _stepTracksRepository.DeleteAsync(emp);
}
await _tracksRepository.DeleteAsync(track); await _tracksRepository.DeleteAsync(track);
await _unitOfWork.SaveChangesAsync(); await _unitOfWork.SaveChangesAsync();
......
...@@ -56,6 +56,7 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.UpdateEmployeeWorkTra ...@@ -56,6 +56,7 @@ namespace PSManagement.Application.Tracks.UseCaes.Commands.UpdateEmployeeWorkTra
employeeTrack.UpdateEmployeeWorkInfo(request.EmployeeWorkInfo); employeeTrack.UpdateEmployeeWorkInfo(request.EmployeeWorkInfo);
employeeTrack.UpdateNotes(request.Notes); employeeTrack.UpdateNotes(request.Notes);
System.Console.WriteLine(employeeTrack.EmployeeWork);
await _employeeTracksRepository.UpdateAsync(employeeTrack); await _employeeTracksRepository.UpdateAsync(employeeTrack);
......
namespace PSManagement.Contracts.Projects.Requests
{
public record GetFileByUrlRequest(
string FileUrl,
int AttachmentId
);
}
using Microsoft.AspNetCore.Http;
namespace PSManagement.Contracts.Projects.Response
{
public record FileAttachmentResponse(
string AttachmentName,
string AttachmentDescription,
IFormFile File
);
}
...@@ -18,13 +18,13 @@ namespace PSManagement.Domain.Tracking ...@@ -18,13 +18,13 @@ namespace PSManagement.Domain.Tracking
#region Encapsulation #region Encapsulation
public void UpdateEmployeeWork(EmployeeWork employeeWork) public void UpdateEmployeeWork(EmployeeWork employeeWork)
{ {
EmployeeWork = employeeWork; EmployeeWork = new(employeeWork.AssignedWorkingHours,employeeWork.WorkedHours,employeeWork.ContributingRatio);
} }
public void UpdateEmployeeWorkInfo(EmployeeWorkInfo employeeWorkInfo) public void UpdateEmployeeWorkInfo(EmployeeWorkInfo employeeWorkInfo)
{ {
EmployeeWorkInfo = employeeWorkInfo; EmployeeWorkInfo = new (employeeWorkInfo.AssignedWork,employeeWorkInfo.PerformedWork,employeeWorkInfo.AssignedWorkEnd);
} }
public void UpdateNotes(string notes) public void UpdateNotes(string notes)
......
...@@ -53,12 +53,15 @@ namespace PSManagement.Domain.Tracking ...@@ -53,12 +53,15 @@ namespace PSManagement.Domain.Tracking
} }
// this method check if the track is completed
public bool IsCompleted() public bool IsCompleted()
{ {
return TrackInfo.IsCompleted; return TrackInfo.IsCompleted;
} }
// this method check for the exitence of an employee in the track
//
public bool HasEmployee(int employeeId) public bool HasEmployee(int employeeId)
{ {
return EmployeeTracks.Any(e => e.EmployeeId == employeeId); return EmployeeTracks.Any(e => e.EmployeeId == employeeId);
...@@ -80,13 +83,17 @@ namespace PSManagement.Domain.Tracking ...@@ -80,13 +83,17 @@ namespace PSManagement.Domain.Tracking
public bool CheckEmployeeTrack() public bool CheckEmployeeTrack()
{ {
//
int contributions = 0; int contributions = 0;
// calculate the total contribution of participatns in the tracks
foreach (EmployeeTrack employeeTrack in EmployeeTracks) { foreach (EmployeeTrack employeeTrack in EmployeeTracks) {
contributions += employeeTrack.EmployeeWork.ContributingRatio; contributions += employeeTrack.EmployeeWork.ContributingRatio;
} }
// the track can be completed only if the contribution are equal to 100
return contributions == 100; return contributions == 100;
} }
......
...@@ -41,5 +41,38 @@ namespace PSManagement.Infrastructure.Services.Storage ...@@ -41,5 +41,38 @@ namespace PSManagement.Infrastructure.Services.Storage
} }
return Result.Success(fileName); return Result.Success(fileName);
} }
public async Task<Result<IFormFile>> RetreiveFile(string fileUrl)
{
if (string.IsNullOrWhiteSpace(fileUrl))
{
return Result.Invalid(new ValidationError("File URL couldn't be empty."));
}
var filePath = Path.Combine("wwwroot\\uploads", fileUrl);
if (!File.Exists(filePath))
{
return Result.Invalid(new ValidationError("File not found."));
}
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memoryStream);
}
memoryStream.Position = 0; // Reset the stream position to the beginning
// Create a new form file to return
IFormFile formFile = new FormFile(memoryStream, 0, memoryStream.Length, null, Path.GetFileName(filePath))
{
Headers = new HeaderDictionary(),
ContentType = "application/octet-stream"
};
return Result.Success(formFile);
}
} }
} }
...@@ -30,6 +30,7 @@ using PSManagement.Application.Projects.UseCases.Commands.RemoveAttachment; ...@@ -30,6 +30,7 @@ using PSManagement.Application.Projects.UseCases.Commands.RemoveAttachment;
using PSManagement.Application.Projects.UseCases.Queries.GetProjectCompletion; using PSManagement.Application.Projects.UseCases.Queries.GetProjectCompletion;
using PSManagement.Domain.Identity.Constants; using PSManagement.Domain.Identity.Constants;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using PSManagement.Application.Projects.UseCases.Queries.GetFileByUrl;
namespace PSManagement.Presentation.Controllers.Projects namespace PSManagement.Presentation.Controllers.Projects
{ {
...@@ -336,6 +337,15 @@ namespace PSManagement.Presentation.Controllers.Projects ...@@ -336,6 +337,15 @@ namespace PSManagement.Presentation.Controllers.Projects
return HandleResult(_mapper.Map<Result<IEnumerable<AttachmentReponse>>>(result)); return HandleResult(_mapper.Map<Result<IEnumerable<AttachmentReponse>>>(result));
}
[HttpGet("Attachment")]
public async Task<IActionResult> GetAttachments([FromQuery] GetFileByUrlRequest request)
{
var query = _mapper.Map<GetFileByUrlQuery>(request);
var result = await _sender.Send(query);
return HandleResult(_mapper.Map<Result<FileAttachmentResponse>>(result));
} }
#endregion Attachments Management #endregion Attachments Management
} }
......
...@@ -43,11 +43,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{A01E75A3 ...@@ -43,11 +43,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{A01E75A3
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ArchitectureTests", "ArchitectureTests", "{EECB1F9F-F97D-4A58-BC3D-62490B931836}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ArchitectureTests", "ArchitectureTests", "{EECB1F9F-F97D-4A58-BC3D-62490B931836}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{9E74DD5B-202D-4DAD-9A08-3C7340CEF939}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSManagement.ArchitectureTests", "PSManagement.ArchitectureTests\PSManagement.ArchitectureTests.csproj", "{394812BD-ECB4-4B7B-A6FF-4310E145450A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IntegerationTests", "IntegerationTests", "{83FB2F8C-3B65-44D8-A4A7-8E87166233CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PSManagement.ArchitectureTests", "PSManagement.ArchitectureTests\PSManagement.ArchitectureTests.csproj", "{394812BD-ECB4-4B7B-A6FF-4310E145450A}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
...@@ -114,8 +110,6 @@ Global ...@@ -114,8 +110,6 @@ Global
{E40CD9A8-20E3-4D39-992B-F7DA048E3B4C} = {7C209DBF-1DB8-4E86-BD78-F689B70D5BD1} {E40CD9A8-20E3-4D39-992B-F7DA048E3B4C} = {7C209DBF-1DB8-4E86-BD78-F689B70D5BD1}
{2FF0133A-7AC6-4346-AEC2-CB5C36939AC7} = {7C209DBF-1DB8-4E86-BD78-F689B70D5BD1} {2FF0133A-7AC6-4346-AEC2-CB5C36939AC7} = {7C209DBF-1DB8-4E86-BD78-F689B70D5BD1}
{EECB1F9F-F97D-4A58-BC3D-62490B931836} = {A01E75A3-EF06-4880-8EFE-2E2D8EC0FA9F} {EECB1F9F-F97D-4A58-BC3D-62490B931836} = {A01E75A3-EF06-4880-8EFE-2E2D8EC0FA9F}
{9E74DD5B-202D-4DAD-9A08-3C7340CEF939} = {A01E75A3-EF06-4880-8EFE-2E2D8EC0FA9F}
{83FB2F8C-3B65-44D8-A4A7-8E87166233CD} = {A01E75A3-EF06-4880-8EFE-2E2D8EC0FA9F}
{394812BD-ECB4-4B7B-A6FF-4310E145450A} = {EECB1F9F-F97D-4A58-BC3D-62490B931836} {394812BD-ECB4-4B7B-A6FF-4310E145450A} = {EECB1F9F-F97D-4A58-BC3D-62490B931836}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
......
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