zinab_elgendy 9 mesiacov pred
rodič
commit
8d9592da69

+ 25 - 0
Dockerfile

@@ -0,0 +1,25 @@
+FROM mcr.microsoft.com/dotnet/aspnet:8.0  AS base
+WORKDIR /app
+EXPOSE 8080
+EXPOSE 443
+
+FROM mcr.microsoft.com/dotnet/sdk:8.0  AS build
+WORKDIR /src
+COPY ["MTWorkHR.API/MTWorkHR.API.csproj", "MTWorkHR.API/"]
+COPY ["MTWorkHR.Application/MTWorkHR.Application.csproj", "MTWorkHR.Application/"]
+COPY ["MTWorkHR.Core/MTWorkHR.Core.csproj", "MTWorkHR.Core/"]
+COPY ["MTWorkHR.Identity/MTWorkHR.Identity.csproj", "MTWorkHR.Identity/"]
+COPY ["MTWorkHR.Infrastructure/MTWorkHR.Infrastructure.csproj", "MTWorkHR.Infrastructure/"]
+RUN dotnet restore "MTWorkHR.API/MTWorkHR.API.csproj"
+COPY . .
+WORKDIR "/src//MTWorkHR.API"
+RUN dotnet build "MTWorkHR.API.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "MTWorkHR.API.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "MTWorkHR.API.dll"]
+

+ 4 - 1
MTWorkHR.API/appsettings.json

@@ -23,7 +23,10 @@
   "DbConfig": {
     "RunMigrations": true
   },
-
+  "AttachmentSettings": {
+    "TempAttachment": "C:\\Attachment\\Temp",
+    "ActualAttachment": "C:\\Attachment\\Actual"
+  },
   "MailSettings": {
     "ApiKey": "SendGrid-Key",
     "FromAddress": "eng_z@live.com",

+ 3 - 0
MTWorkHR.Application/ApplicationServiceRegistration.cs

@@ -2,6 +2,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using MTWorkHR.Application.Identity;
 using MTWorkHR.Application.Services;
+using MTWorkHR.Application.Services.Interfaces;
 using MTWorkHR.Core.Global;
 using MTWorkHR.Identity.Services;
 using System.Reflection;
@@ -20,6 +21,8 @@ namespace MTWorkHR.Application
 
             services.AddTransient<IAuthService, AuthService>();
             services.AddTransient<IUserService, UserService>();
+            services.AddTransient<IFileService, FileService>();
+            
             return services;
         }
     }

+ 1 - 1
MTWorkHR.Application/Mapper/MapperObject.cs

@@ -5,7 +5,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace MTWorkHR.Application.MappingProfiles
+namespace MTWorkHR.Application.Mapper
 {
     public class MapperObject 
     {

+ 2 - 2
MTWorkHR.Application/Mapper/MappingProfile.cs

@@ -9,7 +9,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace MTWorkHR.Application.MappingProfiles
+namespace MTWorkHR.Application.Mapper
 {
     public class MappingProfile : Profile
     {
@@ -37,7 +37,7 @@ namespace MTWorkHR.Application.MappingProfiles
 
             CreateMap<ApplicationUser, UserUpdateDto>();
 
-            CreateMap<UserAttachmentDto, UserAttachment>().ReverseMap();
+            CreateMap<AttachmentDto, UserAttachment>().ReverseMap();
             CreateMap<UserAddress, UserAddressDto>().ReverseMap();
 
             //identity userRoles

+ 1 - 1
MTWorkHR.Application/Models/Identity/UserAttachmentDto.cs

@@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema;
 
 namespace MTWorkHR.Application.Models
 {
-    public class UserAttachmentDto
+    public class AttachmentDto
     {
         public long AttachmentTypeId { get; set; }
 

+ 1 - 1
MTWorkHR.Application/Models/Identity/UserDto.cs

@@ -35,7 +35,7 @@ namespace MTWorkHR.Application.Models
         public decimal IncomeTaxValue { get; set; }
 
         public IList<UserRoleDto>? UserRoles { get; set; }
-        public IList<UserAttachmentDto>? UserAttachments{ get; set; }
+        public IList<AttachmentDto>? UserAttachments{ get; set; }
         public UserAddressDto? UserAddress{ get; set; }
     }
 }

+ 8 - 3
MTWorkHR.Application/Services/Auth/UserService.cs

@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.WebUtilities;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Configuration;
 using MTWorkHR.Application.Identity;
-using MTWorkHR.Application.MappingProfiles;
+using MTWorkHR.Application.Mapper;
 using MTWorkHR.Application.Models;
 using MTWorkHR.Application.Services;
 using MTWorkHR.Application.Models.Email;
@@ -20,6 +20,7 @@ using NeomtechERP.Auth.Core.Global;
 using Microsoft.AspNetCore.Identity.UI.Services;
 using IEmailSender = MTWorkHR.Application.Services.IEmailSender;
 using System.Security.Policy;
+using MTWorkHR.Application.Services.Interfaces;
 
 namespace MTWorkHR.Identity.Services
 {
@@ -32,10 +33,11 @@ namespace MTWorkHR.Identity.Services
         private readonly AppSettingsConfiguration _configuration;
         private readonly IEmailSender _emailSender;
         private readonly GlobalInfo _globalInfo;
+        private readonly IFileService _fileService;
 
         public UserService(ApplicationUserManager userManager, IUnitOfWork unitOfWork
              , RoleManager<ApplicationRole> roleManager, GlobalInfo globalInfo, AppSettingsConfiguration configuration, IEmailSender emailSender
-            , IUserRoleRepository<IdentityUserRole<string>> userRole)
+            , IUserRoleRepository<IdentityUserRole<string>> userRole, IFileService fileService)
         {
             _userManager = userManager;
             _unitOfWork = unitOfWork;
@@ -44,6 +46,7 @@ namespace MTWorkHR.Identity.Services
             _configuration = configuration;
             _emailSender = emailSender;
             _globalInfo = globalInfo;
+            _fileService = fileService;
         }
         public async Task<UserDto> GetById(string userId)
         {
@@ -94,7 +97,9 @@ namespace MTWorkHR.Identity.Services
             var userExists = await _userManager.FindByAnyAsync(input.UserName);
             if (userExists != null)
                 throw new AppException(ExceptionEnum.RecordAlreadyExist);
-
+            //loop for given list of attachment, and move each file from Temp path to Actual path
+            if (!_fileService.CopyFileToActualFolder(input.UserAttachments.ToList()))
+                throw new AppException(ExceptionEnum.CouldNotMoveFiles);
             var user = MapperObject.Mapper.Map<ApplicationUser>(input);
 
             _unitOfWork.BeginTran();

+ 299 - 0
MTWorkHR.Application/Services/Base/BaseService.cs

@@ -0,0 +1,299 @@
+
+using MTWorkHR.Application.Models;
+using MTWorkHR.Application.Services.Interfaces;
+using MTWorkHR.Core.Entities.Base;
+using MTWorkHR.Core.Global;
+using MTWorkHR.Core.IRepositories.Base;
+using MTWorkHR.Core.UnitOfWork;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Application.Services
+{
+    public class BaseService<TEntity, TDto, TGetAllDto> : IService<TEntity, TDto, TGetAllDto>
+        where TEntity : class
+        where TDto : EntityDto
+        where TGetAllDto : class
+    {
+        private readonly IUnitOfWork unitOfWork;
+        private readonly IRepository<TEntity> repository;
+
+        public BaseService(IUnitOfWork _unitOfWork)
+        {
+            unitOfWork = _unitOfWork;
+            repository = (IRepository<TEntity>)unitOfWork.GetRepositoryByName(typeof(TEntity).Name);
+
+        }
+        //Task<IPagingResultDto<TGetAllDto>> IService<TEntity, TDto, TGetAllDto>.GetAll(int pageNumber, int pageSize, string orderByField, string orderType)
+        //{
+        //    throw new NotImplementedException();
+        //}
+        public virtual async Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto)
+        {
+            var result = await repository.GetAllAsync();
+
+            var list = Mapper.MapperObject.Mapper.Map<IList<TGetAllDto>>(result.Item1);
+
+            var response = new PagingResultDto<TGetAllDto>
+            {
+                Result = list,
+                Total = result.Item2
+            };
+
+            return response;
+        }
+
+        public virtual async Task<TDto> GetById(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            var response = Mapper.MapperObject.Mapper.Map<TDto>(entity);
+
+            return response;
+        }
+
+        public virtual async Task Delete(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            if (entity == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            var isSoftDelete = typeof(TEntity).GetInterfaces().Any(x => x == typeof(ISoftDelete));
+
+            if (isSoftDelete)
+            {
+                ((ISoftDelete)entity).IsDeleted = true;
+            }
+            else
+            {
+                await repository.DeleteAsync(entity);
+            }
+
+            await unitOfWork.CompleteAsync();
+        }
+
+        public virtual async Task<TDto> Create(TDto input)
+        {
+            var employeeEntitiy = Mapper.MapperObject.Mapper.Map<TEntity>(input);
+            if (employeeEntitiy is null)
+            {
+                throw new AppException(ExceptionEnum.MapperIssue);
+            }
+
+            var newEmployee = await repository.AddAsync(employeeEntitiy);
+            await unitOfWork.CompleteAsync();
+
+            var response = Mapper.MapperObject.Mapper.Map<TDto>(newEmployee);
+            return response;
+        }
+
+        public virtual async Task<TDto> Update(TDto input)
+        {
+            var entitiy = await repository.GetByIdAsync(input.Id);
+
+            if (entitiy == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            Mapper.MapperObject.Mapper.Map(input, entitiy, typeof(TDto), typeof(TEntity));
+
+            await unitOfWork.CompleteAsync();
+
+            return input;
+        }
+
+
+    }
+    public class BaseService<TEntity, TDto, TUpdatDto, TGetAllDto> : IService<TEntity, TDto, TUpdatDto, TGetAllDto>
+        where TEntity : class
+        where TDto : EntityDto
+        where TUpdatDto : EntityDto
+        where TGetAllDto : class
+    {
+        private readonly IUnitOfWork unitOfWork;
+        private readonly IRepository<TEntity> repository;
+
+        public BaseService(IUnitOfWork _unitOfWork)
+        {
+            unitOfWork = _unitOfWork;
+            repository = (IRepository<TEntity>)unitOfWork.GetRepositoryByName(typeof(TEntity).Name);
+
+        }
+        //Task<IPagingResultDto<TGetAllDto>> IService<TEntity, TDto, TGetAllDto>.GetAll(int pageNumber, int pageSize, string orderByField, string orderType)
+        //{
+        //    throw new NotImplementedException();
+        //}
+        public virtual async Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto)
+        {
+            var result = await repository.GetAllAsync();
+
+            var list = Mapper.MapperObject.Mapper.Map<IList<TGetAllDto>>(result.Item1);
+
+            var response = new PagingResultDto<TGetAllDto>
+            {
+                Result = list,
+                Total = result.Item2
+            };
+
+            return response;
+        }
+
+        public virtual async Task<TDto> GetById(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            var response = Mapper.MapperObject.Mapper.Map<TDto>(entity);
+
+            return response;
+        }
+
+        public virtual async Task Delete(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            if (entity == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            var isSoftDelete = typeof(TEntity).GetInterfaces().Any(x => x == typeof(ISoftDelete));
+
+            if (isSoftDelete)
+            {
+                ((ISoftDelete)entity).IsDeleted = true;
+            }
+            else
+            {
+                await repository.DeleteAsync(entity);
+            }
+
+            await unitOfWork.CompleteAsync();
+        }
+
+        public virtual async Task<TDto> Create(TDto input)
+        {
+            var employeeEntitiy = Mapper.MapperObject.Mapper.Map<TEntity>(input);
+            if (employeeEntitiy is null)
+            {
+                throw new AppException(ExceptionEnum.MapperIssue);
+            }
+
+            var newEmployee = await repository.AddAsync(employeeEntitiy);
+            await unitOfWork.CompleteAsync();
+
+            var response = Mapper.MapperObject.Mapper.Map<TDto>(newEmployee);
+            return response;
+        }
+
+        public virtual async Task<TDto> Update(TUpdatDto input)
+        {
+            var entitiy = await repository.GetByIdAsync(input.Id);
+
+            if (entitiy == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            Mapper.MapperObject.Mapper.Map(input, entitiy, typeof(TDto), typeof(TEntity));
+
+            await unitOfWork.CompleteAsync();
+
+            var response = Mapper.MapperObject.Mapper.Map<TDto>(entitiy);
+
+            return response;
+        }
+    }
+    public class BaseService<TEntity, TGetDto, TCreateDto, TUpdatDto, TGetAllDto> : IService<TEntity, TGetDto, TCreateDto, TUpdatDto, TGetAllDto>
+    where TEntity : class
+    where TGetDto : EntityDto
+    where TCreateDto : EntityDto
+    where TUpdatDto : EntityDto
+    where TGetAllDto : class
+    {
+        private readonly IUnitOfWork unitOfWork;
+        private readonly IRepository<TEntity> repository;
+
+        public BaseService(IUnitOfWork _unitOfWork)
+        {
+            unitOfWork = _unitOfWork;
+            repository = (IRepository<TEntity>)unitOfWork.GetRepositoryByName(typeof(TEntity).Name);
+
+        }
+        //Task<IPagingResultDto<TGetAllDto>> IService<TEntity, TDto, TGetAllDto>.GetAll(int pageNumber, int pageSize, string orderByField, string orderType)
+        //{
+        //    throw new NotImplementedException();
+        //}
+        public virtual async Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto)
+        {
+            var result = await repository.GetAllAsync();
+
+            var list = Mapper.MapperObject.Mapper.Map<IList<TGetAllDto>>(result.Item1);
+
+            var response = new PagingResultDto<TGetAllDto>
+            {
+                Result = list,
+                Total = result.Item2
+            };
+
+            return response;
+        }
+
+        public virtual async Task<TGetDto> GetById(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            var response = Mapper.MapperObject.Mapper.Map<TGetDto>(entity);
+
+            return response;
+        }
+
+        public virtual async Task Delete(long id)
+        {
+            var entity = await repository.GetByIdAsync(id);
+
+            if (entity == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            var isSoftDelete = typeof(TEntity).GetInterfaces().Any(x => x == typeof(ISoftDelete));
+
+            if (isSoftDelete)
+            {
+                ((ISoftDelete)entity).IsDeleted = true;
+            }
+            else
+            {
+                await repository.DeleteAsync(entity);
+            }
+
+            await unitOfWork.CompleteAsync();
+        }
+
+        public virtual async Task<TGetDto> Create(TCreateDto input)
+        {
+            var employeeEntitiy = Mapper.MapperObject.Mapper.Map<TEntity>(input);
+            if (employeeEntitiy is null)
+            {
+                throw new AppException(ExceptionEnum.MapperIssue);
+            }
+
+            var newEmployee = await repository.AddAsync(employeeEntitiy);
+            await unitOfWork.CompleteAsync();
+
+            var response = Mapper.MapperObject.Mapper.Map<TGetDto>(newEmployee);
+            return response;
+        }
+
+        public virtual async Task<TGetDto> Update(TUpdatDto input)
+        {
+            var entitiy = await repository.GetByIdAsync(input.Id);
+
+            if (entitiy == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
+
+            Mapper.MapperObject.Mapper.Map(input, entitiy, typeof(TGetDto), typeof(TEntity));
+
+            await unitOfWork.CompleteAsync();
+
+            var response = Mapper.MapperObject.Mapper.Map<TGetDto>(entitiy);
+
+            return response;
+        }
+    }
+}

+ 196 - 0
MTWorkHR.Application/Services/Base/FileService.cs

@@ -0,0 +1,196 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.StaticFiles;
+using MTWorkHR.Application.Models;
+using MTWorkHR.Application.Services.Interfaces;
+using MTWorkHR.Core.Global;
+using System.Net.Http.Headers;
+
+namespace MTWorkHR.Application.Services
+{
+    public class FileService : IFileService
+    {
+        private readonly AppSettingsConfiguration settings;
+
+        public FileService(AppSettingsConfiguration settings)
+        {
+            this.settings = settings;
+        }
+        public string UploadFile(IFormFile file)
+        {
+            return UploadFiles(new List<IFormFile> { file }).First();
+        }
+
+        public List<string> UploadFiles(List<IFormFile> files)
+        {
+            if (!AttachmentsMust(files))
+                throw new AppException(ExceptionEnum.InvalidFileType);
+
+            string pathToSave = GetTempAttachmentPath();
+            if (!Directory.Exists(pathToSave))
+                Directory.CreateDirectory(pathToSave);
+
+            var fileNames = new List<string>();
+            foreach (var formFile in files)
+            {
+                var fname = ContentDispositionHeaderValue.Parse(formFile.ContentDisposition).FileName.Trim('"');
+                var fnameSplit = fname.Split(".");
+                var fNewName = Guid.NewGuid().ToString() + "." + fnameSplit[fnameSplit.Length - 1];
+                var fullPath = Path.Combine(pathToSave, fNewName);
+                fileNames.Add(fNewName);
+                if (formFile.Length > 0)
+                {
+                    using (var stream = new FileStream(fullPath, FileMode.Create))
+                    {
+                        formFile.CopyToAsync(stream);
+                    }
+                }
+                else
+                    throw new AppException(ExceptionEnum.FileLengthNotCorrect);
+
+            }
+            return fileNames;
+        }
+
+        public async Task<Tuple<MemoryStream,string, string>> GetFileDownloadInfo(string fileUrl)
+        {
+            var filePath = Path.Combine(GetActualAttachmentPath(), fileUrl);
+            if (!System.IO.File.Exists(filePath))
+                throw new AppException(ExceptionEnum.RecordNotExist);
+            var memory = new MemoryStream();
+            await using (var stream = new FileStream(filePath, FileMode.Open))
+            {
+                await stream.CopyToAsync(memory);
+            }
+            memory.Position = 0;
+            return new Tuple<MemoryStream, string, string>(memory, GetContentType(filePath), filePath);
+        }
+
+        private string GetContentType(string path)
+        {
+            var provider = new FileExtensionContentTypeProvider();
+            string contentType;
+
+            if (!provider.TryGetContentType(path, out contentType))
+            {
+                contentType = "application/octet-stream";
+            }
+
+            return contentType;
+        }
+
+        public bool CopyFileToActualFolder(List<AttachmentDto> attachments)
+        {
+         
+            foreach (var attachment in attachments)
+            {
+                if (!Directory.Exists(GetActualAttachmentPath()))
+                    Directory.CreateDirectory(GetActualAttachmentPath());
+                var tempFilePath = Path.Combine(GetTempAttachmentPath(), attachment.FileName);
+                var destinationFilePath = Path.Combine(GetActualAttachmentPath(), attachment.FileName);
+                if (File.Exists(tempFilePath))
+                {
+                    if (!File.Exists(destinationFilePath))
+                        File.Copy(tempFilePath, destinationFilePath);
+                }
+                else
+                    return false;
+            }
+            return true;
+        }
+        public bool CopyFileToActualFolder(string FileName)
+        {
+            if (!Directory.Exists(GetActualAttachmentPath()))
+                Directory.CreateDirectory(GetActualAttachmentPath());
+            var tempFilePath = Path.Combine(GetTempAttachmentPath(), FileName);
+            var destinationFilePath = Path.Combine(GetActualAttachmentPath(), FileName);
+            if (File.Exists(tempFilePath))
+            {
+                if (!File.Exists(destinationFilePath))
+                    File.Copy(tempFilePath, destinationFilePath);
+                return true;
+            }
+            return false;
+        }
+
+        public bool DeleteFileFromTempFolder(string FileName)
+        {
+            try
+            {
+                string pathToRemove = GetTempAttachmentPath();
+                if (Directory.Exists(pathToRemove))
+                {
+                    var tempFilePath = Path.Combine(pathToRemove, FileName);
+                    if (File.Exists(tempFilePath))
+                    {
+                        File.Delete(tempFilePath);
+                    }
+                }
+            }
+            catch (Exception ex) { }
+            return true;
+        }
+        public string GetTempAttachmentPath()
+        {
+            var pathTemp = settings.AttachmentSettings.TempAttachment;
+
+            return pathTemp;
+        }
+        public string GetActualAttachmentPath()
+        {
+            var pathActual = settings.AttachmentSettings.ActualAttachment ;
+
+            return pathActual;
+        }
+       private bool AttachmentsMust(List<IFormFile> files)
+        {
+            // extensions whitelist
+            string[] allowedExtensions = new string[]
+            {
+                ".jpeg"
+                , ".jpg"
+                , ".png"
+                , ".pdf"
+                , ".doc"
+                , ".docx"
+                , ".csv"
+                , ".xls"
+                , ".xlsx"
+                , ".txt"
+                , ".pptx"
+                , ".svg"
+                , ".webp"
+            };
+
+            // MIME types whitelist
+            string[] allowedMIMETypes = new string[]
+            {
+                "image/jpeg"
+                , "image/png"
+                , "application/pdf"
+                , "application/msword"
+                , "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+                , "text/csv"
+                , "application/vnd.ms-excel"
+                , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+                , "text/plain"
+                , "application/vnd.openxmlformats-officedocument.presentationml.presentation"
+                , "image/svg+xml"
+                , "image/webp"
+            };
+
+            foreach (IFormFile file in files)
+            {
+                if (!allowedExtensions.Contains(Path.GetExtension(file.FileName).ToLower()))
+                    return false;
+
+                if (!allowedMIMETypes.Contains(file.ContentType.ToLower()))
+                    return false;
+            }
+
+            return true;
+        }
+
+ 
+    }
+}

+ 23 - 0
MTWorkHR.Application/Services/Interfaces/IFileService.cs

@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Http;
+using MTWorkHR.Application.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Application.Services.Interfaces
+{
+    public interface IFileService
+    {
+        string UploadFile(IFormFile file);
+        List<string> UploadFiles(List<IFormFile> files);
+        bool CopyFileToActualFolder(List<AttachmentDto> attachments);
+        bool CopyFileToActualFolder(string FileName);
+        bool DeleteFileFromTempFolder(string FileName);
+
+        string GetTempAttachmentPath();
+        string GetActualAttachmentPath();
+        Task<Tuple<MemoryStream, string, string>> GetFileDownloadInfo(string fileUrl);
+    }
+}

+ 44 - 0
MTWorkHR.Application/Services/Interfaces/IService.cs

@@ -0,0 +1,44 @@
+using MTWorkHR.Application.Models;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Application.Services.Interfaces
+{
+    public interface IService<TEntity, TDto, TGetAllDto>
+        where TEntity : class
+        where TDto : class
+        where TGetAllDto : class
+    {
+        Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto);
+        Task<TDto> GetById(long id);
+        Task Delete(long id);
+        Task<TDto> Create(TDto input);
+        Task<TDto> Update(TDto input);
+    }
+
+    public interface IService<TEntity, TDto, TUpdatDto, TGetAllDto>
+        where TEntity : class
+        where TDto : class
+        where TUpdatDto : class
+        where TGetAllDto : class
+    {
+        Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto);
+        Task<TDto> GetById(long id);
+        Task Delete(long id);
+        Task<TDto> Create(TDto input);
+        Task<TDto> Update(TUpdatDto input);
+    }
+
+    public interface IService<TEntity, TGetDto,TCreateDto, TUpdatDto, TGetAllDto>
+    where TEntity : class
+    where TGetDto : class
+    where TCreateDto : class
+    where TUpdatDto : class
+    where TGetAllDto : class
+    {
+        Task<PagingResultDto<TGetAllDto>> GetAll(PagingInputDto pagingInputDto);
+        Task<TGetDto> GetById(long id);
+        Task Delete(long id);
+        Task<TGetDto> Create(TCreateDto input);
+        Task<TGetDto> Update(TUpdatDto input);
+    }
+}

+ 5 - 2
MTWorkHR.Core/Global/Enum/ExceptionEnum.cs

@@ -31,6 +31,9 @@ namespace MTWorkHR.Core.Global
 		EmptyResponse=21,
 		ErrorSendingSMS=22,
         InvalidCaptcha = 23,
-		AccountLocked = 24
-	}
+		AccountLocked = 24,
+        InvalidFileType = 25,
+        FileLengthNotCorrect= 26,
+
+    }
 }

+ 4 - 1
MTWorkHR.Core/IRepositories/Base/IRepository.cs

@@ -1,4 +1,5 @@
 using MTWorkHR.Core.Entities.Base;
+using MTWorkHR.Core.IDto;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -7,9 +8,11 @@ using System.Threading.Tasks;
 
 namespace MTWorkHR.Core.IRepositories.Base
 {
-    public interface IRepository<T> where T : Entity
+    public interface IRepository<T> where T : class
     {
         Task<T> GetByIdAsync(long id);
+        //Task<Tuple<ICollection<T>, int>> GetAllAsync(IPagingInputDto pagingInputDto);
+
         Task<Tuple<ICollection<T>, int>> GetAllAsync();
         Task<T> AddAsync(T entity);
         Task<IList<T>> AddRangeAsync(IList<T> entities);

+ 33 - 0
MTWorkHR.Infrastructure/Repositories/Repository.cs

@@ -1,6 +1,8 @@
 using Azure;
+using Microsoft.AspNetCore.Mvc.RazorPages;
 using Microsoft.EntityFrameworkCore;
 using MTWorkHR.Core.Entities.Base;
+using MTWorkHR.Core.IDto;
 using MTWorkHR.Core.IRepositories.Base;
 using MTWorkHR.Infrastructure.Data;
 using System;
@@ -52,6 +54,37 @@ namespace MTWorkHR.Infrastructure.Repositories
             return new Tuple<ICollection<T>, int>(await query.ToListAsync(), total);
         }
 
+        //public virtual async Task<Tuple<ICollection<T>, int>> GetAllAsync(IPagingInputDto pagingInputDto)
+        //{
+        //    //var query = dbSet.AsQueryable();
+
+        //    //if (pagingInputDto.HiddenFilter != null)
+        //    //{
+        //    //    query = query.Where(pagingInputDto.HiddenFilter);
+        //    //}
+
+        //    //if (pagingInputDto.Filter != null)
+        //    //{
+        //    //    var props = typeof(T).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(FilterAttribute)));
+        //    //    var condition = "";
+        //    //    foreach (var p in props)
+        //    //    {
+        //    //        condition = (condition == "" ? condition : condition + " || ") + p.Name + ".Contains(@0)";
+        //    //    }
+
+        //    //    query = query.Where(condition, pagingInputDto.Filter);
+        //    //}
+
+        //    //var order = query.OrderBy(pagingInputDto.OrderByField + " " + pagingInputDto.OrderType);
+
+        //    //var page = order.Skip((pagingInputDto.PageNumber * pagingInputDto.PageSize) - pagingInputDto.PageSize).Take(pagingInputDto.PageSize);
+
+        //    //var total = await query.CountAsync();
+
+        //    //return new Tuple<ICollection<T>, int>(await page.ToListAsync(), total);
+        //    throw new NotImplementedException();
+        //}
+
         public async Task<T> GetByIdAsync(long id)
         {
             return await _context.Set<T>().FindAsync(id);