235 lines
11 KiB
C#
235 lines
11 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 ILoggingService _logger;
|
|
public FirebaseService(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
|
ILoggingService logger)
|
|
{
|
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
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);
|
|
}
|
|
public async Task SendAttendanceMessageAsync(Guid projectId, string Name, ATTENDANCE_MARK_TYPE markType, 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 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);
|
|
|
|
var teamAttendanceRoleIds = teamAttendanceRoleTask.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();
|
|
|
|
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 ?? ""}."
|
|
};
|
|
break;
|
|
case ATTENDANCE_MARK_TYPE.CHECK_OUT:
|
|
notificationFirebase = new Notification
|
|
{
|
|
Title = "Attendance Update",
|
|
Body = $" {Name} has checked out for project {project?.ProjectName ?? ""}."
|
|
};
|
|
break;
|
|
case ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE:
|
|
notificationFirebase = new Notification
|
|
{
|
|
Title = "Regularization Request",
|
|
Body = $" {Name} has submitted a regularization request for project {project?.ProjectName ?? ""}."
|
|
};
|
|
break;
|
|
case ATTENDANCE_MARK_TYPE.REGULARIZE:
|
|
notificationFirebase = new Notification
|
|
{
|
|
Title = " Regularization Approved",
|
|
Body = $" {Name}'s regularization request for project {project?.ProjectName ?? ""} has been accepted."
|
|
};
|
|
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."
|
|
};
|
|
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 registrationTokens = await _context.FCMTokenMappings
|
|
.Where(ft => employeeIds.Contains(ft.EmployeeId) && ft.TenantId == tenantId)
|
|
.Select(ft => ft.FcmToken).ToListAsync();
|
|
|
|
var data = new Dictionary<string, string>()
|
|
{
|
|
{ "Keyword", "Attendance" },
|
|
{ "ProjectId", projectId.ToString() },
|
|
{ "Action", markType.ToString() }
|
|
};
|
|
|
|
await SendMessageToMultipleDevicesWithDataAsync(registrationTokens, notificationFirebase, data);
|
|
}
|
|
public async Task SendMessageToMultipleDevicesWithDataAsync(List<string> registrationTokens, Notification notificationFirebase, Dictionary<string, string> data)
|
|
{
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
public async Task SendMessageToMultipleDevicesAsync(List<string> registrationTokens, Notification notificationFirebase)
|
|
{
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|