using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Directory; using Marco.Pms.Model.Dtos.Directory; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Mapper; using Marco.Pms.Model.Projects; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Directory; using Marco.Pms.Model.ViewModels.Master; using Marco.Pms.Model.ViewModels.Projects; using Marco.Pms.Services.Service; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.EntityFrameworkCore; namespace Marco.Pms.Services.Helpers { public class DirectoryHelper { private readonly ApplicationDbContext _context; private readonly ILoggingService _logger; private readonly UserHelper _userHelper; private readonly PermissionServices _permissionServices; public DirectoryHelper(ApplicationDbContext context, ILoggingService logger, UserHelper userHelper, PermissionServices permissionServices) { _context = context; _logger = logger; _userHelper = userHelper; _permissionServices = permissionServices; } public async Task> GetListOfContacts(string? search, bool active, ContactFilterDto? filterDto, Guid? projectId) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); List? employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).ToListAsync(); List bucketIds = employeeBuckets.Select(c => c.BucketId).ToList(); if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { var buckets = await _context.Buckets.Where(b => b.TenantId == tenantId).ToListAsync(); bucketIds = buckets.Select(b => b.Id).ToList(); } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) || permissionIds.Contains(PermissionsMaster.DirectoryUser)) { var buckets = await _context.Buckets.Where(b => b.CreatedByID == LoggedInEmployee.Id).ToListAsync(); var createdBucketIds = buckets.Select(b => b.Id).ToList(); bucketIds.AddRange(createdBucketIds); bucketIds = bucketIds.Distinct().ToList(); } else { _logger.LogWarning("Employee {EmployeeId} attemped to access a contacts, but do not have permission", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("You don't have permission", "You don't have permission", 401); } List filterbucketIds = bucketIds; if (filterDto != null && filterDto.BucketIds != null && filterDto.BucketIds.Count > 0) { filterbucketIds = filterDto.BucketIds; } List? contactBuckets = await _context.ContactBucketMappings.Where(cb => bucketIds.Contains(cb.BucketId)).ToListAsync(); List contactIds = contactBuckets.Where(b => filterbucketIds.Contains(b.BucketId)).Select(cb => cb.ContactId).ToList(); List contacts = new List(); var contactProjects = await _context.ContactProjectMappings.Where(p => contactIds.Contains(p.ContactId)).ToListAsync(); if (projectId != null && projectId != Guid.Empty) { contactProjects = contactProjects.Where(p => p.ProjectId == projectId).ToList(); contactIds = contactProjects.Select(p => p.ContactId).Distinct().ToList(); } if (filterDto != null && filterDto.CategoryIds != null && filterDto.CategoryIds.Count > 0) { var categoryIds = filterDto.CategoryIds; contacts = await _context.Contacts.Include(c => c.ContactCategory).Where(c => contactIds.Contains(c.Id) && categoryIds.Contains(c.ContactCategoryId ?? Guid.Empty) && c.TenantId == tenantId && c.IsActive == active).ToListAsync(); } else { contacts = await _context.Contacts.Include(c => c.ContactCategory).Where(c => contactIds.Contains(c.Id) && c.TenantId == tenantId && c.IsActive == active).ToListAsync(); } var phoneNo = await _context.ContactsPhones.Where(p => contactIds.Contains(p.ContactId)).ToListAsync(); var Emails = await _context.ContactsEmails.Where(E => contactIds.Contains(E.ContactId)).ToListAsync(); var Tags = await _context.ContactTagMappings.Where(t => contactIds.Contains(t.ContactId)).ToListAsync(); List TagIds = Tags.Select(t => t.ContactTagId).ToList(); var TagList = await _context.ContactTagMasters.Where(t => TagIds.Contains(t.Id)).ToListAsync(); if (search != null && search != string.Empty) { List filteredContactIds = new List(); phoneNo = phoneNo.Where(p => Compare(p.PhoneNumber, search)).ToList(); filteredContactIds = phoneNo.Select(p => p.ContactId).ToList(); Emails = Emails.Where(e => Compare(e.EmailAddress, search)).ToList(); filteredContactIds.AddRange(Emails.Select(e => e.ContactId).ToList()); filteredContactIds = filteredContactIds.Distinct().ToList(); contacts = contacts.Where(c => Compare(c.Name, search) || Compare(c.Organization, search) || filteredContactIds.Contains(c.Id)).ToList(); } List list = new List(); foreach (var contact in contacts) { ContactVM contactVM = new ContactVM(); List contactEmailVms = new List(); List contactPhoneVms = new List(); List conatctTagVms = new List(); var phones = phoneNo.Where(p => p.ContactId == contact.Id).ToList(); var emails = Emails.Where(e => e.ContactId == contact.Id).ToList(); var tagMappingss = Tags.Where(t => t.ContactId == contact.Id).ToList(); var projectMapping = contactProjects.Where(p => p.ContactId == contact.Id).ToList(); var bucketMapping = contactBuckets.Where(b => b.ContactId == contact.Id).ToList(); if (emails != null && emails.Count > 0) { foreach (var email in emails) { ContactEmailVM emailVM = new ContactEmailVM(); emailVM = email.ToContactEmailVMFromContactEmail(); contactEmailVms.Add(emailVM); } } if (phones != null && phones.Count > 0) { foreach (var phone in phones) { ContactPhoneVM phoneVM = new ContactPhoneVM(); phoneVM = phone.ToContactPhoneVMFromContactPhone(); contactPhoneVms.Add(phoneVM); } } if (tagMappingss != null && tagMappingss.Count > 0) { foreach (var tagMapping in tagMappingss) { ContactTagVM tagVM = new ContactTagVM(); ; var tag = TagList.Find(t => t.Id == tagMapping.ContactTagId); tagVM = tag != null ? tag.ToContactTagVMFromContactTagMaster() : new ContactTagVM(); conatctTagVms.Add(tagVM); } } contactVM = contact.ToContactVMFromContact(); if (projectMapping != null && projectMapping.Count > 0) { contactVM.ProjectIds = projectMapping.Select(p => p.ProjectId).ToList(); } if (bucketMapping != null && bucketMapping.Count > 0) { contactVM.BucketIds = bucketMapping.Select(p => p.BucketId).ToList(); } contactVM.ContactEmails = contactEmailVms; contactVM.ContactPhones = contactPhoneVms; contactVM.Tags = conatctTagVms; list.Add(contactVM); } _logger.LogInfo("{count} contacts are fetched by Employee with ID {LoggedInEmployeeId}", list.Count, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(list, System.String.Format("{0} contacts fetched successfully", list.Count), 200); } public async Task> GetContactsListByBucketId(Guid id) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (id != Guid.Empty) { Bucket? bucket = await _context.Buckets.FirstOrDefaultAsync(b => b.Id == id && b.TenantId == tenantId); if (bucket == null) { _logger.LogInfo("Employee ID {EmployeeId} attempted access to bucket ID {BucketId}, but not found in database", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Bucket not found", "Bucket not found", 404); } List? employeeBuckets = await _context.EmployeeBucketMappings.Where(em => em.BucketId == id).ToListAsync(); var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); EmployeeBucketMapping? employeeBucket = null; if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { employeeBucket = employeeBuckets.FirstOrDefault(); } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) || permissionIds.Contains(PermissionsMaster.DirectoryUser)) { employeeBucket = employeeBuckets.FirstOrDefault(eb => eb.EmployeeId == LoggedInEmployee.Id); } else { _logger.LogWarning("Employee {EmployeeId} attemped to access a contacts with in bucket {BucketId}, but do not have permission", LoggedInEmployee.Id, id); return ApiResponse.ErrorResponse("You don't have permission", "You don't have permission", 401); } if (employeeBucket == null) { _logger.LogInfo("Employee ID {EmployeeId} does not have access to bucket ID {BucketId}", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("You do not have access to this bucket.", "You do not have access to this bucket.", 401); } List contactBucket = await _context.ContactBucketMappings.Where(cb => cb.BucketId == id).ToListAsync() ?? new List(); List contactVMs = new List(); if (contactBucket.Count > 0) { var contactIds = contactBucket.Select(cb => cb.ContactId).ToList(); List contacts = await _context.Contacts.Include(c => c.ContactCategory).Where(c => contactIds.Contains(c.Id) && c.IsActive).ToListAsync(); List phones = await _context.ContactsPhones.Where(p => contactIds.Contains(p.ContactId)).ToListAsync(); List emails = await _context.ContactsEmails.Where(e => contactIds.Contains(e.ContactId)).ToListAsync(); List? tags = await _context.ContactTagMappings.Where(ct => contactIds.Contains(ct.ContactId)).ToListAsync(); List? contactProjects = await _context.ContactProjectMappings.Where(cp => contactIds.Contains(cp.ContactId)).ToListAsync(); List? contactBuckets = await _context.ContactBucketMappings.Where(cp => contactIds.Contains(cp.ContactId)).ToListAsync(); List tagIds = new List(); List tagMasters = new List(); if (tags.Count > 0) { tagIds = tags.Select(ct => ct.ContactTagId).ToList(); tagMasters = await _context.ContactTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync(); } if (contacts.Count > 0) { foreach (var contact in contacts) { List? emailVMs = new List(); List? phoneVMs = new List(); List? tagVMs = new List(); List contactPhones = phones.Where(p => p.ContactId == contact.Id).ToList(); List contactEmails = emails.Where(e => e.ContactId == contact.Id).ToList(); List? contactTags = tags.Where(t => t.ContactId == contact.Id).ToList(); List? projectMappings = contactProjects.Where(cp => cp.ContactId == contact.Id).ToList(); List? bucketMappings = contactBuckets.Where(cb => cb.ContactId == contact.Id).ToList(); if (contactPhones.Count > 0) { foreach (var phone in contactPhones) { ContactPhoneVM phoneVM = phone.ToContactPhoneVMFromContactPhone(); phoneVMs.Add(phoneVM); } } if (contactEmails.Count > 0) { foreach (var email in contactEmails) { ContactEmailVM emailVM = email.ToContactEmailVMFromContactEmail(); emailVMs.Add(emailVM); } } if (contactTags.Count > 0) { foreach (var contactTag in contactTags) { ContactTagMaster? tagMaster = tagMasters.Find(t => t.Id == contactTag.ContactTagId); if (tagMaster != null) { ContactTagVM tagVM = tagMaster.ToContactTagVMFromContactTagMaster(); tagVMs.Add(tagVM); } } } ContactVM contactVM = contact.ToContactVMFromContact(); contactVM.ContactEmails = emailVMs; contactVM.ContactPhones = phoneVMs; contactVM.Tags = tagVMs; contactVM.ProjectIds = projectMappings.Select(cp => cp.ProjectId).ToList(); contactVM.BucketIds = bucketMappings.Select(cb => cb.BucketId).ToList(); contactVMs.Add(contactVM); } } } _logger.LogInfo("{count} contact from Bucket {BucketId} fetched by Employee {EmployeeId}", contactVMs.Count, id, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(contactVMs, $"{contactVMs.Count} contacts fetched successfully", 200); } _logger.LogInfo("Employee ID {EmployeeId} sent an empty Bucket id", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Bucket ID is empty", "Bucket ID is empty", 400); } public async Task> CreateContact(CreateContactDto createContact) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (createContact != null) { List phones = new List(); List emails = new List(); List contactBucketMappings = new List(); List contactTagMappings = new List(); Contact? contact = createContact.ToContactFromCreateContactDto(tenantId, LoggedInEmployee.Id); _context.Contacts.Add(contact); await _context.SaveChangesAsync(); _logger.LogInfo("Contact with ID {ContactId} created by Employee with ID {LoggedInEmployeeId}", contact.Id, LoggedInEmployee.Id); var tags = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync(); var tagNames = tags.Select(t => t.Name.ToLower()).ToList(); var buckets = await _context.Buckets.Where(b => b.TenantId == tenantId).Select(b => b.Id).ToListAsync(); var projects = await _context.Projects.Where(p => p.TenantId == tenantId).Select(p => p.Id).ToListAsync(); if (createContact.ContactPhones != null) { foreach (var contactPhone in createContact.ContactPhones) { ContactPhone phone = contactPhone.ToContactPhoneFromCreateContactPhoneDto(tenantId, contact.Id); phones.Add(phone); } _context.ContactsPhones.AddRange(phones); _logger.LogInfo("{count} phone number are saved in contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", phones.Count, contact.Id, LoggedInEmployee.Id); } if (createContact.ContactEmails != null) { foreach (var contactEmail in createContact.ContactEmails) { ContactEmail email = contactEmail.ToContactEmailFromCreateContactEmailDto(tenantId, contact.Id); emails.Add(email); } _context.ContactsEmails.AddRange(emails); _logger.LogInfo("{count} email addresses are saved in contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", emails.Count, contact.Id, LoggedInEmployee.Id); } if (createContact.BucketIds != null) { foreach (var bucket in createContact.BucketIds) { if (buckets.Contains(bucket)) { ContactBucketMapping bucketMapping = new ContactBucketMapping { BucketId = bucket, ContactId = contact.Id }; contactBucketMappings.Add(bucketMapping); } } _context.ContactBucketMappings.AddRange(contactBucketMappings); _logger.LogInfo("Contact with ID {ContactId} added to {count} number of buckets by employee with ID {LoggedEmployeeId}", contact.Id, contactBucketMappings.Count, LoggedInEmployee.Id); } if (createContact.ProjectIds != null) { List projectMappings = new List(); foreach (var projectId in createContact.ProjectIds) { if (projects.Contains(projectId)) { ContactProjectMapping projectMapping = new ContactProjectMapping { ProjectId = projectId, ContactId = contact.Id, TenantId = tenantId }; projectMappings.Add(projectMapping); } } _context.ContactProjectMappings.AddRange(projectMappings); _logger.LogInfo("Contact with ID {ContactId} added to {count} number of project by employee with ID {LoggedEmployeeId}", contact.Id, projectMappings.Count, LoggedInEmployee.Id); } if (createContact.Tags != null) { foreach (var tag in createContact.Tags) { if (tagNames.Contains(tag.Name.ToLower())) { ContactTagMaster existingTag = tags.Find(t => t.Name == tag.Name) ?? new ContactTagMaster(); _context.ContactTagMappings.Add(new ContactTagMapping { ContactId = contact.Id, ContactTagId = tag.Id ?? existingTag.Id }); } else if (tag.Id == null || tags.Where(t => t.Name == tag.Name) == null) { var newtag = new ContactTagMaster { Name = tag.Name, TenantId = tenantId }; _context.ContactTagMasters.Add(newtag); ContactTagMapping tagMapping = new ContactTagMapping { ContactTagId = newtag.Id, ContactId = contact.Id }; contactTagMappings.Add(tagMapping); } } _context.ContactTagMappings.AddRange(contactTagMappings); _logger.LogInfo("{count} number of tags added to Contact with ID {ContactId} by employee with ID {LoggedEmployeeId}", contactTagMappings.Count, contact.Id, LoggedInEmployee.Id); } await _context.SaveChangesAsync(); ContactVM contactVM = new ContactVM(); List phoneVMs = new List(); contact = await _context.Contacts.Include(c => c.ContactCategory).FirstOrDefaultAsync(c => c.Id == contact.Id) ?? new Contact(); var tagIds = contactTagMappings.Select(t => t.ContactTagId).ToList(); tags = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId && tagIds.Contains(t.Id)).ToListAsync(); List contactProjects = await _context.ContactProjectMappings.Where(cp => cp.ContactId == contact.Id).ToListAsync(); List bucketMappings = await _context.ContactBucketMappings.Where(cb => cb.ContactId == contact.Id).ToListAsync(); foreach (var phone in phones) { ContactPhoneVM phoneVM = phone.ToContactPhoneVMFromContactPhone(); phoneVMs.Add(phoneVM); } List emailVMs = new List(); foreach (var email in emails) { ContactEmailVM emailVM = email.ToContactEmailVMFromContactEmail(); emailVMs.Add(emailVM); } List tagVMs = new List(); foreach (var contactTagMapping in contactTagMappings) { ContactTagVM tagVM = new ContactTagVM(); var tag = tags.Find(t => t.Id == contactTagMapping.ContactTagId); tagVM = tag != null ? tag.ToContactTagVMFromContactTagMaster() : new ContactTagVM(); tagVMs.Add(tagVM); } contactVM = contact.ToContactVMFromContact(); contactVM.ContactPhones = phoneVMs; contactVM.ContactEmails = emailVMs; contactVM.Tags = tagVMs; contactVM.ProjectIds = contactProjects.Select(cp => cp.ProjectId).ToList(); contactVM.BucketIds = bucketMappings.Select(cb => cb.BucketId).ToList(); return ApiResponse.SuccessResponse(contactVM, "Contact Created Successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> UpdateContact(Guid id, UpdateContactDto updateContact) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (updateContact != null) { if (updateContact.Id != id) { _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended different ID in payload and path parameter", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Invalid data", "Invalid data", 400); } Contact? contact = await _context.Contacts.AsNoTracking().FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId); if (contact == null) { _logger.LogWarning("Employee with ID {LoggedInEmployeeId} tries to update contact with ID {ContactId} is not found in database", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); List? employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).ToListAsync(); List bucketIds = employeeBuckets.Select(c => c.BucketId).ToList(); if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { var buckets = await _context.Buckets.Where(b => b.TenantId == tenantId).ToListAsync(); bucketIds = buckets.Select(b => b.Id).ToList(); } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) || permissionIds.Contains(PermissionsMaster.DirectoryUser)) { var buckets = await _context.Buckets.Where(b => b.CreatedByID == LoggedInEmployee.Id).ToListAsync(); var createdBucketIds = buckets.Select(b => b.Id).ToList(); bucketIds.AddRange(createdBucketIds); bucketIds = bucketIds.Distinct().ToList(); } else { _logger.LogWarning("Employee {EmployeeId} attemped to update a contact, but do not have permission", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("You don't have permission", "You don't have permission", 401); } List contactBuckets = await _context.ContactBucketMappings.AsNoTracking().Where(m => m.ContactId == contact.Id && bucketIds.Contains(m.BucketId)).ToListAsync(); bucketIds = contactBuckets.Select(b => b.BucketId).Distinct().ToList(); var newContact = updateContact.ToContactFromUpdateContactDto(tenantId, contact); newContact.UpdatedById = LoggedInEmployee.Id; newContact.UpdatedAt = DateTime.UtcNow; _context.Contacts.Update(newContact); await _context.SaveChangesAsync(); List phones = await _context.ContactsPhones.AsNoTracking().Where(p => p.ContactId == contact.Id).ToListAsync(); var phoneIds = phones.Select(p => p.Id).ToList(); List emails = await _context.ContactsEmails.AsNoTracking().Where(p => p.ContactId == contact.Id).ToListAsync(); var emailIds = emails.Select(p => p.Id).ToList(); List contactTags = await _context.ContactTagMappings.AsNoTracking().Where(m => m.ContactId == contact.Id).ToListAsync(); var tagIds = contactTags.Select(t => t.ContactTagId).Distinct().ToList(); List contactProjects = await _context.ContactProjectMappings.AsNoTracking().Where(m => m.ContactId == contact.Id).ToListAsync(); var projectIds = contactProjects.Select(t => t.ProjectId).Distinct().ToList(); List tags = await _context.ContactTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync(); List allTags = await _context.ContactTagMasters.Where(t => t.TenantId == tenantId).ToListAsync(); var tagNames = allTags.Select(t => t.Name.ToLower()).ToList(); if (updateContact.ContactPhones != null) { var updatedPhoneIds = updateContact.ContactPhones.Select(p => p.Id).Distinct().ToList(); foreach (var phoneDto in updateContact.ContactPhones) { var phone = phoneDto.ToContactPhoneFromUpdateContactPhoneDto(tenantId, contact.Id); if (phoneDto.Id != null && phoneDto.Id != Guid.Empty && phoneIds.Contains(phone.Id)) { _context.ContactsPhones.Update(phone); } else { _context.ContactsPhones.Add(phone); } } foreach (var phone in phones) { if (!updatedPhoneIds.Contains(phone.Id)) { _context.ContactsPhones.Remove(phone); } } } else if (phones != null) { _context.ContactsPhones.RemoveRange(phones); } if (updateContact.ContactEmails != null) { var updateEmailIds = updateContact.ContactEmails.Select(p => p.Id).Distinct().ToList(); foreach (var emailDto in updateContact.ContactEmails) { var email = emailDto.ToContactEmailFromUpdateContactEmailDto(tenantId, contact.Id); if (emailDto.Id != null && emailDto.Id != Guid.Empty && emailIds.Contains(email.Id)) { _context.ContactsEmails.Update(email); } else { _context.ContactsEmails.Add(email); } } foreach (var email in emails) { if (!updateEmailIds.Contains(email.Id)) { _context.ContactsEmails.Remove(email); } } } else if (emails != null) { _context.ContactsEmails.RemoveRange(emails); } if (updateContact.BucketIds != null) { foreach (var bucketId in updateContact.BucketIds) { if (!bucketIds.Contains(bucketId)) { _context.ContactBucketMappings.Add(new ContactBucketMapping { BucketId = bucketId, ContactId = contact.Id }); } } foreach (var bucketMapping in contactBuckets) { if (!updateContact.BucketIds.Contains(bucketMapping.BucketId)) { _context.ContactBucketMappings.Remove(bucketMapping); } } } else if (contactBuckets != null) { _context.ContactBucketMappings.RemoveRange(contactBuckets); } if (updateContact.ProjectIds != null) { foreach (var ProjectId in updateContact.ProjectIds) { if (!projectIds.Contains(ProjectId)) { _context.ContactProjectMappings.Add(new ContactProjectMapping { ProjectId = ProjectId, ContactId = contact.Id, TenantId = tenantId }); } } foreach (var projectMapping in contactProjects) { if (!updateContact.ProjectIds.Contains(projectMapping.ProjectId)) { _context.ContactProjectMappings.Remove(projectMapping); } } } else if (contactProjects != null) { _context.ContactProjectMappings.RemoveRange(contactProjects); } if (updateContact.Tags != null) { var updatedTagIds = updateContact.Tags.Select(t => t.Id).Distinct().ToList(); foreach (var tag in updateContact.Tags) { var namecheck = tagNames.Contains(tag.Name.ToLower()); var idCheck = (!tagIds.Contains(tag.Id ?? Guid.Empty)); var test = namecheck && idCheck; if (test) { ContactTagMaster existingTag = tags.Find(t => t.Name == tag.Name) ?? new ContactTagMaster(); _context.ContactTagMappings.Add(new ContactTagMapping { ContactId = contact.Id, ContactTagId = tag.Id ?? existingTag.Id }); } else if (tag.Id == null || tag.Id == Guid.Empty) { ContactTagMaster contactTag = new ContactTagMaster { Name = tag.Name, Description = "", TenantId = tenantId }; _context.ContactTagMasters.Add(contactTag); _context.ContactTagMappings.Add(new ContactTagMapping { ContactId = contact.Id, ContactTagId = contactTag.Id }); } } foreach (var contactTag in contactTags) { if (!updatedTagIds.Contains(contactTag.ContactTagId)) { _context.ContactTagMappings.Remove(contactTag); } } } else if (contactTags != null) { _context.ContactTagMappings.RemoveRange(contactTags); } _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = contact.Id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); contact = await _context.Contacts.Include(c => c.ContactCategory).FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId) ?? new Contact(); phones = await _context.ContactsPhones.AsNoTracking().Where(p => p.ContactId == contact.Id).ToListAsync(); emails = await _context.ContactsEmails.AsNoTracking().Where(p => p.ContactId == contact.Id).ToListAsync(); contactTags = await _context.ContactTagMappings.AsNoTracking().Where(m => m.ContactId == contact.Id).ToListAsync(); contactBuckets = await _context.ContactBucketMappings.AsNoTracking().Where(cb => cb.ContactId == contact.Id).ToListAsync(); contactProjects = await _context.ContactProjectMappings.AsNoTracking().Where(cp => cp.ContactId == contact.Id).ToListAsync(); tagIds = contactTags.Select(t => t.ContactTagId).Distinct().ToList(); tags = await _context.ContactTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync(); ContactVM contactVM = new ContactVM(); List phoneVMs = new List(); foreach (var phone in phones) { ContactPhoneVM phoneVM = phone.ToContactPhoneVMFromContactPhone(); phoneVMs.Add(phoneVM); } List emailVMs = new List(); foreach (var email in emails) { ContactEmailVM emailVM = email.ToContactEmailVMFromContactEmail(); emailVMs.Add(emailVM); } List tagVMs = new List(); foreach (var contactTagMapping in contactTags) { ContactTagVM tagVM = new ContactTagVM(); var tag = tags.Find(t => t.Id == contactTagMapping.ContactTagId); tagVM = tag != null ? tag.ToContactTagVMFromContactTagMaster() : new ContactTagVM(); tagVMs.Add(tagVM); } contactVM = contact.ToContactVMFromContact(); contactVM.ContactPhones = phoneVMs; contactVM.ContactEmails = emailVMs; contactVM.Tags = tagVMs; contactVM.BucketIds = contactBuckets.Select(cb => cb.BucketId).ToList(); contactVM.ProjectIds = contactProjects.Select(cp => cp.ProjectId).ToList(); _logger.LogInfo("Conatct {ContactId} has been updated by employee {EmployeeId}", contact.Id, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(contactVM, "Contact Updated Successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> GetContactProfile(Guid id) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (id != Guid.Empty) { Contact? contact = await _context.Contacts.Include(c => c.ContactCategory).Include(c => c.CreatedBy).FirstOrDefaultAsync(c => c.Id == id && c.IsActive); if (contact == null) { _logger.LogWarning("Employee with ID {LoggedInEmployeeId} tries to update contact with ID {ContactId} is not found in database", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } ContactProfileVM contactVM = contact.ToContactProfileVMFromContact(); DirectoryUpdateLog? updateLog = await _context.DirectoryUpdateLogs.Include(l => l.Employee).Where(l => l.RefereanceId == contact.Id).OrderByDescending(l => l.UpdateAt).FirstOrDefaultAsync(); if (updateLog != null) { contactVM.UpdatedAt = updateLog.UpdateAt; contactVM.UpdatedBy = updateLog.Employee != null ? updateLog.Employee.ToBasicEmployeeVMFromEmployee() : null; } List? phones = await _context.ContactsPhones.Where(p => p.ContactId == contact.Id).ToListAsync(); if (phones.Any()) { List? phoneVMs = new List(); foreach (var phone in phones) { ContactPhoneVM phoneVM = phone.ToContactPhoneVMFromContactPhone(); phoneVMs.Add(phoneVM); } contactVM.ContactPhones = phoneVMs; } List? emails = await _context.ContactsEmails.Where(e => e.ContactId == contact.Id).ToListAsync(); if (emails.Any()) { List? emailVMs = new List(); foreach (var email in emails) { ContactEmailVM emailVM = email.ToContactEmailVMFromContactEmail(); emailVMs.Add(emailVM); } contactVM.ContactEmails = emailVMs; } List? contactProjects = await _context.ContactProjectMappings.Where(cp => cp.ContactId == contact.Id).ToListAsync(); if (contactProjects.Any()) { List projectIds = contactProjects.Select(cp => cp.ProjectId).ToList(); List? projects = await _context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync(); List? projectVMs = new List(); foreach (var project in projects) { BasicProjectVM projectVM = new BasicProjectVM { Id = project.Id, Name = project.Name }; projectVMs.Add(projectVM); } contactVM.Projects = projectVMs; } List? contactBuckets = await _context.ContactBucketMappings.Where(cb => cb.ContactId == contact.Id).ToListAsync(); List? employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).ToListAsync(); if (contactBuckets.Any() && employeeBuckets.Any()) { List contactBucketIds = contactBuckets.Select(cb => cb.BucketId).ToList(); List employeeBucketIds = employeeBuckets.Select(eb => eb.BucketId).ToList(); List? buckets = await _context.Buckets.Where(b => contactBucketIds.Contains(b.Id) && employeeBucketIds.Contains(b.Id)).ToListAsync(); List? bucketVMs = new List(); foreach (var bucket in buckets) { BucketVM bucketVM = bucket.ToBucketVMFromBucket(); bucketVMs.Add(bucketVM); } contactVM.Buckets = bucketVMs; } List? contactTags = await _context.ContactTagMappings.Where(ct => ct.ContactId == contact.Id).ToListAsync(); if (contactTags.Any()) { List tagIds = contactTags.Select(ct => ct.ContactTagId).ToList(); List tagMasters = await _context.ContactTagMasters.Where(t => tagIds.Contains(t.Id)).ToListAsync(); List tagVMs = new List(); foreach (var tagMaster in tagMasters) { ContactTagVM tagVM = tagMaster.ToContactTagVMFromContactTagMaster(); tagVMs.Add(tagVM); } contactVM.Tags = tagVMs; } List? notes = await _context.ContactNotes.Where(n => n.ContactId == contact.Id && n.IsActive).ToListAsync(); if (notes.Any()) { List? noteIds = notes.Select(n => n.Id).ToList(); List? noteUpdateLogs = await _context.DirectoryUpdateLogs.Include(l => l.Employee).Where(l => noteIds.Contains(l.RefereanceId)).OrderByDescending(l => l.UpdateAt).ToListAsync(); List? noteVMs = new List(); foreach (var note in notes) { DirectoryUpdateLog? noteUpdateLog = noteUpdateLogs.Where(n => n.RefereanceId == note.Id).OrderByDescending(l => l.UpdateAt).FirstOrDefault(); ContactNoteVM noteVM = note.ToContactNoteVMFromContactNote(); if (noteUpdateLog != null) { noteVM.UpdatedAt = noteUpdateLog.UpdateAt; noteVM.UpdatedBy = noteUpdateLog.Employee != null ? noteUpdateLog.Employee.ToBasicEmployeeVMFromEmployee() : null; } noteVMs.Add(noteVM); } contactVM.Notes = noteVMs; } _logger.LogInfo("Employee ID {EmployeeId} fetched profile of contact {COntactId}", LoggedInEmployee.Id, contact.Id); return ApiResponse.SuccessResponse(contactVM, "Contact profile fetched successfully"); } _logger.LogInfo("Employee ID {EmployeeId} sent an empty contact id", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Contact ID is empty", "Contact ID is empty", 400); } public async Task> GetOrganizationList() { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var organizationList = await _context.Contacts.Where(c => c.TenantId == tenantId).Select(c => c.Organization).Distinct().ToListAsync(); _logger.LogInfo("Employee {EmployeeId} fetched list of organizations in a tenant {TenantId}", LoggedInEmployee.Id, tenantId); return ApiResponse.SuccessResponse(organizationList, $"{organizationList.Count} records of organization names fetched from contacts", 200); } public async Task> DeleteContact(Guid id, bool active) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (id != Guid.Empty) { Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == id && c.TenantId == tenantId); if (contact == null) { _logger.LogWarning("Employee with ID {LoggedInEmployeeId} tries to delete contact with ID {ContactId} is not found in database", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } contact.IsActive = active; _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = contact.Id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); _logger.LogInfo("Contact {ContactId} has been deleted by Employee {Employee}", id, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(new { }, "Contact is deleted Successfully", 200); } _logger.LogInfo("Employee ID {EmployeeId} sent an empty contact id", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Contact ID is empty", "Contact ID is empty", 400); } // -------------------------------- Contact Notes -------------------------------- /// /// Retrieves a paginated list of contact notes based on user permissions. /// /// The number of items per page. /// The current page number. /// An ApiResponse containing the paginated notes or an error message. public async Task> GetListOFAllNotes(Guid? projectId, int pageSize, int pageNumber) { _logger.LogInfo("Attempting to fetch list of all notes. PageSize: {PageSize}, PageNumber: {PageNumber}", pageSize, pageNumber); Guid tenantId = _userHelper.GetTenantId(); var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); List? projectContactIds = null; if (loggedInEmployee == null) { _logger.LogWarning("GetListOFAllNotes: LoggedInEmployee is null. Cannot proceed."); return ApiResponse.ErrorResponse("Unauthorized", "Employee not found.", 401); } // --- Permission Checks --- var hasAdminPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryAdmin, loggedInEmployee.Id); var hasManagerPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryAdmin, loggedInEmployee.Id); var hasUserPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryUser, loggedInEmployee.Id); IQueryable notesQuery = _context.ContactNotes .Include(cn => cn.UpdatedBy) .Include(cn => cn.Createdby) // Assuming 'CreatedBy' (PascalCase) .Include(cn => cn.Contact) .Where(cn => cn.TenantId == tenantId) .AsQueryable(); // Start building the query if (!hasAdminPermission && !(hasManagerPermission || hasUserPermission)) { _logger.LogWarning("GetListOFAllNotes: User {EmployeeId} does not have required permissions to access notes for TenantId: {TenantId}", loggedInEmployee.Id, tenantId); return ApiResponse.ErrorResponse("Access Denied", "You don't have access to view notes.", 403); } if (projectId != null) { projectContactIds = await _context.ContactProjectMappings .Where(pc => pc.ProjectId == projectId) .Select(pc => pc.ContactId) .ToListAsync(); } if (!hasAdminPermission) // If not an admin, apply additional filtering { _logger.LogInfo("GetListOFAllNotes: User {EmployeeId} is not an admin. Applying manager/user specific filters.", loggedInEmployee.Id); var assignedBucketIds = await _context.EmployeeBucketMappings .Where(eb => eb.EmployeeId == loggedInEmployee.Id) .Select(eb => eb.BucketId) .ToListAsync(); if (!assignedBucketIds.Any()) { _logger.LogInfo("GetListOFAllNotes: User {EmployeeId} has no assigned buckets. Returning empty list.", loggedInEmployee.Id); return ApiResponse.SuccessResponse(new { CurrentPage = pageNumber, TotalPages = 0, Data = new List() }, "No notes found based on assigned buckets.", 200); } List? contactIds = null; if (projectContactIds == null) { contactIds = await _context.ContactBucketMappings .Where(cb => assignedBucketIds.Contains(cb.BucketId)) .Select(cb => cb.ContactId) .ToListAsync(); } else { contactIds = await _context.ContactBucketMappings .Where(cb => assignedBucketIds.Contains(cb.BucketId) && projectContactIds.Contains(cb.ContactId)) .Select(cb => cb.ContactId) .ToListAsync(); } if (!contactIds.Any()) { _logger.LogInfo("GetListOFAllNotes: No contacts found for assigned buckets for user {EmployeeId}. Returning empty list.", loggedInEmployee.Id); return ApiResponse.SuccessResponse(new { CurrentPage = pageNumber, TotalPages = 0, Data = new List() }, "No notes found for associated contacts.", 200); } notesQuery = notesQuery.Where(cn => contactIds.Contains(cn.ContactId)); } else { if (projectContactIds != null) { notesQuery = notesQuery.Where(cn => projectContactIds.Contains(cn.ContactId)); } } // --- Pagination Logic --- // Ensure pageSize and pageNumber are valid pageSize = pageSize < 1 ? 25 : pageSize; // Default to 25 if less than 1 pageNumber = pageNumber < 1 ? 1 : pageNumber; // Default to 1 if less than 1 // Get total count BEFORE applying Skip/Take for accurate pagination metadata int totalRecords = await notesQuery.CountAsync(); int totalPages = (int)Math.Ceiling((double)totalRecords / pageSize); int skip = (pageNumber - 1) * pageSize; // --- Apply Ordering and Pagination in the database --- List notes = await notesQuery .OrderByDescending(cn => (cn.UpdatedAt != null ? cn.UpdatedAt : cn.CreatedAt)) // Order by updated date or created date .Skip(skip) .Take(pageSize) .ToListAsync(); _logger.LogInfo("GetListOFAllNotes: Fetched {Count} notes for page {PageNumber} of {TotalPages} total pages. Total records: {TotalRecords}.", notes.Count, pageNumber, totalPages, totalRecords); // --- Map to ViewModel (in-memory) --- // This mapping is done in memory because ToBasicEmployeeVMFromEmployee() is likely a C# method // that cannot be translated to SQL by Entity Framework. List noteVMS = notes .Select(cn => cn.ToContactNoteVMFromContactNote()) .ToList(); var response = new { CurrentPage = pageNumber, PageSize = pageSize, // Include pageSize in response for client clarity TotalPages = totalPages, TotalRecords = totalRecords, // Add total records for client Data = noteVMS }; _logger.LogInfo("GetListOFAllNotes: Successfully retrieved notes and mapped to ViewModel for TenantId: {TenantId}.", tenantId); return ApiResponse.SuccessResponse(response, $"{noteVMS.Count} notes fetched successfully.", 200); } public async Task> GetNoteListByContactId(Guid id, bool active) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId); if (contact != null) { List notes = new List(); if (active) { notes = await _context.ContactNotes .Include(n => n.Createdby) .Include(n => n.UpdatedBy) .Where(n => n.ContactId == contact.Id && n.IsActive && n.TenantId == tenantId) .ToListAsync(); } else { notes = await _context.ContactNotes .Include(n => n.Createdby) .Include(n => n.UpdatedBy) .Where(n => n.ContactId == contact.Id && n.TenantId == tenantId) .ToListAsync(); } var noteIds = notes.Select(n => n.Id).ToList(); List? updateLogs = await _context.DirectoryUpdateLogs.Include(l => l.Employee).Where(l => noteIds.Contains(l.RefereanceId)).ToListAsync(); //List? noteVMs = new List(); List? noteVMs = notes.Select(n => n.ToContactNoteVMFromContactNote()).ToList(); _logger.LogInfo("{count} contact-notes record from contact {ContactId} fetched by Employee {EmployeeId}", noteVMs.Count, id, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(noteVMs, $"{noteVMs.Count} contact-notes record fetched successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to fetch a list notes from contact with ID {ContactId}, but the contact was not found in the database.", LoggedInEmployee.Id, id); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } public async Task> CreateContactNote(CreateContactNoteDto noteDto) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (noteDto != null) { Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == noteDto.ContactId && c.IsActive && c.TenantId == tenantId); if (contact != null) { ContactNote note = noteDto.ToContactNoteFromCreateContactNoteDto(tenantId, LoggedInEmployee.Id); _context.ContactNotes.Add(note); await _context.SaveChangesAsync(); ContactNoteVM noteVM = note.ToContactNoteVMFromContactNote(); _logger.LogInfo("Employee {EmployeeId} Added note at contact {ContactId}", LoggedInEmployee.Id, contact.Id); return ApiResponse.SuccessResponse(noteVM, "Note added successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to add a note to contact with ID {ContactId}, but the contact was not found in the database.", LoggedInEmployee.Id, noteDto.ContactId); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> UpdateContactNote(Guid id, UpdateContactNoteDto noteDto) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (noteDto != null && id == noteDto.Id) { Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == noteDto.ContactId && c.TenantId == tenantId); if (contact != null) { ContactNote? contactNote = await _context.ContactNotes.Include(cn => cn.Createdby).Include(cn => cn.Contact).FirstOrDefaultAsync(n => n.Id == noteDto.Id && n.ContactId == contact.Id && n.IsActive); if (contactNote != null) { contactNote.Note = noteDto.Note; contactNote.UpdatedById = LoggedInEmployee.Id; contactNote.UpdatedAt = DateTime.UtcNow; _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); ContactNoteVM noteVM = contactNote.ToContactNoteVMFromContactNote(); noteVM.UpdatedAt = DateTime.UtcNow; noteVM.UpdatedBy = LoggedInEmployee.ToBasicEmployeeVMFromEmployee(); _logger.LogInfo("Employee {EmployeeId} updated note {NoteId} at contact {ContactId}", LoggedInEmployee.Id, noteVM.Id, contact.Id); return ApiResponse.SuccessResponse(noteVM, "Note updated successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to update a note {NoteId} to contact with ID {ContactId}, but the Note was not found in the database.", LoggedInEmployee.Id, noteDto.Id, noteDto.ContactId); return ApiResponse.ErrorResponse("Note not found", "Note not found", 404); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to update a note {NoteId} to contact with ID {ContactId}, but the contact was not found in the database.", LoggedInEmployee.Id, noteDto.Id, noteDto.ContactId); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> DeleteContactNote(Guid id, bool active) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); ContactNote? note = await _context.ContactNotes.FirstOrDefaultAsync(n => n.Id == id && n.TenantId == tenantId); if (note != null) { note.IsActive = active; note.UpdatedById = LoggedInEmployee.Id; note.UpdatedAt = DateTime.UtcNow; _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); _logger.LogInfo("Employee {EmployeeId} deleted note {NoteId}", LoggedInEmployee.Id, id); } _logger.LogWarning("Employee {EmployeeId} tries to delete contact note {NoteId} but not found in database", LoggedInEmployee.Id, id); return ApiResponse.SuccessResponse(new { }, "Note deleted successfully", 200); } // -------------------------------- Bucket -------------------------------- public async Task> GetBucketList() { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); List employeeBuckets = await _context.EmployeeBucketMappings.Where(b => b.EmployeeId == LoggedInEmployee.Id).ToListAsync(); var bucketIds = employeeBuckets.Select(b => b.BucketId).ToList(); List employeeBucketVM = await _context.EmployeeBucketMappings.Where(b => bucketIds.Contains(b.BucketId)).ToListAsync(); List bucketList = new List(); if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { bucketList = await _context.Buckets.Include(b => b.CreatedBy).Where(b => b.TenantId == tenantId).ToListAsync(); } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) || permissionIds.Contains(PermissionsMaster.DirectoryUser)) { bucketList = await _context.Buckets.Include(b => b.CreatedBy).Where(b => bucketIds.Contains(b.Id) || b.CreatedByID == LoggedInEmployee.Id).ToListAsync(); } else { _logger.LogWarning("Employee {EmployeeId} attemped to access a buckets list, but do not have permission", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("You don't have permission", "You don't have permission", 401); } List bucketVMs = new List(); if (bucketList.Any()) { bucketIds = bucketList.Select(b => b.Id).ToList(); List? contactBucketMappings = await _context.ContactBucketMappings.Where(cb => bucketIds.Contains(cb.BucketId)).ToListAsync(); foreach (var bucket in bucketList) { List employeeBucketMappings = employeeBucketVM.Where(eb => eb.BucketId == bucket.Id).ToList(); var emplyeeIds = employeeBucketMappings.Select(eb => eb.EmployeeId).ToList(); List? contactBuckets = contactBucketMappings.Where(cb => cb.BucketId == bucket.Id).ToList(); AssignBucketVM bucketVM = bucket.ToAssignBucketVMFromBucket(); bucketVM.EmployeeIds = emplyeeIds; bucketVM.NumberOfContacts = contactBuckets.Count; bucketVMs.Add(bucketVM); } } _logger.LogInfo("{count} Buckets are fetched by Employee with ID {LoggedInEmployeeId}", bucketVMs.Count, LoggedInEmployee.Id); return ApiResponse.SuccessResponse(bucketVMs, $"{bucketVMs.Count} buckets fetched successfully", 200); } public async Task> CreateBucket(CreateBucketDto bucketDto) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (bucketDto != null) { var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); var demo = !permissionIds.Contains(PermissionsMaster.DirectoryUser); if (!permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && !permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && !permissionIds.Contains(PermissionsMaster.DirectoryUser)) { _logger.LogWarning("Employee {EmployeeId} attemped to create a bucket, but do not have permission", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("You don't have permission", "You don't have permission", 401); } var existingBucket = await _context.Buckets.FirstOrDefaultAsync(b => b.Name == bucketDto.Name); if (existingBucket != null) { _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to create an existing bucket.", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Bucket already existed", "Bucket already existed", 409); } Bucket bucket = new Bucket { Name = bucketDto.Name, Description = bucketDto.Description, CreatedAt = DateTime.UtcNow, CreatedByID = LoggedInEmployee.Id, TenantId = tenantId }; _context.Buckets.Add(bucket); EmployeeBucketMapping employeeBucket = new EmployeeBucketMapping { EmployeeId = LoggedInEmployee.Id, BucketId = bucket.Id }; _context.EmployeeBucketMappings.Add(employeeBucket); await _context.SaveChangesAsync(); bucket = await _context.Buckets.Include(b => b.CreatedBy).FirstOrDefaultAsync(b => b.Id == bucket.Id) ?? new Bucket(); BucketVM bucketVM = bucket.ToBucketVMFromBucket(); _logger.LogInfo("Employee Id {LoggedInEmployeeId} creayted new bucket {BucketId}", LoggedInEmployee.Id, bucket.Id); return ApiResponse.SuccessResponse(bucketVM, "Bucket Created SuccessFully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> UpdateBucket(Guid id, UpdateBucketDto bucketDto) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (bucketDto != null && id == bucketDto.Id) { var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); var employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == id).ToListAsync(); var bucketIds = employeeBuckets.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).Select(eb => eb.BucketId).ToList(); Bucket? bucket = await _context.Buckets.Include(b => b.CreatedBy).FirstOrDefaultAsync(b => b.Id == bucketDto.Id && b.TenantId == tenantId); if (bucket == null) { _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to update a bucket but not found in database.", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Bucket not found", "Bucket not found", 404); } Bucket? accessableBucket = null; if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && bucketIds.Contains(id)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryUser)) { if (bucket.CreatedByID == LoggedInEmployee.Id) { accessableBucket = bucket; } } if (accessableBucket == null) { _logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without the necessary permissions.", LoggedInEmployee.Id, bucket.Id); return ApiResponse.ErrorResponse("You don't have permission to access this bucket", "You don't have permission to access this bucket", 401); } bucket.Name = bucketDto.Name ?? ""; bucket.Description = bucketDto.Description ?? ""; _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = bucketDto.Id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); AssignBucketVM bucketVM = bucket.ToAssignBucketVMFromBucket(); List employeeBucketMappings = employeeBuckets.Where(eb => eb.BucketId == bucket.Id).ToList(); List contactBuckets = await _context.ContactBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync(); var employeeIds = employeeBucketMappings.Select(eb => eb.EmployeeId).ToList(); bucketVM.EmployeeIds = employeeIds; bucketVM.NumberOfContacts = contactBuckets.Count; _logger.LogInfo("Employee Id {LoggedInEmployeeId} Updated new bucket {BucketId}", LoggedInEmployee.Id, bucket.Id); return ApiResponse.SuccessResponse(bucketVM, "Bucket update successFully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> AssignBucket(Guid bucketId, List assignBuckets) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (assignBuckets != null && bucketId != Guid.Empty) { var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); Bucket? bucket = await _context.Buckets.Include(b => b.CreatedBy).FirstOrDefaultAsync(b => b.Id == bucketId && b.TenantId == tenantId); if (bucket == null) { _logger.LogWarning("Employee ID {LoggedInEmployeeId} attempted to update a bucket but not found in database.", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("Bucket not found", "Bucket not found", 404); } var employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == bucketId).ToListAsync(); var bucketIds = employeeBuckets.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).Select(eb => eb.BucketId).ToList(); var employeeBucketIds = employeeBuckets.Select(eb => eb.EmployeeId).ToList(); Bucket? accessableBucket = null; if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && bucketIds.Contains(bucketId)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryUser)) { if (bucket.CreatedByID == LoggedInEmployee.Id) { accessableBucket = bucket; } } if (accessableBucket == null) { _logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without the necessary permissions.", LoggedInEmployee.Id, bucket.Id); return ApiResponse.ErrorResponse("You don't have permission to access this bucket", "You don't have permission to access this bucket", 401); } var employeeIds = await _context.Employees.Where(e => e.TenantId == tenantId && e.IsActive).Select(e => e.Id).ToListAsync(); int assignedEmployee = 0; int removededEmployee = 0; foreach (var assignBucket in assignBuckets) { if (employeeIds.Contains(assignBucket.EmployeeId)) { if (assignBucket.IsActive && !employeeBucketIds.Contains(assignBucket.EmployeeId)) { EmployeeBucketMapping employeeBucketMapping = new EmployeeBucketMapping { EmployeeId = assignBucket.EmployeeId, BucketId = bucketId }; _context.EmployeeBucketMappings.Add(employeeBucketMapping); assignedEmployee += 1; } else { EmployeeBucketMapping? employeeBucketMapping = employeeBuckets.FirstOrDefault(eb => eb.BucketId == bucketId && eb.EmployeeId == assignBucket.EmployeeId); if (employeeBucketMapping != null) { _context.EmployeeBucketMappings.Remove(employeeBucketMapping); removededEmployee += 1; } } } } _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = bucketId, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); AssignBucketVM bucketVM = bucket.ToAssignBucketVMFromBucket(); List employeeBucketMappings = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync(); List contactBuckets = await _context.ContactBucketMappings.Where(eb => eb.BucketId == bucket.Id).ToListAsync(); employeeIds = employeeBucketMappings.Select(eb => eb.EmployeeId).ToList(); bucketVM.EmployeeIds = employeeIds; bucketVM.NumberOfContacts = contactBuckets.Count; if (assignedEmployee > 0) { _logger.LogInfo("Employee {EmployeeId} assigned bucket {BucketId} to {conut} number of employees", LoggedInEmployee.Id, bucketId, assignedEmployee); } if (removededEmployee > 0) { _logger.LogWarning("Employee {EmployeeId} removed {conut} number of employees from bucket {BucketId}", LoggedInEmployee.Id, removededEmployee, bucketId); } return ApiResponse.SuccessResponse(bucketVM, "Details updated successfully", 200); } _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> DeleteBucket(Guid id) { Guid tenantId = _userHelper.GetTenantId(); var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); Bucket? bucket = await _context.Buckets.FirstOrDefaultAsync(n => n.Id == id && n.TenantId == tenantId); if (bucket != null) { List? employeeBuckets = await _context.EmployeeBucketMappings.Where(eb => eb.BucketId == id).ToListAsync(); List? contactBuckets = await _context.ContactBucketMappings.Where(eb => eb.BucketId == id).ToListAsync(); if (contactBuckets.Any()) { _logger.LogInfo("Employee {EmployeeId} attempted to deleted bucket {BucketId},but bucket have contacts in it.", LoggedInEmployee.Id, id); return ApiResponse.ErrorResponse("This bucket can not be deleted", "This bucket can not be deleted", 400); } var assignedRoleIds = await _context.EmployeeRoleMappings.Where(r => r.EmployeeId == LoggedInEmployee.Id).Select(r => r.RoleId).ToListAsync(); var permissionIds = await _context.RolePermissionMappings.Where(rp => assignedRoleIds.Contains(rp.ApplicationRoleId)).Select(rp => rp.FeaturePermissionId).Distinct().ToListAsync(); var bucketIds = employeeBuckets.Where(eb => eb.EmployeeId == LoggedInEmployee.Id).Select(eb => eb.BucketId).ToList(); Bucket? accessableBucket = null; if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryAdmin) && bucketIds.Contains(id)) { accessableBucket = bucket; } else if (permissionIds.Contains(PermissionsMaster.DirectoryUser)) { if (bucket.CreatedByID == LoggedInEmployee.Id) { accessableBucket = bucket; } } if (accessableBucket == null) { _logger.LogWarning("Employee {EmployeeId} attempted to access bucket {BucketId} without the necessary permissions.", LoggedInEmployee.Id, bucket.Id); return ApiResponse.ErrorResponse("You don't have permission to access this bucket", "You don't have permission to access this bucket", 401); } _context.EmployeeBucketMappings.RemoveRange(employeeBuckets); _context.Buckets.Remove(bucket); _context.DirectoryUpdateLogs.Add(new DirectoryUpdateLog { RefereanceId = id, UpdatedById = LoggedInEmployee.Id, UpdateAt = DateTime.UtcNow }); await _context.SaveChangesAsync(); _logger.LogInfo("Employee {EmployeeId} deleted bucket {BucketId} and related entries", LoggedInEmployee.Id, id); return ApiResponse.SuccessResponse(new { }, "Bucket deleted successfully", 200); } _logger.LogWarning("Employee {EmployeeId} tries to delete bucket {BucketId} but not found in database", LoggedInEmployee.Id, id); return ApiResponse.SuccessResponse(new { }, "Bucket deleted successfully", 200); } // -------------------------------- Helper -------------------------------- private bool Compare(string sentence, string search) { sentence = sentence.Trim().ToLower(); search = search.Trim().ToLower(); // Check for exact substring bool result = sentence.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; return result; } } }