821 lines
40 KiB
C#

using FirebaseAdmin.Messaging;
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Dtos.Attendance;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Services.Service.ServiceInterfaces;
using MarcoBMS.Services.Service;
using Microsoft.EntityFrameworkCore;
namespace Marco.Pms.Services.Service
{
public class FirebaseService : IFirebaseService
{
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
private readonly IServiceScopeFactory _serviceScopeFactory;
public FirebaseService(IDbContextFactory<ApplicationDbContext> dbContextFactory,
IServiceScopeFactory serviceScopeFactory)
{
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
}
public async Task SendLoginMessageAsync(string name)
{
await using var _context = await _dbContextFactory.CreateDbContextAsync();
// List of device registration tokens to send the message to
var registrationTokens = await _context.FCMTokenMappings.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);
}
// 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<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
var employeeIds = await _context.EmployeeRoleMappings
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && teamAttendanceRoleIds.Contains(er.RoleId))
.Select(er => er.EmployeeId)
.ToListAsync();
var dataNotificationIds = new List<Guid>();
var mesaageNotificationIds = new List<Guid>();
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();
dataNotificationIds = employeeIds;
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);
dataNotificationIds.AddRange(employeeIds);
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);
dataNotificationIds.AddRange(employeeIds);
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<string, string>()
{
{ "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)).Select(ft => ft.FcmToken).ToListAsync();
await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notificationFirebase, data);
}
});
var registrationTokensForDataTask = Task.Run(async () =>
{
if (dataNotificationIds.Any())
{
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
var registrationTokensForData = await dbContext.FCMTokenMappings.Where(ft => dataNotificationIds.Contains(ft.EmployeeId)).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<Guid> teamMembers, Guid tenantId)
{
using var scope = _serviceScopeFactory.CreateScope();
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
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<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
var employeeIds = await _context.EmployeeRoleMappings
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewTaskRoleIds.Contains(er.RoleId))
.Select(er => er.EmployeeId)
.ToListAsync();
var data = new Dictionary<string, string>()
{
{ "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)).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)).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<ILoggingService>();
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 teamMemberTask = 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 viewTaskRoleTask = 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<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
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)) && viewTaskRoleIds.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<string, string>()
{
{ "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)).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)).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<ILoggingService>();
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.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, 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<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
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<string, string>()
{
{ "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)).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<ILoggingService>();
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 teamMemberTask = 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 viewTaskRoleTask = 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<Guid> projectAssignedEmployeeIds = project?.EmployeeIds ?? new List<Guid>();
var employeeIds = await _context.EmployeeRoleMappings
.Where(er => (projectAssignedEmployeeIds.Contains(er.EmployeeId) || manageProjectsRoleIds.Contains(er.RoleId)) && viewTaskRoleIds.Contains(er.RoleId))
.Select(er => er.EmployeeId)
.ToListAsync();
teamMembers.Add(taskAllocation.AssignedBy);
var data = new Dictionary<string, string>()
{
{ "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)).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)).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
public async Task SendMessageToMultipleDevicesWithDataAsync(List<string> registrationTokens, Notification notificationFirebase, Dictionary<string, string> data)
{
using var scope = _serviceScopeFactory.CreateScope();
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
try
{
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<string>();
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<string> registrationTokens, Dictionary<string, string> data)
{
using var scope = _serviceScopeFactory.CreateScope();
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
try
{
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<string>();
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<string> registrationTokens, Notification notificationFirebase)
{
using var scope = _serviceScopeFactory.CreateScope();
var _logger = scope.ServiceProvider.GetRequiredService<ILoggingService>();
try
{
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<string>();
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);
}
}
}
}
}