using FirebaseAdmin.Messaging; using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.Attendance; using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.Expenses; using Marco.Pms.Model.Projects; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Service; using Microsoft.CodeAnalysis; using Microsoft.EntityFrameworkCore; using Project = Marco.Pms.Model.Projects.Project; namespace Marco.Pms.Services.Service { public class FirebaseService : IFirebaseService { private readonly IDbContextFactory _dbContextFactory; private readonly IServiceScopeFactory _serviceScopeFactory; private static readonly Guid Review = Guid.Parse("6537018f-f4e9-4cb3-a210-6c3b2da999d7"); private static readonly Guid RejectedByReviewer = Guid.Parse("965eda62-7907-4963-b4a1-657fb0b2724b"); private static readonly Guid Approve = Guid.Parse("4068007f-c92f-4f37-a907-bc15fe57d4d8"); private static readonly Guid RejectedByApprover = Guid.Parse("d1ee5eec-24b6-4364-8673-a8f859c60729"); private static readonly Guid ProcessPending = Guid.Parse("f18c5cfd-7815-4341-8da2-2c2d65778e27"); private static readonly Guid Processed = Guid.Parse("61578360-3a49-4c34-8604-7b35a3787b95"); public FirebaseService(IDbContextFactory dbContextFactory, IServiceScopeFactory serviceScopeFactory) { _dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory)); _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory)); } // Auth Controller public async Task SendLoginOnAnotherDeviceMessageAsync(Guid employeeId, string fcmToken, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); // List of device registration tokens to send the message to var registrationTokens = await _context.FCMTokenMappings .Where(ft => ft.EmployeeId == employeeId && ft.ExpiredAt >= DateTime.UtcNow && ft.FcmToken != fcmToken && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = "Login Alert", Body = $"You has successfully logged in to the application from another device" }; await SendMessageToMultipleDevicesAsync(registrationTokens, notificationFirebase); } public async Task SendLoginMessageAsync(string name, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); // List of device registration tokens to send the message to var registrationTokens = await _context.FCMTokenMappings .Where(ft => ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = "Login Alert", Body = $"{name} has successfully logged in to the application" }; await SendMessageToMultipleDevicesAsync(registrationTokens, notificationFirebase); } // Employee Controller public async Task SendEmployeeSuspendMessageAsync(Guid employeeId, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var projectIds = await _context.ProjectAllocations .Where(pa => pa.EmployeeId == employeeId && pa.TenantId == tenantId) .Select(pa => pa.ProjectId).ToListAsync(); var employeeIds = await _context.ProjectAllocations .Where(pa => projectIds.Contains(pa.ProjectId) && pa.TenantId == tenantId) .Select(pa => pa.EmployeeId).ToListAsync(); var registrationTokensForData = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var data = new Dictionary() { { "Keyword", "Employee_Suspend" }, { "EmployeeId", employeeId.ToString() } }; await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); } // Attendance Controller public async Task SendAttendanceMessageAsync(Guid projectId, string name, ATTENDANCE_MARK_TYPE markType, Guid employeeId, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var teamAttendanceRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.TeamAttendance) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var regularizeAttendanceRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.RegularizeAttendance) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, teamAttendanceRoleTask, manageProjectsRoleTask, regularizeAttendanceRoleTask); var teamAttendanceRoleIds = teamAttendanceRoleTask.Result; var regularizeAttendanceRoleIds = regularizeAttendanceRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var project = projectTask.Result; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && teamAttendanceRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); }); var teamEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.EmployeeRoleMappings .Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); }); await Task.WhenAll(employeeIdsTask, teamEmployeeIdsTask); var employeeIds = employeeIdsTask.Result; var teamEmployeeIds = teamEmployeeIdsTask.Result; var mesaageNotificationIds = new List(); Notification notificationFirebase; switch (markType) { case ATTENDANCE_MARK_TYPE.CHECK_IN: notificationFirebase = new Notification { Title = "Attendance Update", Body = $" {name} has checked in for project {project?.ProjectName ?? ""}." }; mesaageNotificationIds.AddRange(employeeIds); break; case ATTENDANCE_MARK_TYPE.CHECK_OUT: notificationFirebase = new Notification { Title = "Attendance Update", Body = $" {name} has checked out for project {project?.ProjectName ?? ""}." }; mesaageNotificationIds.AddRange(employeeIds); break; case ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE: notificationFirebase = new Notification { Title = "Regularization Request", Body = $" {name} has submitted a regularization request for project {project?.ProjectName ?? ""}." }; mesaageNotificationIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && regularizeAttendanceRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); break; case ATTENDANCE_MARK_TYPE.REGULARIZE: notificationFirebase = new Notification { Title = " Regularization Approved", Body = $" {name}'s regularization request for project {project?.ProjectName ?? ""} has been accepted." }; mesaageNotificationIds.Add(employeeId); break; case ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT: notificationFirebase = new Notification { Title = "Regularization Denied", Body = $" {name}'s regularization request for project {project?.ProjectName ?? ""} has been rejected." }; mesaageNotificationIds.Add(employeeId); break; default: notificationFirebase = new Notification { Title = "Attendance Update", Body = $" {name} has update his/her attendance for project {project?.ProjectName ?? ""}." }; break; } // List of device registration tokens to send the message to var data = new Dictionary() { { "Keyword", "Attendance" }, { "ProjectId", projectId.ToString() }, { "Action", markType.ToString() } }; var registrationTokensForNotificationTask = Task.Run(async () => { if (mesaageNotificationIds.Any()) { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => mesaageNotificationIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } }); var registrationTokensForDataTask = Task.Run(async () => { if (teamEmployeeIds.Any()) { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForData = await dbContext.FCMTokenMappings .Where(ft => teamEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); } }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask); } // Task Controller public async Task SendAssignTaskMessageAsync(Guid workItemId, string name, List teamMembers, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var workItem = await _context.WorkItems .Include(wi => wi.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(wi => wi.Id == workItemId && wi.WorkArea != null && wi.WorkArea.Floor != null && wi.WorkArea.Floor.Building != null); if (workItem == null) { return; } var projectId = workItem.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, viewTaskRoleTask, manageProjectsRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var project = projectTask.Result; var buildingName = workItem.WorkArea.Floor.Building.Name; var FloorName = workItem.WorkArea.Floor.FloorName; var AreaName = workItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); var data = new Dictionary() { { "Keyword", "Assign_Task" }, { "ProjectId", projectId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => teamMembers.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = $"Task Assigned for {project?.ProjectName}", Body = $"A task has been assigned to you by {name} at {location}" }; await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); }); var registrationTokensForDataTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForData = await dbContext.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendReportTaskMessageAsync(Guid taskAllocationId, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var taskAllocation = await _context.TaskAllocations .Include(t => t.WorkItem) .ThenInclude(wi => wi!.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(t => t.Id == taskAllocationId && t.TenantId == tenantId && t.WorkItem != null && t.WorkItem.WorkArea != null && t.WorkItem.WorkArea.Floor != null && t.WorkItem.WorkArea.Floor.Building != null); if (taskAllocation == null) { return; } var projectId = taskAllocation.WorkItem!.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var teamMemberTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.TaskMembers .Where(tm => tm.TaskAllocationId == taskAllocationId && tm.TenantId == tenantId) .Select(tm => tm.EmployeeId).ToListAsync(); }); var approveTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ApproveTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, teamMemberTask, viewTaskRoleTask, manageProjectsRoleTask, approveTaskRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var teamMembers = teamMemberTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var approveTaskRoleIds = approveTaskRoleTask.Result; var project = projectTask.Result; var buildingName = taskAllocation.WorkItem.WorkArea.Floor.Building.Name; var FloorName = taskAllocation.WorkItem.WorkArea.Floor.FloorName; var AreaName = taskAllocation.WorkItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var dataNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); employeeIds.AddRange(teamMembers); return employeeIds; }); var mesaageNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && approveTaskRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); }); await Task.WhenAll(dataNotificationTask, mesaageNotificationTask); var dataNotificationIds = dataNotificationTask.Result; var mesaageNotificationIds = mesaageNotificationTask.Result; var data = new Dictionary() { { "Keyword", "Report_Task" }, { "ProjectId", projectId.ToString() }, { "TaskAllocationId", taskAllocationId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => mesaageNotificationIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = $"New Task Reported - {project?.ProjectName}", Body = $"{name} reported a task at {location}." }; await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); }); var registrationTokensForDataTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForData = await dbContext.FCMTokenMappings .Where(ft => dataNotificationIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendTaskCommentMessageAsync(Guid taskAllocationId, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var taskAllocation = await _context.TaskAllocations .Include(t => t.WorkItem) .ThenInclude(wi => wi!.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(t => t.Id == taskAllocationId && t.TenantId == tenantId && t.WorkItem != null && t.WorkItem.WorkArea != null && t.WorkItem.WorkArea.Floor != null && t.WorkItem.WorkArea.Floor.Building != null); if (taskAllocation == null) { return; } var projectId = taskAllocation.WorkItem!.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, viewTaskRoleTask, manageProjectsRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var project = projectTask.Result; var buildingName = taskAllocation.WorkItem.WorkArea.Floor.Building.Name; var FloorName = taskAllocation.WorkItem.WorkArea.Floor.FloorName; var AreaName = taskAllocation.WorkItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewTaskRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); employeeIds.Add(taskAllocation.AssignedBy); var data = new Dictionary() { { "Keyword", "Task_Comment" }, { "ProjectId", projectId.ToString() }, { "TaskAllocationId", taskAllocationId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = $"New Comment on Task - {project?.ProjectName}", Body = $"{name} added a comment on Task at {location}." }; await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendApproveTaskMessageAsync(Guid taskAllocationId, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var taskAllocation = await _context.TaskAllocations .Include(t => t.WorkItem) .ThenInclude(wi => wi!.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(t => t.Id == taskAllocationId && t.TenantId == tenantId && t.WorkItem != null && t.WorkItem.WorkArea != null && t.WorkItem.WorkArea.Floor != null && t.WorkItem.WorkArea.Floor.Building != null); if (taskAllocation == null) { return; } var projectId = taskAllocation.WorkItem!.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var teamMemberTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.TaskMembers .Where(tm => tm.TaskAllocationId == taskAllocationId && tm.TenantId == tenantId) .Select(tm => tm.EmployeeId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, teamMemberTask, viewTaskRoleTask, manageProjectsRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var teamMembers = teamMemberTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var project = projectTask.Result; var buildingName = taskAllocation.WorkItem.WorkArea.Floor.Building.Name; var FloorName = taskAllocation.WorkItem.WorkArea.Floor.FloorName; var AreaName = taskAllocation.WorkItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); teamMembers.Add(taskAllocation.AssignedBy); var data = new Dictionary() { { "Keyword", "Report_Task" }, { "ProjectId", projectId.ToString() }, { "TaskAllocationId", taskAllocationId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => teamMembers.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); var notificationFirebase = new Notification { Title = $"Task Approved - {project?.ProjectName}", Body = $"{name} approved your {taskAllocation.ReportedTask} of {taskAllocation.CompletedTask} tasks at {location}." }; await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); }); var registrationTokensForDataTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForData = await dbContext.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } // Project Controller //Project Infra public async Task SendModifyTaskMeaasgeAsync(List workItemIds, string name, bool IsExist, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var workItems = await _context.WorkItems .Include(wi => wi.ActivityMaster) .Include(wi => wi.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .Where(wi => workItemIds.Contains(wi.Id) && wi.TenantId == tenantId && wi.ActivityMaster != null && wi.WorkArea != null && wi.WorkArea.Floor != null && wi.WorkArea.Floor.Building != null) .ToListAsync(); if (!workItems.Any()) { return; } var workItem = workItems.FirstOrDefault(); var projectId = workItem!.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var viewProjectInfraRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewProjectInfra) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, viewTaskRoleTask, manageProjectsRoleTask, viewProjectInfraRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var viewProjectInfraRoleIds = viewProjectInfraRoleTask.Result; var project = projectTask.Result; var activityName = workItem.ActivityMaster!.ActivityName; var buildingName = workItem.WorkArea.Floor.Building.Name; var FloorName = workItem.WorkArea.Floor.FloorName; var AreaName = workItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; var buildingId = workItem.WorkArea.Floor.Building.Id; var floorId = workItem.WorkArea.Floor.Id; var areaId = workItem.WorkArea.Id; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && (viewTaskRoleIds.Contains(er.RoleId) || viewProjectInfraRoleIds.Contains(er.RoleId))) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase; if (IsExist) { notificationFirebase = new Notification { Title = $"Task Updated - {project?.ProjectName}", Body = $"{name} updated tasks {activityName} at {location}." }; } else { notificationFirebase = new Notification { Title = $"New Task Created - {project?.ProjectName}", Body = $"{name} created tasks {activityName} at {location}." }; } var data = new Dictionary() { { "Keyword", "Task_Modified" }, { "ProjectId", projectId.ToString() }, { "BuildingId", buildingId.ToString() }, { "FloorId", floorId.ToString() }, { "AreaId", areaId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendModifyWorkAreaMeaasgeAsync(Guid workAreaId, string name, bool IsExist, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var workArea = await _context.WorkAreas .Include(wa => wa.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(wa => wa.Id == workAreaId && wa.TenantId == tenantId && wa.Floor != null && wa.Floor.Building != null); if (workArea == null) { return; } var projectId = workArea.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewProjectInfraRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewProjectInfra) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, manageProjectsRoleTask, viewProjectInfraRoleTask); var manageProjectsRoleIds = manageProjectsRoleTask.Result; var viewProjectInfraRoleIds = viewProjectInfraRoleTask.Result; var project = projectTask.Result; var buildingName = workArea.Floor.Building.Name; var FloorName = workArea.Floor.FloorName; var location = $"{buildingName} > {FloorName}"; var buildingId = workArea.Floor.Building.Id; var floorId = workArea.Floor.Id; var areaName = workArea.AreaName; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewProjectInfraRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase; if (IsExist) { notificationFirebase = new Notification { Title = $"WorkArea Updated - {project?.ProjectName}", Body = $"{name} updated WorkArea \"{areaName}\" at {location}." }; } else { notificationFirebase = new Notification { Title = $"New WorkArea Created - {project?.ProjectName}", Body = $"{name} created WorkArea \"{areaName}\" at {location}." }; } var data = new Dictionary() { { "Keyword", "WorkArea_Modified" }, { "ProjectId", projectId.ToString() }, { "BuildingId", buildingId.ToString() }, { "FloorId", floorId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendModifyFloorMeaasgeAsync(Guid floorId, string name, bool IsExist, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var floor = await _context.Floor .Include(f => f.Building) .FirstOrDefaultAsync(f => f.Id == floorId && f.TenantId == tenantId && f.Building != null); if (floor == null) { return; } var projectId = floor.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewProjectInfraRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewProjectInfra) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, manageProjectsRoleTask, viewProjectInfraRoleTask); var manageProjectsRoleIds = manageProjectsRoleTask.Result; var viewProjectInfraRoleIds = viewProjectInfraRoleTask.Result; var project = projectTask.Result; var buildingName = floor.Building.Name; var floorName = floor.FloorName; var buildingId = floor.Building.Id; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewProjectInfraRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase; if (IsExist) { notificationFirebase = new Notification { Title = $"Floor Updated - {project?.ProjectName}", Body = $"{name} updated Floor \"{floorName}\" at {buildingName}." }; } else { notificationFirebase = new Notification { Title = $"New Floor Created - {project?.ProjectName}", Body = $"{name} created Floor \"{floorName}\" at {buildingName}." }; } var data = new Dictionary() { { "Keyword", "Floor_Modified" }, { "ProjectId", projectId.ToString() }, { "BuildingId", buildingId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendModifyBuildingMeaasgeAsync(Guid buildingId, string name, bool IsExist, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var building = await _context.Buildings .FirstOrDefaultAsync(b => b.Id == buildingId && b.TenantId == tenantId); if (building == null) { return; } var projectId = building.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewProjectInfraRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewProjectInfra) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, manageProjectsRoleTask, viewProjectInfraRoleTask); var manageProjectsRoleIds = manageProjectsRoleTask.Result; var viewProjectInfraRoleIds = viewProjectInfraRoleTask.Result; var project = projectTask.Result; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewProjectInfraRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); var buildingName = building.Name; Notification notificationFirebase; if (IsExist) { notificationFirebase = new Notification { Title = $"Building Updated - {project?.ProjectName}", Body = $"{name} updated building \"{buildingName}\" in {project?.ProjectName}." }; } else { notificationFirebase = new Notification { Title = $"New Building Created - {project?.ProjectName}", Body = $"\"{{name}} created a new building \"{buildingName}\" in {project?.ProjectName}." }; } var data = new Dictionary() { { "Keyword", "Building_Modified" }, { "ProjectId", projectId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } public async Task SendDeleteTaskMeaasgeAsync(Guid workItemId, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var workItem = await _context.WorkItems .Include(wi => wi.ActivityMaster) .Include(wi => wi.WorkArea) .ThenInclude(wa => wa!.Floor) .ThenInclude(f => f!.Building) .FirstOrDefaultAsync(wi => workItemId == wi.Id && wi.TenantId == tenantId && wi.ActivityMaster != null && wi.WorkArea != null && wi.WorkArea.Floor != null && wi.WorkArea.Floor.Building != null); if (workItem != null) { return; } var projectId = workItem!.WorkArea!.Floor!.Building!.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var viewTaskRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewTask) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var viewProjectInfraRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewProjectInfra) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, viewTaskRoleTask, manageProjectsRoleTask, viewProjectInfraRoleTask); var viewTaskRoleIds = viewTaskRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var viewProjectInfraRoleIds = viewProjectInfraRoleTask.Result; var project = projectTask.Result; var activityName = workItem.ActivityMaster!.ActivityName; var buildingName = workItem.WorkArea.Floor.Building.Name; var FloorName = workItem.WorkArea.Floor.FloorName; var AreaName = workItem.WorkArea.AreaName; var location = $"{buildingName} > {FloorName} > {AreaName}"; var buildingId = workItem.WorkArea.Floor.Building.Id; var floorId = workItem.WorkArea.Floor.Id; var areaId = workItem.WorkArea.Id; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && (viewTaskRoleIds.Contains(er.RoleId) || viewProjectInfraRoleIds.Contains(er.RoleId))) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase = new Notification { Title = $"Task Deleted - {project?.ProjectName}", Body = $"{name} deleted tasks {activityName} at {location}." }; var data = new Dictionary() { { "Keyword", "Task_Modified" }, { "ProjectId", projectId.ToString() }, { "BuildingId", buildingId.ToString() }, { "FloorId", floorId.ToString() }, { "AreaId", areaId.ToString() }, }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } //Project Allocation public async Task SendProjectAllocationMessageAsync(List projectAllocations, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); foreach (var projectAllocation in projectAllocations) { var projectId = projectAllocation.ProjectId; var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var manageTeamRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageTeam) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, manageTeamRoleTask, manageProjectsRoleTask); var manageTeamRoleIds = manageTeamRoleTask.Result; var manageProjectsRoleIds = manageProjectsRoleTask.Result; var project = projectTask.Result; List projectAssignedEmployeeIds = project?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && manageTeamRoleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase; if (projectAllocation.IsActive) { notificationFirebase = new Notification { Title = $"Assigned to Project - {project?.ProjectName}", Body = $"You have been assigned to the project \"{project?.ProjectName}\"." }; } else { notificationFirebase = new Notification { Title = $"Removed from Project - {project?.ProjectName}", Body = $"{name} has removed you from the project \"{project?.ProjectName}\"." }; } var data = new Dictionary() { { "Keyword", "Team_Modefied" }, { "ProjectId", projectId.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotificationTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => projectAllocation.EmployeeId == ft.EmployeeId && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); }); var registrationTokensForDataTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForData = await dbContext.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForData, data); }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask); } } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } //Project Management public async Task SendModifyProjectMessageAsync(Project project, string name, bool IsExist, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var projectTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.ProjectAllocations .Include(pa => pa.Project) .Where(pa => pa.ProjectId == project.Id && pa.IsActive && pa.Project != null) .GroupBy(pa => pa.ProjectId) .Select(g => new { ProjectName = g.Select(pa => pa.Project!.Name).FirstOrDefault(), EmployeeIds = g.Select(pa => pa.EmployeeId).Distinct().ToList() }).FirstOrDefaultAsync(); }); var manageProjectsRoleTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); return await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); }); await Task.WhenAll(projectTask, manageProjectsRoleTask); var manageProjectsRoleIds = manageProjectsRoleTask.Result; var projectVM = projectTask.Result; List projectAssignedEmployeeIds = projectVM?.EmployeeIds ?? new List(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId))) .Select(er => er.EmployeeId) .ToListAsync(); Notification notificationFirebase; if (IsExist) { notificationFirebase = new Notification { Title = $"Project Updated - {project.Name}", Body = $"{name} updated the project \"{project.Name}\"." }; } else { notificationFirebase = new Notification { Title = $"Project Created - {project.Name}", Body = $"A new project \"{project.Name}\" has been created by {name}." }; } var data = new Dictionary() { { "Keyword", "Project_Modefied" }, { "ProjectId", project.Id.ToString() } }; // List of device registration tokens to send the message to var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } //Expenses Controller public async Task SendExpenseMessageAsync(Expenses expenses, string name, Guid tenantId) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { await using var _context = await _dbContextFactory.CreateDbContextAsync(); var nextStatusIds = await _context.ExpensesStatusMapping.Where(sm => sm.StatusId == expenses.StatusId).Select(sm => sm.NextStatusId).ToListAsync(); var requriedPermissionIds = await _context.StatusPermissionMapping.Where(sp => nextStatusIds.Contains(sp.StatusId)).Select(sp => sp.PermissionId).ToListAsync(); requriedPermissionIds = requriedPermissionIds.Distinct().ToList(); var notificationEmployeeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => requriedPermissionIds.Contains(rp.FeaturePermissionId)) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); var dataEmployeeTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ExpenseViewAll) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); await Task.WhenAll(notificationEmployeeTask, dataEmployeeTask); var notificationEmployeeIds = notificationEmployeeTask.Result; var dataEmployeeIds = dataEmployeeTask.Result; Notification? notificationFirebase = null; Notification? notificationCreatedBy = null; if (expenses.StatusId == Review) { notificationFirebase = new Notification { Title = $"Expense Awaiting Your Review", Body = $"An expense of amount \"{expenses.Amount}\" has been submitted by {name} and is awaiting your review." }; } else if (expenses.StatusId == Approve) { notificationFirebase = new Notification { Title = $"Expense Awaiting Your Approval", Body = $"An expense of amount \"{expenses.Amount}\" has been reviewed by {name} and is awaiting your approval." }; notificationCreatedBy = new Notification { Title = "Expense Reviewed", Body = $"Your expense of amount \"{expenses.Amount}\" is reviewed by {name}." }; } else if (expenses.StatusId == ProcessPending) { notificationFirebase = new Notification { Title = $"Expense Awaiting Your Payment", Body = $"Expense of amount \"{expenses.Amount}\" has been approved by {name}. Please complete the payment." }; notificationCreatedBy = new Notification { Title = "Expense Approved", Body = $"Your expense of amount \"{expenses.Amount}\" is approved by {name}." }; } else if (expenses.StatusId == Processed) { notificationCreatedBy = new Notification { Title = "Expense Paid", Body = $"Your expense of amount \"{expenses.Amount}\" has been processed and paid by {name}." }; } else if (expenses.StatusId == RejectedByApprover || expenses.StatusId == RejectedByReviewer) { notificationCreatedBy = new Notification { Title = "Expense Rejected", Body = $"Your expense of amount \"{expenses.Amount}\" has been rejected by {name}." }; } var data = new Dictionary() { { "Keyword", "Expenses_Modified" }, { "ExpenseId", expenses.Id.ToString() } }; var registrationTokensForNotificationTask = Task.Run(async () => { if (notificationFirebase != null) { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => notificationEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data); } }); var registrationTokensForDataTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForNotification = await dbContext.FCMTokenMappings .Where(ft => dataEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesOnlyDataAsync(registrationTokensForNotification, data); }); var registrationTokensForCreatedByTask = Task.Run(async () => { if (notificationCreatedBy != null) { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var registrationTokensForemployee = await dbContext.FCMTokenMappings .Where(ft => ft.EmployeeId == expenses.CreatedById && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForemployee, notificationCreatedBy, data); } }); await Task.WhenAll(registrationTokensForNotificationTask, registrationTokensForDataTask, registrationTokensForCreatedByTask); } catch (Exception ex) { _logger.LogError(ex, "Exception occured while get data for sending notification"); } } // Directory Controller public async Task SendContactAsync(Guid contactId, List bucketIds, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); var assignedEmployeeIdsTask = Task.Run(async () => { await using var _context = await _dbContextFactory.CreateDbContextAsync(); return await _context.EmployeeBucketMappings.Where(eb => bucketIds.Contains(eb.BucketId)).Select(eb => eb.EmployeeId).ToListAsync(); }); var directoryAdminEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.DirectoryAdmin) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); await Task.WhenAll(assignedEmployeeIdsTask, directoryAdminEmployeeIdsTask); var assignedEmployeeIds = assignedEmployeeIdsTask.Result; var directoryAdminEmployeeIds = directoryAdminEmployeeIdsTask.Result; assignedEmployeeIds.AddRange(directoryAdminEmployeeIds); assignedEmployeeIds = assignedEmployeeIds.Distinct().ToList(); var data = new Dictionary() { { "Keyword", "Contact_Modified" }, { "ContactId", contactId.ToString() } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => assignedEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } public async Task SendContactNoteAsync(Guid contactId, List bucketIds, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); var assignedEmployeeIdsTask = Task.Run(async () => { await using var _context = await _dbContextFactory.CreateDbContextAsync(); return await _context.EmployeeBucketMappings.Where(eb => bucketIds.Contains(eb.BucketId)).Select(eb => eb.EmployeeId).ToListAsync(); }); var directoryAdminEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.DirectoryAdmin) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); await Task.WhenAll(assignedEmployeeIdsTask, directoryAdminEmployeeIdsTask); var assignedEmployeeIds = assignedEmployeeIdsTask.Result; var directoryAdminEmployeeIds = directoryAdminEmployeeIdsTask.Result; assignedEmployeeIds.AddRange(directoryAdminEmployeeIds); assignedEmployeeIds = assignedEmployeeIds.Distinct().ToList(); var data = new Dictionary() { { "Keyword", "Contact_Note_Modified" }, { "ContactId", contactId.ToString() } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => assignedEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } public async Task SendBucketAsync(Guid bucketId, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); var assignedEmployeeIdsTask = Task.Run(async () => { await using var _context = await _dbContextFactory.CreateDbContextAsync(); return await _context.EmployeeBucketMappings.Where(eb => bucketId == eb.BucketId).Select(eb => eb.EmployeeId).ToListAsync(); }); var directoryAdminEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.DirectoryAdmin) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); await Task.WhenAll(assignedEmployeeIdsTask, directoryAdminEmployeeIdsTask); var assignedEmployeeIds = assignedEmployeeIdsTask.Result; var directoryAdminEmployeeIds = directoryAdminEmployeeIdsTask.Result; assignedEmployeeIds.AddRange(directoryAdminEmployeeIds); assignedEmployeeIds = assignedEmployeeIds.Distinct().ToList(); var data = new Dictionary() { { "Keyword", "Bucket_Modified" }, {"BucketId", bucketId.ToString() } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => assignedEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } public async Task SendAssignBucketAsync(List employeeIds, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); var data = new Dictionary() { { "Keyword", "Bucket_Assigned" } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } //Document Controller public async Task SendEmployeeDocumentMessageAsync(Guid documentId, Guid employeeId, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var roleIds = await _context.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewDocument) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await _context.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); employeeIds.Add(employeeId); var data = new Dictionary() { { "Keyword", "Employee_Document_Modified" }, { "EmployeeId", employeeId.ToString() }, { "DocumentId", documentId.ToString() } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } public async Task SendProjectDocumentMessageAsync(Guid documentId, Guid projectId, Notification notification, Guid tenantId) { await using var _context = await _dbContextFactory.CreateDbContextAsync(); using var scope = _serviceScopeFactory.CreateScope(); var assignedEmployeeIdsTask = Task.Run(async () => { await using var _context = await _dbContextFactory.CreateDbContextAsync(); return await _context.ProjectAllocations.Where(pa => projectId == pa.ProjectId).Select(pa => pa.EmployeeId).ToListAsync(); }); var manageProjectEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ManageProject) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); var viewDocumentEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var roleIds = await dbContext.RolePermissionMappings .Where(rp => rp.FeaturePermissionId == PermissionsMaster.ViewDocument) .Select(rp => rp.ApplicationRoleId).ToListAsync(); var employeeIds = await dbContext.EmployeeRoleMappings .Where(er => roleIds.Contains(er.RoleId)) .Select(er => er.EmployeeId) .ToListAsync(); return employeeIds; }); var viewDocumentForProjectEmployeeIdsTask = Task.Run(async () => { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(); var employeeIds = await dbContext.ProjectLevelPermissionMappings .Where(pl => pl.ProjectId == projectId && pl.PermissionId == PermissionsMaster.ViewDocument) .Select(pl => pl.EmployeeId) .ToListAsync(); return employeeIds; }); await Task.WhenAll(assignedEmployeeIdsTask, manageProjectEmployeeIdsTask, viewDocumentEmployeeIdsTask, viewDocumentForProjectEmployeeIdsTask); var assignedEmployeeIds = assignedEmployeeIdsTask.Result; var manageProjectEmployeeIds = manageProjectEmployeeIdsTask.Result; var viewDocumentEmployeeIds = viewDocumentEmployeeIdsTask.Result; var viewDocumentForProjectEmployeeIds = viewDocumentForProjectEmployeeIdsTask.Result; assignedEmployeeIds.AddRange(manageProjectEmployeeIds); assignedEmployeeIds.AddRange(viewDocumentForProjectEmployeeIds); var finalEmployeeIds = assignedEmployeeIds.Intersect(viewDocumentEmployeeIds).ToList(); var data = new Dictionary() { { "Keyword", "Project_Document_Modified" }, { "ProjectId", projectId.ToString() }, { "DocumentId", documentId.ToString() } }; var registrationTokensForNotification = await _context.FCMTokenMappings .Where(ft => finalEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow && ft.TenantId == tenantId) .Select(ft => ft.FcmToken).ToListAsync(); await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } #region =================================================================== Helper Functions =================================================================== public async Task SendMessageToMultipleDevicesWithDataAsync(List registrationTokens, Notification notificationFirebase, Dictionary data) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { registrationTokens = registrationTokens.Distinct().ToList(); var message = new MulticastMessage() { Tokens = registrationTokens, Data = data, Notification = notificationFirebase }; // Send the multicast message var response = await FirebaseMessaging.DefaultInstance.SendEachForMulticastAsync(message); _logger.LogInfo("{SuccessCount} messages were sent successfully.", response.SuccessCount); if (response.FailureCount > 0) { var failedTokens = new List(); for (int i = 0; i < response.Responses.Count; i++) { if (!response.Responses[i].IsSuccess) { failedTokens.Add(registrationTokens[i]); } } _logger.LogInfo("List of tokens that caused failures: " + string.Join(", ", failedTokens)); } } catch (FirebaseMessagingException ex) { // Log the specific Firebase error. _logger.LogError(ex, "Error sending push notification"); // Check for specific error codes that indicate an invalid or unregistered token. if (ex.MessagingErrorCode == MessagingErrorCode.Unregistered || ex.MessagingErrorCode == MessagingErrorCode.InvalidArgument) { _logger.LogWarning("FCM token is invalid and should be deleted from the database"); // TODO: Implement the logic here to remove the invalid token from your database. // Example: await YourTokenService.DeleteTokenAsync(loginDto.DeviceToken); } } catch (Exception ex) { _logger.LogError(ex, "Exception Occured while sending notification to firebase"); } } public async Task SendMessageToMultipleDevicesOnlyDataAsync(List registrationTokens, Dictionary data) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { registrationTokens = registrationTokens.Distinct().ToList(); var message = new MulticastMessage() { Tokens = registrationTokens, Data = data }; // Send the multicast message var response = await FirebaseMessaging.DefaultInstance.SendEachForMulticastAsync(message); _logger.LogInfo("{SuccessCount} messages were sent successfully.", response.SuccessCount); if (response.FailureCount > 0) { var failedTokens = new List(); for (int i = 0; i < response.Responses.Count; i++) { if (!response.Responses[i].IsSuccess) { failedTokens.Add(registrationTokens[i]); } } _logger.LogInfo("List of tokens that caused failures: " + string.Join(", ", failedTokens)); } } catch (FirebaseMessagingException ex) { // Log the specific Firebase error. _logger.LogError(ex, "Error sending push notification"); // Check for specific error codes that indicate an invalid or unregistered token. if (ex.MessagingErrorCode == MessagingErrorCode.Unregistered || ex.MessagingErrorCode == MessagingErrorCode.InvalidArgument) { _logger.LogWarning("FCM token is invalid and should be deleted from the database"); // TODO: Implement the logic here to remove the invalid token from your database. // Example: await YourTokenService.DeleteTokenAsync(loginDto.DeviceToken); } } catch (Exception ex) { _logger.LogError(ex, "Exception Occured while sending notification to firebase"); } } public async Task SendMessageToMultipleDevicesAsync(List registrationTokens, Notification notificationFirebase) { using var scope = _serviceScopeFactory.CreateScope(); var _logger = scope.ServiceProvider.GetRequiredService(); try { registrationTokens = registrationTokens.Distinct().ToList(); var message = new MulticastMessage() { Tokens = registrationTokens, Notification = notificationFirebase }; // Send the multicast message var response = await FirebaseMessaging.DefaultInstance.SendEachForMulticastAsync(message); _logger.LogInfo("{SuccessCount} messages were sent successfully.", response.SuccessCount); if (response.FailureCount > 0) { var failedTokens = new List(); for (int i = 0; i < response.Responses.Count; i++) { if (!response.Responses[i].IsSuccess) { failedTokens.Add(registrationTokens[i]); } } _logger.LogInfo("List of tokens that caused failures: " + string.Join(", ", failedTokens)); } } catch (FirebaseMessagingException ex) { // Log the specific Firebase error. _logger.LogError(ex, "Error sending push notification"); // Check for specific error codes that indicate an invalid or unregistered token. if (ex.MessagingErrorCode == MessagingErrorCode.Unregistered || ex.MessagingErrorCode == MessagingErrorCode.InvalidArgument) { _logger.LogWarning("FCM token is invalid and should be deleted from the database"); // TODO: Implement the logic here to remove the invalid token from your database. // Example: await YourTokenService.DeleteTokenAsync(loginDto.DeviceToken); } } } #endregion } }