Added the firebase services
This commit is contained in:
parent
47a3d6035c
commit
58b817be99
@ -102,6 +102,8 @@ namespace Marco.Pms.DataAccess.Data
|
||||
public DbSet<StatusPermissionMapping> StatusPermissionMapping { get; set; }
|
||||
public DbSet<ExpensesStatusMapping> ExpensesStatusMapping { get; set; }
|
||||
|
||||
public DbSet<FCMTokenMapping> FCMTokenMappings { get; set; }
|
||||
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
4471
Marco.Pms.DataAccess/Migrations/20250813060211_Added_FCMTokenMApping_Table.Designer.cs
generated
Normal file
4471
Marco.Pms.DataAccess/Migrations/20250813060211_Added_FCMTokenMApping_Table.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Marco.Pms.DataAccess.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Added_FCMTokenMApping_Table : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "FCMTokenMappings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
EmployeeId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||
FcmToken = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_FCMTokenMappings", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_FCMTokenMappings_Tenants_TenantId",
|
||||
column: x => x.TenantId,
|
||||
principalTable: "Tenants",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FCMTokenMappings_TenantId",
|
||||
table: "FCMTokenMappings",
|
||||
column: "TenantId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "FCMTokenMappings");
|
||||
}
|
||||
}
|
||||
}
|
@ -3058,6 +3058,29 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.ToTable("JobRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.Utilities.FCMTokenMapping", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid>("EmployeeId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("FcmToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("FCMTokenMappings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.Utilities.Inquiries", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@ -4368,6 +4391,17 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.Navigation("Tenant");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.Utilities.FCMTokenMapping", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant")
|
||||
.WithMany()
|
||||
.HasForeignKey("TenantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Tenant");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
|
@ -2,8 +2,8 @@
|
||||
{
|
||||
public class FCMTokenMapping : TenantRelation
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid EmployeeId { get; set; }
|
||||
public string FCcmToken { get; set; } = string.Empty;
|
||||
public string FcmToken { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
using FirebaseAdmin.Messaging;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Authentication;
|
||||
using Marco.Pms.Model.Dtos.Authentication;
|
||||
using Marco.Pms.Model.Dtos.Util;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Services.Service.ServiceInterfaces;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -32,9 +32,10 @@ namespace MarcoBMS.Services.Controllers
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly EmployeeHelper _employeeHelper;
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly IFirebaseService _firebase;
|
||||
//string tenentId = "1";
|
||||
public AuthController(UserManager<ApplicationUser> userManager, ApplicationDbContext context, JwtSettings jwtSettings, RefreshTokenService refreshTokenService,
|
||||
IEmailSender emailSender, IConfiguration configuration, EmployeeHelper employeeHelper, UserHelper userHelper, ILoggingService logger)
|
||||
IEmailSender emailSender, IConfiguration configuration, EmployeeHelper employeeHelper, UserHelper userHelper, ILoggingService logger, IFirebaseService firebase)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_jwtSettings = jwtSettings;
|
||||
@ -45,6 +46,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
_context = context;
|
||||
_userHelper = userHelper;
|
||||
_logger = logger;
|
||||
_firebase = firebase;
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
@ -222,42 +224,40 @@ namespace MarcoBMS.Services.Controllers
|
||||
// Return a successful response with the generated tokens.
|
||||
_logger.LogInfo("User {Username} logged in successfully.", user.UserName);
|
||||
|
||||
var exsistingFCMMapping = await _context.FCMTokenMappings.FirstOrDefaultAsync(ft => ft.EmployeeId == emp.Id);
|
||||
if (exsistingFCMMapping == null)
|
||||
{
|
||||
var fcmTokenMapping = new FCMTokenMapping
|
||||
{
|
||||
EmployeeId = emp.Id,
|
||||
FcmToken = loginDto.FcmToken,
|
||||
TenantId = emp.TenantId
|
||||
};
|
||||
_context.FCMTokenMappings.Add(fcmTokenMapping);
|
||||
_logger.LogInfo("New FCM Token registering for employee {EmployeeId}", emp.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
exsistingFCMMapping.FcmToken = loginDto.FcmToken;
|
||||
_logger.LogInfo("Updating FCM Token for employee {EmployeeId}", emp.Id);
|
||||
}
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occured while saving FCM Token for employee {EmployeeId}", emp.Id);
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal Error", ex.Message, 500));
|
||||
}
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
// --- Push Notification Section ---
|
||||
// This section attempts to send a test push notification to the user's device.
|
||||
// It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.
|
||||
var message = new Message()
|
||||
{
|
||||
Token = loginDto.FcmToken,
|
||||
Notification = new Notification
|
||||
{
|
||||
Title = "Hello from AuthController",
|
||||
Body = "This is a test with not increased response time message"
|
||||
}
|
||||
};
|
||||
await _firebase.SendMessageToMultipleDevicesAsync();
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to send the message via Firebase.
|
||||
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
|
||||
_logger.LogInfo("Successfully sent test push notification. MessageId: {MessageId}", response);
|
||||
}
|
||||
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: {Token}", loginDto.FcmToken ?? string.Empty);
|
||||
|
||||
// TODO: Implement the logic here to remove the invalid token from your database.
|
||||
// Example: await YourTokenService.DeleteTokenAsync(loginDto.DeviceToken);
|
||||
}
|
||||
}
|
||||
});
|
||||
return Ok(ApiResponse<object>.SuccessResponse(responseData, "User logged in successfully.", 200));
|
||||
}
|
||||
@ -899,22 +899,34 @@ namespace MarcoBMS.Services.Controllers
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var tenantId = _userHelper.GetTenantId();
|
||||
|
||||
var exsistingFCMMapping = await _context.FCMTokenMappings.FirstOrDefaultAsync(ft => ft.EmployeeId == loggedInEmployee.Id);
|
||||
if (exsistingFCMMapping == null)
|
||||
{
|
||||
var fcmTokenMapping = new FCMTokenMapping
|
||||
{
|
||||
EmployeeId = loggedInEmployee.Id,
|
||||
FcmToken = model.FcmToken,
|
||||
TenantId = tenantId
|
||||
};
|
||||
//_context.FCMTokenMappings.Add(fcmTokenMapping);
|
||||
//try
|
||||
//{
|
||||
// await _context.SaveChangesAsync();
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// _logger.LogError(ex, "Exception occured while saving FCM Token for employee {EmployeeId}", loggedInEmployee.Id);
|
||||
//}
|
||||
return Ok(ApiResponse<object>.SuccessResponse(fcmTokenMapping));
|
||||
_context.FCMTokenMappings.Add(fcmTokenMapping);
|
||||
_logger.LogInfo("New FCM Token registering for employee {EmployeeId}", loggedInEmployee.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
exsistingFCMMapping.FcmToken = model.FcmToken;
|
||||
_logger.LogInfo("Updating FCM Token for employee {EmployeeId}", loggedInEmployee.Id);
|
||||
}
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occured while saving FCM Token for employee {EmployeeId}", loggedInEmployee.Id);
|
||||
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal Error", ex.Message, 500));
|
||||
}
|
||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "FCM Token registered Successfuly", 200));
|
||||
}
|
||||
private static string ComputeSha256Hash(string rawData)
|
||||
{
|
||||
|
@ -178,6 +178,7 @@ builder.Services.AddScoped<ISignalRService, SignalRService>();
|
||||
builder.Services.AddScoped<IProjectServices, ProjectServices>();
|
||||
builder.Services.AddScoped<IExpensesService, ExpensesService>();
|
||||
builder.Services.AddScoped<IMasterService, MasterService>();
|
||||
builder.Services.AddScoped<IFirebaseService, FirebaseService>();
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
90
Marco.Pms.Services/Service/FirebaseService.cs
Normal file
90
Marco.Pms.Services/Service/FirebaseService.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using FirebaseAdmin.Messaging;
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
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 SendDemoMessages(Notification notificationFirebase)
|
||||
{
|
||||
string deviceToken = "";
|
||||
var message = new Message()
|
||||
{
|
||||
Token = deviceToken,
|
||||
Notification = notificationFirebase
|
||||
};
|
||||
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
|
||||
}
|
||||
|
||||
public async Task SendMessageToMultipleDevicesAsync()
|
||||
{
|
||||
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 registrationTokens = new List<string>
|
||||
//{
|
||||
// "YOUR_REGISTRATION_TOKEN_1",
|
||||
// "YOUR_REGISTRATION_TOKEN_2",
|
||||
// // add up to 500 tokens
|
||||
//};
|
||||
|
||||
var message = new MulticastMessage()
|
||||
{
|
||||
Tokens = registrationTokens,
|
||||
Notification = new Notification
|
||||
{
|
||||
Title = "Testing from API",
|
||||
Body = "This messages comes from FireBase Services"
|
||||
}
|
||||
};
|
||||
try
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
{
|
||||
public interface IFirebaseService
|
||||
{
|
||||
Task SendMessageToMultipleDevicesAsync();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user