Просмотр исходного кода

Remove multipart from userProfile and TaskAttachments,
, use AzureEmail for email sending
, Logger in email and UserService

zinab_elgendy месяцев назад: 2
Родитель
Сommit
d023282c01

+ 4 - 4
MTWorkHR.API/Controllers/CompanyController.cs

@@ -42,19 +42,19 @@ namespace MTWorkHR.API.Controllers
 
         [HttpPost("Create")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Consumes("multipart/form-data")]
+       // [Consumes("multipart/form-data")]
         [AllowAnonymous]
         [AppAuthorize(Permissions = "Company.Create")]
-        public async Task<ActionResult<CompanyDto>> Create([FromForm] CompanyDto input)
+        public async Task<ActionResult<CompanyDto>> Create([FromBody] CompanyDto input)
         {
             return await _companyService.Create(input);
         }
 
         [HttpPost("Update")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Consumes("multipart/form-data")]
+       // [Consumes("multipart/form-data")]
         [AppAuthorize(Permissions = "Company.Update")]
-        public async Task<ActionResult<CompanyDto>> Update([FromForm] CompanyDto input)
+        public async Task<ActionResult<CompanyDto>> Update([FromBody] CompanyDto input)
         {
             return await _companyService.Update(input);
         }

+ 4 - 4
MTWorkHR.API/Controllers/UserController.cs

@@ -62,18 +62,18 @@ namespace MTWorkHR.API.Controllers
 
         [HttpPost("Create")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Consumes("multipart/form-data")]
+       // [Consumes("multipart/form-data")]
         [AppAuthorize(Permissions = "User.Create")]
-        public async Task<ActionResult<UserDto>> Create([FromForm] UserDto input)
+        public async Task<ActionResult<UserDto>> Create([FromBody] UserDto input)
         {
             return await _userService.Create(input);
         }
 
         [HttpPost("Update")]
-        [Consumes("multipart/form-data")]
+     //   [Consumes("multipart/form-data")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [AppAuthorize(Permissions = "User.Update")]
-        public async Task<ActionResult<UserDto>> Update([FromForm] UserUpdateDto input)
+        public async Task<ActionResult<UserDto>> Update([FromBody] UserUpdateDto input)
         {
             return Ok(await _userService.Update(input));
         }

+ 4 - 4
MTWorkHR.API/Controllers/UserTaskController.cs

@@ -65,17 +65,17 @@ namespace MTWorkHR.API.Controllers
         #region attachments
         [HttpPost("CreateAttachment")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Consumes("multipart/form-data")]
+       // [Consumes("multipart/form-data")]
         [AppAuthorize(Permissions = "UserTask.Create")]
-        public async Task<ActionResult<AttachmentDto>> CreateAttachment([FromForm] AttachmentDto input)
+        public async Task<ActionResult<AttachmentDto>> CreateAttachment([FromBody] AttachmentDto input)
         {
             return await _attachmentService.Create(input);
         }
         [HttpPost("UpdateAttachment")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Consumes("multipart/form-data")]
+       // [Consumes("multipart/form-data")]
         [AppAuthorize(Permissions = "UserTask.Update")]
-        public async Task<ActionResult<AttachmentDto>> UpdateAttachment([FromForm] AttachmentDto input)
+        public async Task<ActionResult<AttachmentDto>> UpdateAttachment([FromBody] AttachmentDto input)
         {
             return await _attachmentService.Update(input);
         }

+ 5 - 4
MTWorkHR.API/appsettings.Development.json

@@ -32,10 +32,11 @@
   },
   "MailSettings": {
     "ApiKey": "SendGrid-Key",
-    "FromAddress": "noreply@mtwork.com",
-    "FromName": "Hr Management System",
-    "Password": "Noreply@1111",
-    "Host": "smtp.gmail.com",
+    "FromAddress": "DoNotReply@bc3ee9f1-57df-4a29-b566-a84d72074975.azurecomm.net",
+    "FromName": "MTWork Hr Management System",
+    "Password": "1qU8Q~gt4nex-gO3gWrc3FO~fpv8uGoTGqjyFbHx",
+    "Host": "smtp.azurecomm.net",
+    "SmtpUsername": "SMTP_username", // "MTCommunicationServiceResource.57fe2efd-9859-488f-8313-0acd27450cf0.2ff48a6f-9604-49d0-b338-28e96f91ec99", //"EmailSMTPApp",
     "Port": 587,
     "TemplatePath": "C:\\Attachment\\MailTemp\\EmailTemplate.html"
   },

+ 10 - 9
MTWorkHR.API/appsettings.Linux.json

@@ -25,15 +25,16 @@
         "TempAttachment": "/var/www/html/attachments/temp",
         "ActualAttachment": "/var/www/html/attachments/actual"
     },
-    "MailSettings": {
-        "ApiKey": "SendGrid-Key",
-        "FromAddress": "eng_z@live.com",
-        "FromName": "Hr Management System",
-        "Password": "111111111111",
-        "Host": "smtp-mail.outlook.com",
-        "Port": 587,
-        "TemplatePath": "/var/www/html/attachments/mailtemp"
-    },
+  "MailSettings": {
+    "ApiKey": "SendGrid-Key",
+    "FromAddress": "DoNotReply@bc3ee9f1-57df-4a29-b566-a84d72074975.azurecomm.net",
+    "FromName": "MTWork Hr Management System",
+    "Password": "1qU8Q~gt4nex-gO3gWrc3FO~fpv8uGoTGqjyFbHx",
+    "Host": "smtp.azurecomm.net",
+    "Port": 587,
+    "SmtpUsername": "SMTP_username", // "MTCommunicationServiceResource.57fe2efd-9859-488f-8313-0acd27450cf0.2ff48a6f-9604-49d0-b338-28e96f91ec99", //"EmailSMTPApp",
+    "TemplatePath": "C:\\Attachment\\MailTemp\\EmailTemplate.html"
+  },
     "OTPSettings": {
         "Length": 4,
         "ExpirePeriodInMinutes": 3000,

+ 5 - 4
MTWorkHR.API/appsettings.json

@@ -31,11 +31,12 @@
   },
   "MailSettings": {
     "ApiKey": "SendGrid-Key",
-    "FromAddress": "noreply@mtwork.com",
-    "FromName": "Hr Management System",
-    "Password": "Noreply@1111",
-    "Host": "smtp.gmail.com",
+    "FromAddress": "DoNotReply@bc3ee9f1-57df-4a29-b566-a84d72074975.azurecomm.net",
+    "FromName": "MTWork Hr Management System",
+    "Password": "1qU8Q~gt4nex-gO3gWrc3FO~fpv8uGoTGqjyFbHx",
+    "Host": "smtp.azurecomm.net",
     "Port": 587,
+    "SmtpUsername": "SMTP_username", // "MTCommunicationServiceResource.57fe2efd-9859-488f-8313-0acd27450cf0.2ff48a6f-9604-49d0-b338-28e96f91ec99", //"EmailSMTPApp",
     "TemplatePath": "C:\\Attachment\\MailTemp\\EmailTemplate.html"
   },
   "OTPSettings": {

+ 9 - 9
MTWorkHR.Application/Dtos/Identity/UserDto.cs

@@ -56,16 +56,16 @@ namespace MTWorkHR.Application.Models
         public bool IsCheckedIn { get; set; }
         public bool IsCheckedOut { get; set; }
         public string? ProfileImagePath { get; set; }
-        public IFormFile? ProfileImage { get; set; }
-        public IFormFile? CVAttach { get; set; }
-        public IFormFile? PassportAttach { get; set; }
-        public IFormFile? EduCertificateAttach { get; set; }
-        public IFormFile? ExperienceCertificateAttach { get; set; }
-        public IFormFile? ProfCertificateAttach { get; set; }
+        public AttachmentDto? ProfileImage { get; set; }
+        public AttachmentDto? CVAttach { get; set; }
+        public AttachmentDto? PassportAttach { get; set; }
+        public AttachmentDto? EduCertificateAttach { get; set; }
+        public AttachmentDto? ExperienceCertificateAttach { get; set; }
+        public AttachmentDto? ProfCertificateAttach { get; set; }
         //Company attach
-        public IFormFile? CommercialRegAttach { get; set; }
-        public IFormFile? TaxDeclarationAttach { get; set; }
-        public IFormFile? IdAttach { get; set; }
+        public AttachmentDto? CommercialRegAttach { get; set; }
+        public AttachmentDto? TaxDeclarationAttach { get; set; }
+        public AttachmentDto? IdAttach { get; set; }
 
         public IList<UserRoleDto>? UserRoles { get; set; }
         public IList<AttachmentDto>? UserAttachments{ get; set; }

+ 6 - 6
MTWorkHR.Application/Dtos/Identity/UserUpdateDto.cs

@@ -47,13 +47,13 @@ namespace MTWorkHR.Application.Models
         public decimal IncomeTaxValue { get; set; }
         public string? Position { get; set; }
         public long? CompanyId { get; set; }
-        public IFormFile? ProfileImage { get; set; }
+        public AttachmentDto? ProfileImage { get; set; }
 
-        public IFormFile? CVAttach { get; set; }
-        public IFormFile? PassportAttach { get; set; }
-        public IFormFile? EduCertificateAttach { get; set; }
-        public IFormFile? ExperienceCertificateAttach { get; set; }
-        public IFormFile? ProfCertificateAttach { get; set; }
+        public AttachmentDto? CVAttach { get; set; }
+        public AttachmentDto? PassportAttach { get; set; }
+        public AttachmentDto? EduCertificateAttach { get; set; }
+        public AttachmentDto? ExperienceCertificateAttach { get; set; }
+        public AttachmentDto? ProfCertificateAttach { get; set; }
 
         public IList<UserRoleDto>? UserRoles { get; set; }
         public IList<AttachmentDto>? UserAttachments { get; set; }

+ 6 - 6
MTWorkHR.Application/Dtos/User/CompanyDto.cs

@@ -25,12 +25,12 @@ namespace MTWorkHR.Application.Models
         public string? CountryName { get; set; }
         public UserTypeEnum? UserType { get; set; }
         public CompanyUserDto? CompanyUser { get; set; }
-        public IFormFile? ProfileImage { get; set; }
-        public IFormFile? CommercialRegAttach { get; set; }
-        public IFormFile? TaxDeclarationAttach { get; set; }
-        public IFormFile? PassportAttach { get; set; }
-        public IFormFile? ExperienceCertificateAttach { get; set; }
-        public IFormFile? IdAttach { get; set; }
+        public AttachmentDto? ProfileImage { get; set; }
+        public AttachmentDto? CommercialRegAttach { get; set; }
+        public AttachmentDto? TaxDeclarationAttach { get; set; }
+        public AttachmentDto? PassportAttach { get; set; }
+        public AttachmentDto? ExperienceCertificateAttach { get; set; }
+        public AttachmentDto? IdAttach { get; set; }
         public string? CreateUser { get; set; }
         public bool IsSuspended { get; set; }
 

+ 1 - 0
MTWorkHR.Application/Dtos/User/TeamUserDto.cs

@@ -13,6 +13,7 @@ namespace MTWorkHR.Application.Models
         [Required]
         public string AssignedUserId { get; set; }
         public string? AssignedUserName { get; set; }
+        public string? AssignedUserEmail { get; set; }
 
     }
 }

+ 1 - 1
MTWorkHR.Application/Services/Base/BlobFileService.cs

@@ -100,7 +100,7 @@ namespace MTWorkHR.Application.Services
             }
             catch (Exception ex)
             {
-                // Log the exception for debugging (e.g., using ILogger)
+                _logger.LogError(ex.Message);
                 return "";
             }
         }

+ 2 - 0
MTWorkHR.Application/Services/Interfaces/IUserService.cs

@@ -40,5 +40,7 @@ namespace MTWorkHR.Application.Identity
         Task<bool> Update(string userId, long companyId);
         Task Suspend(string id);
         Task<bool> UnAssignCompanyEmployees(long companyId);
+        Task<(string FullName, string Email)> GetUserNameEmail(string userId);
+
     }
 }

+ 18 - 31
MTWorkHR.Application/Services/Task/UserTaskAttachmentService.cs

@@ -38,15 +38,15 @@ namespace MTWorkHR.Application.Services
 
         public override async Task<AttachmentDto> Create(AttachmentDto input)
         {
-            if (input.FileData != null)
-            {
-               // input.FilePath = await _fileService.UploadFile(input.FileData);
-                input.OriginalName = input.FileData.FileName;
-                List<AttachmentDto> attachs = new List<AttachmentDto>();
-                attachs.Add(input);
-                _fileService.CopyFileToCloud(ref attachs);
+            //if (input.FileData != null)
+            //{
+            //   // input.FilePath = await _fileService.UploadFile(input.FileData);
+            //    input.OriginalName = input.FileData.FileName;
+            //    List<AttachmentDto> attachs = new List<AttachmentDto>();
+            //    attachs.Add(input);
+            //    _fileService.CopyFileToCloud(ref attachs);
 
-            }
+            //}
             
             var entity = MapperObject.Mapper.Map<UserTaskAttachment>(input);
             if (entity is null)
@@ -58,36 +58,23 @@ namespace MTWorkHR.Application.Services
             await _unitOfWork.CompleteAsync();
 
             var response = MapperObject.Mapper.Map<AttachmentDto>(task);
-            //using (var stream = new MemoryStream(attach.Content))
-            //{
-            //    var file = new FormFile(stream, 0, stream.Length, Path.GetFileNameWithoutExtension(attach.FileName), attach.FileName)
-            //    {
-            //        Headers = new HeaderDictionary(),
-            //        ContentType = attach.ContentType,
-            //    };
-
-            //    System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
-            //    {
-            //        FileName = file.FileName
-            //    };
-            //    file.ContentDisposition = cd.ToString();
-            //}
+           
             return response;
         }
 
 
-        //public override async Task<AttachmentDto> Update(AttachmentDto input)
-        //{
-        //    var entitiy = await _unitOfWork.UserTaskAttachment.GetByIdAsync(input.Id);
+        public override async Task<AttachmentDto> Update(AttachmentDto input)
+        {
+            var entitiy = await _unitOfWork.UserTaskAttachment.GetByIdAsync(input.Id);
 
-        //    if (entitiy == null)
-        //        throw new AppException(ExceptionEnum.RecordNotExist);
+            if (entitiy == null)
+                throw new AppException(ExceptionEnum.RecordNotExist);
 
-        //    MapperObject.Mapper.Map(input, entitiy, typeof(AttachmentDto), typeof(UserTaskAttachment));
+            MapperObject.Mapper.Map(input, entitiy, typeof(AttachmentDto), typeof(UserTaskAttachment));
 
-        //    await _unitOfWork.CompleteAsync();
+            await _unitOfWork.CompleteAsync();
 
-        //    return input;
-        //}
+            return input;
+        }
     }
 }

+ 52 - 67
MTWorkHR.Application/Services/User/CompanyService.cs

@@ -135,30 +135,14 @@ namespace MTWorkHR.Application.Services
             //    UserAddress = input.Address,
             //};
             var  UserAttachments = new List<AttachmentDto>();
-            if (input.ProfileImage != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.ProfileImage, OriginalName = input.ProfileImage?.Name, FileName = input.ProfileImage?.FileName, AttachmentTypeId = 9 });
-            }
-            if (input.CommercialRegAttach != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.CommercialRegAttach, OriginalName = input.CommercialRegAttach?.Name, FileName = input.CommercialRegAttach?.FileName, AttachmentTypeId = 6 });
-            }
-            if (input.PassportAttach != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 });
-            }
-            if (input.TaxDeclarationAttach != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.TaxDeclarationAttach, OriginalName = input.TaxDeclarationAttach?.Name, FileName = input.TaxDeclarationAttach?.FileName, AttachmentTypeId = 7 });
-            }
-            if (input.ExperienceCertificateAttach != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 });
-            }
-            if (input.IdAttach != null)
-            {
-                UserAttachments.Add(new AttachmentDto { FileData = input.IdAttach, OriginalName = input.IdAttach?.Name, FileName = input.IdAttach?.FileName, AttachmentTypeId = 8 });
-            }
+
+            AddAttachment(input.ProfileImage, 9, UserAttachments);
+            AddAttachment(input.CommercialRegAttach, 6, UserAttachments);
+            AddAttachment(input.PassportAttach, 2, UserAttachments);
+            AddAttachment(input.TaxDeclarationAttach, 7, UserAttachments);
+            AddAttachment(input.ExperienceCertificateAttach, 4, UserAttachments);
+            AddAttachment(input.IdAttach, 8, UserAttachments);
+          
             _fileService.CopyFileToCloud(ref UserAttachments);
             companyUser.UserAttachments = UserAttachments;
 
@@ -186,7 +170,19 @@ namespace MTWorkHR.Application.Services
             }
             return user;
         }
-
+        private void AddAttachment(AttachmentDto attachment, int attachmentTypeId, IList<AttachmentDto> attachList)
+        {
+            if (attachment != null)
+            {
+                attachList.Add(new AttachmentDto
+                {
+                    FilePath = attachment.FilePath,
+                    OriginalName = attachment.OriginalName,
+                    FileName = attachment.FileName,
+                    AttachmentTypeId = attachmentTypeId
+                });
+            }
+        }
 
         public override async Task<CompanyDto> Update(CompanyDto input)
         {
@@ -215,53 +211,24 @@ namespace MTWorkHR.Application.Services
 
                 if (entity == null)
                     throw new AppException(ExceptionEnum.RecordNotExist);
-                if (input.CompanyUser != null && input.CompanyUser.UserAttachments == null)
-                    input.CompanyUser.UserAttachments = new List<AttachmentDto>();
+              //  if (input.CompanyUser != null && input.CompanyUser.UserAttachments == null)
+                input.CompanyUser.UserAttachments = new List<AttachmentDto>();
+                
                 var oldAttachList = entity.UserAttachments;
-                if (input.ProfileImage != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 9 || x.OriginalName == input.ProfileImage?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.ProfileImage, OriginalName = input.ProfileImage?.Name, FileName = input.ProfileImage?.FileName, AttachmentTypeId = 9 });
-                }
-                if (input.CommercialRegAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 1 || x.OriginalName == input.CommercialRegAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.CommercialRegAttach, OriginalName = input.CommercialRegAttach?.Name, FileName = input.CommercialRegAttach?.FileName, AttachmentTypeId = 6 });
-                }
-                if (input.PassportAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 2 || x.OriginalName == input.PassportAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 });
-                }
-                if (input.TaxDeclarationAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 3 || x.OriginalName == input.TaxDeclarationAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.TaxDeclarationAttach, OriginalName = input.TaxDeclarationAttach?.Name, FileName = input.TaxDeclarationAttach?.FileName, AttachmentTypeId = 7});
-                }
-                if (input.ExperienceCertificateAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 4 || x.OriginalName == input.ExperienceCertificateAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 });
-                }
-                if (input.IdAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 5 || x.OriginalName == input.IdAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.CompanyUser?.UserAttachments.Add(new AttachmentDto { FileData = input.IdAttach, OriginalName = input.IdAttach?.Name, FileName = input.IdAttach?.FileName, AttachmentTypeId = 8 });
-                }
+
+
+                // Process each attachment type
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.ProfileImage, 9);
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.CommercialRegAttach, 6);
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.PassportAttach, 2);
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.TaxDeclarationAttach, 7);
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.ExperienceCertificateAttach, 4);
+                ProcessAttachment(oldAttachList, input.CompanyUser?.UserAttachments, input.IdAttach, 8);
+
                 List<AttachmentDto> attachs = input.CompanyUser?.UserAttachments.ToList();
                 _fileService.CopyFileToCloud(ref attachs);
                 input.CompanyUser.UserAttachments = attachs;
 
-                //if (!await _fileService.CopyFileToActualFolder(input.UserAttachments.ToList()))
-                //    throw new AppException(ExceptionEnum.CouldNotMoveFiles);
-
-
                 MapperObject.Mapper.Map(input.CompanyUser, entity);
 
                 
@@ -281,7 +248,25 @@ namespace MTWorkHR.Application.Services
             var user = MapperObject.Mapper.Map<UserUpdateDto>(userResponse);
             return user;
         }
+        private void ProcessAttachment(ICollection<UserAttachment> oldAttachments, IList<AttachmentDto> newAttachments, AttachmentDto attachment, int attachmentTypeId)
+        {
+            if (attachment == null)
+                return;
+
+            var oldAttach = oldAttachments
+                .FirstOrDefault(x => x.AttachmentTypeId == attachmentTypeId || x.FileName == attachment.FileName);
+
+            if (oldAttach != null)
+                oldAttachments.Remove(oldAttach);
 
+            newAttachments.Add(new AttachmentDto
+            {
+                FilePath = attachment.FilePath,
+                OriginalName = attachment.OriginalName,
+                FileName = attachment.FileName,
+                AttachmentTypeId = attachmentTypeId
+            });
+        }
         public override async  Task Delete(long id)
         {
             var entity = await _unitOfWork.Company.GetByIdAsync(id);

+ 30 - 3
MTWorkHR.Application/Services/User/TeamService.cs

@@ -80,8 +80,21 @@ namespace MTWorkHR.Application.Services
             {
                 throw new AppException(ExceptionEnum.MapperIssue);
             }
-            entity.TeamUsers = input.TeamUserIds?.Select(s => new TeamUser { AssignedUserId = s,AssignedUserName = _userService.GetUserFullName(s).Result, IsAdmin = false }).ToList();
-            
+            //entity.TeamUsers = input.TeamUserIds?.Select(s => new TeamUser { AssignedUserId = s,AssignedUserName = _userService.GetUserFullName(s).Result, IsAdmin = false }).ToList();
+
+
+            entity.TeamUsers = (await Task.WhenAll(input.TeamUserIds?.Select(async s =>
+            {
+                var userInfo = await _userService.GetUserNameEmail(s);
+                return new TeamUser
+                {
+                    AssignedUserId = s,
+                    AssignedUserName = userInfo.FullName,
+                    AssignedUserEmail = userInfo.Email,
+                    IsAdmin = false
+                };
+            }) ?? Enumerable.Empty<Task<TeamUser>>())).ToList();
+
             var team = await _unitOfWork.Team.AddAsync(entity);
             await _unitOfWork.CompleteAsync();
 
@@ -105,7 +118,21 @@ namespace MTWorkHR.Application.Services
             var oldUsers = entity.TeamUsers?.Select(s => s.AssignedUserId);
 
             var NewItems = input.TeamUserIds?.Where(u => !oldUsers.Contains(u));
-            var newTeamUsers = NewItems?.Select(s => new TeamUser {TeamId = input.Id, AssignedUserId = s, AssignedUserName = _userService.GetUserFullName(s).Result, IsAdmin = false }).ToList();
+          //  var newTeamUsers = NewItems?.Select(s => new TeamUser {TeamId = input.Id, AssignedUserId = s, AssignedUserName = _userService.GetUserFullName(s).Result, IsAdmin = false }).ToList();
+
+            var newTeamUsers = (await Task.WhenAll(NewItems?.Select(async s =>
+            {
+                var (fullName, email) = await _userService.GetUserNameEmail(s);
+                return new TeamUser
+                {
+                    TeamId = input.Id,
+                    AssignedUserId = s,
+                    AssignedUserName = fullName,
+                    AssignedUserEmail = email,
+                    IsAdmin = false
+                };
+            }) ?? Enumerable.Empty<Task<TeamUser>>())).ToList();
+
             var DeletedItems = oldUsers?.Where(u => !input.TeamUserIds.Contains(u));
             _unitOfWork.BeginTran();
             foreach (var delUser in DeletedItems)

+ 196 - 145
MTWorkHR.Application/Services/User/UserService.cs

@@ -27,6 +27,7 @@ using System.Linq;
 using System.ComponentModel.Design;
 using static iText.StyledXmlParser.Jsoup.Select.Evaluator;
 using static iText.IO.Util.IntHashtable;
+using Microsoft.Extensions.Logging;
 
 namespace MTWorkHR.Application.Services
 {
@@ -41,10 +42,11 @@ namespace MTWorkHR.Application.Services
         private readonly GlobalInfo _globalInfo;
         private readonly IFileService _fileService;
         private readonly IOTPService _oTPService;
+        private readonly ILogger<UserService> _logger;
 
         public UserService(ApplicationUserManager userManager, IUnitOfWork unitOfWork
              , RoleManager<ApplicationRole> roleManager, GlobalInfo globalInfo, AppSettingsConfiguration configuration, IMailSender emailSender
-            , IUserRoleRepository<IdentityUserRole<string>> userRole, IFileService fileService, IOTPService oTPService)
+            , IUserRoleRepository<IdentityUserRole<string>> userRole, IFileService fileService, IOTPService oTPService, ILogger<UserService> logger)
         {
             _userManager = userManager;
             _unitOfWork = unitOfWork;
@@ -55,6 +57,7 @@ namespace MTWorkHR.Application.Services
             _globalInfo = globalInfo;
             _fileService = fileService;
             _oTPService = oTPService;
+            _logger = logger;
         }
 
         public async Task<UserDto> GetById()
@@ -86,57 +89,38 @@ namespace MTWorkHR.Application.Services
             if (response.UserAttachments != null)
                 foreach (var attach in response.UserAttachments.Where(a => a.Content != null))
                 {
-                    //var stream = new MemoryStream(attach.Content);
-                    //IFormFile file = new FormFile(stream, 0, stream.Length, Path.GetFileNameWithoutExtension(attach.FileName), attach.FileName);
-
-                    using (var stream = new MemoryStream(attach.Content))
+                    switch (attach.AttachmentTypeId)
                     {
-                        var file = new FormFile(stream, 0, stream.Length, Path.GetFileNameWithoutExtension(attach.FileName), attach.FilePath)
-                        {
-                            Headers = new HeaderDictionary(),
-                            ContentType = attach.ContentType,
-                            
-                        };
-
-                        System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
-                        {
-                            FileName = file.FileName
-                        };
-                        file.ContentDisposition = cd.ToString();
-                        switch (attach.AttachmentTypeId)
-                        {
-                            case 1:
-                                response.CVAttach = file;
-                                break;
-                            case 2:
-                                response.PassportAttach = file;
-                                break;
-                            case 3:
-                                response.EduCertificateAttach = file;
-                                break;
-                            case 4:
-                                response.ExperienceCertificateAttach= file;
-                                break;
-                            case 5:
-                                response.ProfCertificateAttach = file;
-                                break;
-                            case 6:
-                                response.CommercialRegAttach = file;
-                                break;
-                            case 7:
-                                response.TaxDeclarationAttach = file;
-                                break;
-                            case 8:
-                                response.IdAttach = file;
-                                break;
-                            case 9:
-                                response.ProfileImage = file;
-                                response.ProfileImagePath = attach.FilePath;
-                                break;
-                        }
-                        attach.Content = new byte[0];
+                        case 1:
+                            response.CVAttach = attach;
+                            break;
+                        case 2:
+                            response.PassportAttach = attach;
+                            break;
+                        case 3:
+                            response.EduCertificateAttach = attach;
+                            break;
+                        case 4:
+                            response.ExperienceCertificateAttach= attach;
+                            break;
+                        case 5:
+                            response.ProfCertificateAttach = attach;
+                            break;
+                        case 6:
+                            response.CommercialRegAttach = attach;
+                            break;
+                        case 7:
+                            response.TaxDeclarationAttach = attach;
+                            break;
+                        case 8:
+                            response.IdAttach = attach;
+                            break;
+                        case 9:
+                            response.ProfileImage = attach;
+                            response.ProfileImagePath = attach.FilePath;
+                            break;
                     }
-                   
+                    attach.Content = new byte[0];
                 }
             
             var attendance = await _unitOfWork.Attendance.GetAttendanceByUserId(id, DateTime.UtcNow.Date);
@@ -215,9 +199,23 @@ namespace MTWorkHR.Application.Services
         public async Task<string> GetUserFullName(string userId)
         {
             var entity = await GetUserById(userId);
-            var name = entity == null ? "" : entity.FirstName + " " + entity.LastName;
+            var name = $"{entity.FirstName} {entity.LastName}".Trim();
             return name;
         }
+
+        public async Task<(string FullName, string Email)> GetUserNameEmail(string userId)
+        {
+            var entity = await GetUserById(userId);
+
+            if (entity == null)
+                return (string.Empty, string.Empty);
+
+            var name = $"{entity.FirstName} {entity.LastName}".Trim();
+            var email = entity.Email ?? string.Empty;
+
+            return (name, email);
+        }
+
         public async Task<UserDto> GetUserWithAttachmentById(string id)
         {
             var entity = await _userManager.Users.Include(u=> u.UserAttachments).Include(u=> u.JobTitle)
@@ -448,32 +446,16 @@ namespace MTWorkHR.Application.Services
             //loop for given list of attachment, and move each file from Temp path to Actual path
             //  _fileService.UploadFiles(files);
             input.CountryId = input.CountryId == null || input.CountryId == 0 ? input.UserAddress?.CountryId : input.CountryId;
-            if (input.UserAttachments == null )
-                input.UserAttachments = new List<AttachmentDto>();
-            if (input.ProfileImage != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfileImage, OriginalName = input.ProfileImage?.Name, FileName = input.ProfileImage?.FileName, AttachmentTypeId = 9 });
-            }
-            if (input.CVAttach != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.CVAttach, OriginalName = input.CVAttach?.Name,FileName = input.CVAttach?.FileName, AttachmentTypeId = 1 });
-            }
-            if (input.PassportAttach != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 });
-            }
-            if (input.EduCertificateAttach != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.EduCertificateAttach, OriginalName = input.EduCertificateAttach?.Name, FileName = input.EduCertificateAttach?.FileName, AttachmentTypeId = 3 });
-            }
-            if (input.ExperienceCertificateAttach != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 });
-            }
-            if (input.ProfCertificateAttach != null)
-            {
-                input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfCertificateAttach, OriginalName = input.ProfCertificateAttach?.Name, FileName = input.ProfCertificateAttach?.FileName, AttachmentTypeId = 5 });
-            }
+           // if (input.UserAttachments == null )
+            input.UserAttachments = new List<AttachmentDto>();
+            AddAttachment(input.ProfileImage, 9,  input.UserAttachments);
+            AddAttachment(input.CVAttach, 1,  input.UserAttachments);
+            AddAttachment(input.PassportAttach, 2,  input.UserAttachments);
+            AddAttachment(input.EduCertificateAttach, 3,  input.UserAttachments);
+            AddAttachment(input.ExperienceCertificateAttach, 4,  input.UserAttachments);
+            AddAttachment(input.ProfCertificateAttach, 5,  input.UserAttachments);
+
+
             var files = input.UserAttachments.Select(a=> a.FileData).ToList();
             List<AttachmentDto> attachs = input.UserAttachments.ToList();
              _fileService.CopyFileToCloud(ref attachs);
@@ -535,7 +517,6 @@ namespace MTWorkHR.Application.Services
                     await _userManager.AddToRoleAsync(user, roleName);
                 }
             }
-
             // await _userRole.AddRangeAsync(userRoles);
 
             await _unitOfWork.CompleteAsync();
@@ -555,17 +536,33 @@ namespace MTWorkHR.Application.Services
                 });
                 if (!sendMailResult)
                 {
+                    _logger.LogError("User created, but could not send the email!");
                     throw new AppException("User created, but could not send the email!");
                 }
             }
-            catch
+            catch(Exception ex)
             {
+                _logger.LogError(ex.Message);
                 throw new AppException("User created, but could not send the email!");
             }
-
             return input;
         }
 
+
+
+        private void AddAttachment(AttachmentDto attachment, int attachmentTypeId, IList<AttachmentDto> attachList)
+        {
+            if (attachment != null)
+            {
+                attachList.Add(new AttachmentDto
+                {
+                    FilePath = attachment.FilePath,
+                    OriginalName = attachment.OriginalName,
+                    FileName = attachment.FileName,
+                    AttachmentTypeId = attachmentTypeId
+                });
+            }
+        }
         public async Task<BlobObject> Download(string filePath)
         {
             var file = await _fileService.Download(filePath);
@@ -610,87 +607,43 @@ namespace MTWorkHR.Application.Services
             var confirmEmailUrl = QueryHelpers.AddQueryString(userURL.ToString(), "token", codeHtmlVersion);
             return new Tuple<string, string>(confirmEmailUrl, user.Email);
         }
-
         public async Task<UserUpdateDto> Update(UserUpdateDto input)
         {
             try
             {
-                var entity =  _userManager.Users.Include(x => x.UserAttachments).FirstOrDefault(x=> x.Id == input.Id);
+                var entity = await _userManager.Users
+                .Include(x => x.UserAttachments)
+                .FirstOrDefaultAsync(x => x.Id == input.Id);
 
                 if (entity == null)
                     throw new AppException(ExceptionEnum.UserNotExist);
-                if (input.UserAttachments == null)
-                    input.UserAttachments = new List<AttachmentDto>();
+
+                input.UserAttachments = new List<AttachmentDto>();
+
                 var oldAttachList = entity.UserAttachments;
-                if (input.ProfileImage != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 9 || x.OriginalName == input.ProfileImage?.Name).FirstOrDefault();
-                    if(oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfileImage, OriginalName = input.ProfileImage?.Name, FileName = input.ProfileImage?.FileName, AttachmentTypeId = 9 });
-                }
-                if (input.CVAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 1 || x.OriginalName == input.CVAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.CVAttach, OriginalName = input.CVAttach?.Name, FileName = input.CVAttach?.FileName, AttachmentTypeId = 1 });
-                }
-                if (input.PassportAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 2 || x.OriginalName == input.PassportAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 });
-                }
-                if (input.EduCertificateAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 3 || x.OriginalName == input.EduCertificateAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.EduCertificateAttach, OriginalName = input.EduCertificateAttach?.Name, FileName = input.EduCertificateAttach?.FileName, AttachmentTypeId = 3 });
-                }
-                if (input.ExperienceCertificateAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 4 || x.OriginalName == input.ExperienceCertificateAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 });
-                }
-                if (input.ProfCertificateAttach != null)
-                {
-                    var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 5 || x.OriginalName == input.ProfCertificateAttach?.Name).FirstOrDefault();
-                    if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
-                    input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfCertificateAttach, OriginalName = input.ProfCertificateAttach?.Name, FileName = input.ProfCertificateAttach?.FileName, AttachmentTypeId = 5 });
-                }
-                List<AttachmentDto> attachs = input.UserAttachments.ToList();
-                _fileService.CopyFileToCloud(ref attachs);
-                input.UserAttachments = attachs;
 
-                //if (!await _fileService.CopyFileToActualFolder(input.UserAttachments.ToList()))
-                //    throw new AppException(ExceptionEnum.CouldNotMoveFiles);
+                // Process each attachment type
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.ProfileImage, 9);
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.CVAttach, 1);
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.PassportAttach, 2);
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.EduCertificateAttach, 3);
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.ExperienceCertificateAttach, 4);
+                ProcessAttachment(oldAttachList, input.UserAttachments, input.ProfCertificateAttach, 5);
 
+                // Cloud copy
+                List<AttachmentDto> attachments = input.UserAttachments.ToList();
+                _fileService.CopyFileToCloud(ref attachments);
+                input.UserAttachments = attachments;
 
+                // Map updated input to entity
                 MapperObject.Mapper.Map(input, entity);
+                entity.UpdateDate = DateTime.UtcNow;
 
                 _unitOfWork.BeginTran();
-                entity.UpdateDate = DateTime.UtcNow;
-                //saving user
                 var result = await _userManager.UpdateAsync(entity);
                 if (!result.Succeeded)
                     throw new AppException(ExceptionEnum.RecordUpdateFailed);
 
-                //**saving userRoles
-
-                //add new user roles
-                //var exsitedRolesIds = await _userRole.GetUserRoleIdsByUserID(input.Id);
-                //if (input.UserRoles == null)
-                //    input.UserRoles = new List<UserRoleDto>();
-                //var newAddedRoles = MapperObject.Mapper.Map<List<IdentityUserRole<string>>>(input.UserRoles.Where(x => !exsitedRolesIds.Contains(x.RoleId)));
-                //newAddedRoles.ForEach(x => x.UserId = input.Id);
-                //await _userRole.AddRangeAsync(newAddedRoles);
-
-                ////delete removed roles
-                //var rolesIds = input.UserRoles.Select(x => x.RoleId).ToArray();
-                //var removedRoles = await _userRole.GetRemovedUserRoleIdsByUserID(input.Id, rolesIds);
-                //await _userRole.DeleteAsync(removedRoles.AsEnumerable());
-
-
                 await _unitOfWork.CompleteAsync();
                 _unitOfWork.CommitTran();
             }
@@ -698,11 +651,109 @@ namespace MTWorkHR.Application.Services
             {
                 throw e;
             }
+            // Return updated user
             var userResponse = await GetById(input.Id);
-            var user = MapperObject.Mapper.Map<UserUpdateDto>(userResponse);
-            return user;
+            return MapperObject.Mapper.Map<UserUpdateDto>(userResponse);
         }
 
+        private void ProcessAttachment(ICollection<UserAttachment> oldAttachments, IList<AttachmentDto> newAttachments, AttachmentDto attachment,int attachmentTypeId)
+        {
+            if (attachment == null)
+                return;
+
+            var oldAttach = oldAttachments
+                .FirstOrDefault(x => x.AttachmentTypeId == attachmentTypeId || x.FileName == attachment.FileName);
+
+            if (oldAttach != null)
+                oldAttachments.Remove(oldAttach);
+
+            newAttachments.Add(new AttachmentDto
+            {
+                FilePath = attachment.FilePath,
+                OriginalName = attachment.OriginalName,
+                FileName = attachment.FileName,
+                AttachmentTypeId = attachmentTypeId
+            });
+        }
+
+        //public async Task<UserUpdateDto> Update2(UserUpdateDto input)
+        //{
+        //    try
+        //    {
+        //        var entity =  _userManager.Users.Include(x => x.UserAttachments).FirstOrDefault(x=> x.Id == input.Id);
+
+        //        if (entity == null)
+        //            throw new AppException(ExceptionEnum.UserNotExist);
+        //        if (input.UserAttachments == null)
+        //            input.UserAttachments = new List<AttachmentDto>();
+        //        var oldAttachList = entity.UserAttachments;
+        //        if (input.ProfileImage != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 9 || x.OriginalName == input.ProfileImage?.Name).FirstOrDefault();
+        //            if(oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfileImage, OriginalName = input.ProfileImage?.Name, FileName = input.ProfileImage?.FileName, AttachmentTypeId = 9 });
+        //        }
+        //        if (input.CVAttach != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 1 || x.OriginalName == input.CVAttach?.Name).FirstOrDefault();
+        //            if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.CVAttach, OriginalName = input.CVAttach?.Name, FileName = input.CVAttach?.FileName, AttachmentTypeId = 1 });
+        //        }
+        //        if (input.PassportAttach != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 2 || x.OriginalName == input.PassportAttach?.Name).FirstOrDefault();
+        //            if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 });
+        //        }
+        //        if (input.EduCertificateAttach != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 3 || x.OriginalName == input.EduCertificateAttach?.Name).FirstOrDefault();
+        //            if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.EduCertificateAttach, OriginalName = input.EduCertificateAttach?.Name, FileName = input.EduCertificateAttach?.FileName, AttachmentTypeId = 3 });
+        //        }
+        //        if (input.ExperienceCertificateAttach != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 4 || x.OriginalName == input.ExperienceCertificateAttach?.Name).FirstOrDefault();
+        //            if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 });
+        //        }
+        //        if (input.ProfCertificateAttach != null)
+        //        {
+        //            var oldAttach = oldAttachList.Where(x => x.AttachmentTypeId == 5 || x.OriginalName == input.ProfCertificateAttach?.Name).FirstOrDefault();
+        //            if (oldAttach != null) entity.UserAttachments.Remove(oldAttach);
+        //            input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfCertificateAttach, OriginalName = input.ProfCertificateAttach?.Name, FileName = input.ProfCertificateAttach?.FileName, AttachmentTypeId = 5 });
+        //        }
+        //        List<AttachmentDto> attachs = input.UserAttachments.ToList();
+        //        _fileService.CopyFileToCloud(ref attachs);
+        //        input.UserAttachments = attachs;
+
+        //        //if (!await _fileService.CopyFileToActualFolder(input.UserAttachments.ToList()))
+        //        //    throw new AppException(ExceptionEnum.CouldNotMoveFiles);
+
+
+        //        MapperObject.Mapper.Map(input, entity);
+
+        //        _unitOfWork.BeginTran();
+        //        entity.UpdateDate = DateTime.UtcNow;
+        //        //saving user
+        //        var result = await _userManager.UpdateAsync(entity);
+        //        if (!result.Succeeded)
+        //            throw new AppException(ExceptionEnum.RecordUpdateFailed);
+
+             
+
+        //        await _unitOfWork.CompleteAsync();
+        //        _unitOfWork.CommitTran();
+        //    }
+        //    catch (Exception e)
+        //    {
+        //        throw e;
+        //    }
+        //    var userResponse = await GetById(input.Id);
+        //    var user = MapperObject.Mapper.Map<UserUpdateDto>(userResponse);
+        //    return user;
+        //}
+
         public async Task<bool> Update(string userId, long companyId)
         {
             try

+ 1 - 0
MTWorkHR.Core/Entities/User/TeamUser.cs

@@ -18,6 +18,7 @@ namespace MTWorkHR.Core.Entities
         [Required]
         public string AssignedUserId { get; set; }
         public string AssignedUserName { get; set; }
+        public string AssignedUserEmail { get; set; }
         public bool IsAdmin { get; set; }
 
     }

+ 1 - 1
MTWorkHR.Core/Global/AppSettingsConfiguration.cs

@@ -52,7 +52,7 @@ namespace MTWorkHR.Core.Global
         public string Host { get; set; }
         public string TemplatePath { get; set; }
         public int Port { get; set; }
-
+        public string SmtpUsername { get; set; }
     }
 
 

+ 93 - 3
MTWorkHR.Infrastructure/EmailService/MailSender.cs

@@ -1,5 +1,7 @@
 using MailKit;
 using MailKit.Net.Smtp;
+using MailKit.Security;
+using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Options;
 using MimeKit;
 using MTWorkHR.Core.Email;
@@ -10,6 +12,7 @@ using MTWorkHR.Core.Global;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -18,9 +21,11 @@ namespace MTWorkHR.Infrastructure.EmailService
     public class MailSender : IMailSender
     {
         public AppSettingsConfiguration _configuration { get; }
-        public MailSender(AppSettingsConfiguration configuration) 
+        private readonly ILogger<MailSender> _logger;
+        public MailSender(AppSettingsConfiguration configuration,ILogger<MailSender> logger) 
         {
             _configuration = configuration;
+            _logger = logger;
         }
         //public async Task<bool> SendEmailGrid(EmailMessage email)
         //{
@@ -37,11 +42,96 @@ namespace MTWorkHR.Infrastructure.EmailService
 
         //    return response.IsSuccessStatusCode;
         //}
-
         public async Task<bool> SendEmail(EmailMessage email)
         {
             var mailTo = email.To;
             var settings = _configuration.MailSettings;
+
+            // Validate configuration settings
+            if (string.IsNullOrEmpty(settings.SmtpUsername) ||
+                string.IsNullOrEmpty(settings.Password) ||
+                string.IsNullOrEmpty(settings.FromAddress) ||
+                string.IsNullOrEmpty(settings.Host) ||
+                settings.Port == 0 ||
+                string.IsNullOrEmpty(mailTo))
+            {
+                Console.WriteLine("Invalid mail settings or recipient address.");
+                return false;
+            }
+
+            // Create the email message
+            var emailObj = new MimeMessage();
+            emailObj.From.Add(new MailboxAddress("MTWork", settings.FromAddress)); // Display name + verified sender address
+            emailObj.Sender = MailboxAddress.Parse(settings.FromAddress);
+            emailObj.To.Add(MailboxAddress.Parse(mailTo));
+            emailObj.Subject = email.Subject;
+
+            // Build the email body with HTML content
+            var builder = new BodyBuilder();
+            var emailBody = email.Body;
+            if (!string.IsNullOrEmpty(email.url))
+            {
+                // Use string interpolation with proper HTML escaping
+                emailBody += $"Please click on <a href=\"{email.url}\">this link</a> or copy the following URL and open it: '{WebUtility.HtmlEncode(email.url)}'";
+            }
+            builder.HtmlBody = emailBody;
+            emailObj.Body = builder.ToMessageBody();
+
+            // Initialize SMTP client with logging
+            //using var logger = new ProtocolLogger("smtp.log", append: false);
+            using var smtp = new SmtpClient();
+            try
+            {
+                _logger.LogInformation("Connecting to SMTP server {Host}:{Port} with username :[{SmtpUsername}]",
+                settings.Host, settings.Port, settings.SmtpUsername);
+                // Connect to Azure Communication Services SMTP server
+                await smtp.ConnectAsync(settings.Host, settings.Port, SecureSocketOptions.StartTls);
+                _logger.LogInformation("Authenticating with username {SmtpUsername}:[{pass}]", settings.SmtpUsername, settings.Password);
+                // Authenticate using SMTP Username and Entra app client secret
+                await smtp.AuthenticateAsync(settings.SmtpUsername, settings.Password);
+                _logger.LogInformation("Sending email to {To} with subject {Subject}", mailTo, email.Subject);
+                // Send the email
+                await smtp.SendAsync(emailObj);
+                _logger.LogInformation("Email sent successfully to {To}", mailTo);
+            }
+            catch (AuthenticationException ex)
+            {
+                _logger.LogError(ex, "Authentication failed for username {SmtpUsername}: {Message}",
+                settings.SmtpUsername, ex.Message);
+                throw ex;
+                Console.WriteLine($"Authentication failed: {ex.Message}, Inner Exception: {ex.InnerException?.Message}");
+                return false;
+            }
+            catch (SmtpCommandException ex)
+            {
+                _logger.LogError(ex, "SMTP error: {Message}, Status: {StatusCode}", ex.Message, ex.StatusCode);
+                throw ex;
+                Console.WriteLine($"SMTP error: {ex.Message}, Status: {ex.StatusCode}, Inner Exception: {ex.InnerException?.Message}");
+                return false;
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error sending email to {To}: {Message}", mailTo, ex.Message);
+                throw ex;
+                Console.WriteLine($"Error sending email: {ex.Message}, Inner Exception: {ex.InnerException?.Message}");
+                return false;
+            }
+            finally
+            {
+                // Ensure disconnection
+                if (smtp.IsConnected)
+                {
+                    await smtp.DisconnectAsync(true);
+                    _logger.LogInformation("Disconnected from SMTP server");
+                }
+            }
+
+            return true;
+        }
+        public async Task<bool> SendEmailSMTP(EmailMessage email)
+        {
+            var mailTo = email.To;
+            var settings = _configuration.MailSettings;
             if (settings.FromAddress == null || settings.FromAddress== "" || settings.Password == null || settings.TemplatePath == null || settings.Host == null || settings.Port == 0 || mailTo == null)
                 return false;
 
@@ -53,7 +143,7 @@ namespace MTWorkHR.Infrastructure.EmailService
             //MailText = MailText.Replace("[NotificationType]", email.Subject).Replace("[Info]", email.Body).Replace("[Link]", email.url );
 
             var emailObj = new MimeMessage();
-            emailObj.From.Add(new MailboxAddress("Zinab Elgendy", _configuration.MailSettings.FromAddress)); // Ensure From matches authenticated email
+            emailObj.From.Add(new MailboxAddress("MTWork", _configuration.MailSettings.FromAddress)); // Ensure From matches authenticated email
             emailObj.Sender = MailboxAddress.Parse(_configuration.MailSettings.FromAddress);
             emailObj.To.Add(MailboxAddress.Parse(mailTo));
             emailObj.Subject = email.Subject;

Разница между файлами не показана из-за своего большого размера
+ 7355 - 0
MTWorkHR.Infrastructure/Migrations/20250519133714_altrTeamUsers.Designer.cs


+ 29 - 0
MTWorkHR.Infrastructure/Migrations/20250519133714_altrTeamUsers.cs

@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace MTWorkHR.Infrastructure.Migrations
+{
+    /// <inheritdoc />
+    public partial class altrTeamUsers : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<string>(
+                name: "AssignedUserEmail",
+                table: "TeamUser",
+                type: "nvarchar(max)",
+                nullable: false,
+                defaultValue: "");
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "AssignedUserEmail",
+                table: "TeamUser");
+        }
+    }
+}

+ 4 - 0
MTWorkHR.Infrastructure/Migrations/HRDataContextModelSnapshot.cs

@@ -4821,6 +4821,10 @@ namespace MTWorkHR.Infrastructure.Migrations
 
                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
 
+                    b.Property<string>("AssignedUserEmail")
+                        .IsRequired()
+                        .HasColumnType("nvarchar(max)");
+
                     b.Property<string>("AssignedUserId")
                         .IsRequired()
                         .HasColumnType("nvarchar(max)");