From 87ebee8005623549a1b1c0c966f1a01a34964229 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Fri, 12 Sep 2025 18:02:58 +0530 Subject: [PATCH] Added the firebase notification in document controller --- .../Controllers/DocumentController.cs | 139 +++++++++++++++++- Marco.Pms.Services/Service/FirebaseService.cs | 72 +++++++++ .../ServiceInterfaces/IFirebaseService.cs | 3 + 3 files changed, 212 insertions(+), 2 deletions(-) diff --git a/Marco.Pms.Services/Controllers/DocumentController.cs b/Marco.Pms.Services/Controllers/DocumentController.cs index ef73d3c..036e075 100644 --- a/Marco.Pms.Services/Controllers/DocumentController.cs +++ b/Marco.Pms.Services/Controllers/DocumentController.cs @@ -1,4 +1,5 @@ using AutoMapper; +using FirebaseAdmin.Messaging; using Marco.Pms.DataAccess.Data; using Marco.Pms.Helpers.Utility; using Marco.Pms.Model.DocumentManager; @@ -10,6 +11,7 @@ using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.DocumentManager; using Marco.Pms.Services.Service; +using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Service; using Microsoft.AspNetCore.Authorization; @@ -841,6 +843,38 @@ namespace Marco.Pms.Services.Controllers response.ParentAttachmentId = versionMapping.ParentAttachmentId; response.Version = versionMapping.Version; + _ = 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 _firebase = scope.ServiceProvider.GetRequiredService(); + + var name = $"{loggedInEmployee.FirstName} {loggedInEmployee.LastName}"; + + if (EmployeeEntity == entityType && model.EntityId != loggedInEmployee.Id) + { + var notification = new Notification + { + Title = $"Document added to Employee.", + Body = $"Document added to your profile of type \"{documentType.Name}\" by {name}" + }; + + await _firebase.SendEmployeeDocumentMessageAsync(model.EntityId, notification, tenantId); + } + if (ProjectEntity == entityType) + { + var notification = new Notification + { + Title = $"Document added to Project.", + Body = $"Document added to your Project of type \"{documentType.Name}\" by {name}" + }; + + await _firebase.SendProjectDocumentMessageAsync(model.EntityId, notification, tenantId); + } + + }); + return Ok(ApiResponse.SuccessResponse(response, "Document added successfully", 200)); } catch (Exception ex) @@ -932,6 +966,40 @@ namespace Marco.Pms.Services.Controllers } _logger.LogInfo("Document verified successfully. DocumentId: {DocumentId}, VerifiedBy: {EmployeeId}", documentAttachment.Id, loggedInEmployee.Id); + _ = 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 _firebase = scope.ServiceProvider.GetRequiredService(); + + var name = $"{loggedInEmployee.FirstName} {loggedInEmployee.LastName}"; + + var entityType = documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId; + var documentType = documentAttachment.DocumentType; + + if (EmployeeEntity == entityType && documentAttachment.EntityId != loggedInEmployee.Id) + { + var notification = new Notification + { + Title = $"Your Document is Verified.", + Body = $"Your Document of type \"{documentType?.Name}\" is Verified by {name}" + }; + + await _firebase.SendEmployeeDocumentMessageAsync(documentAttachment.EntityId, notification, tenantId); + } + if (ProjectEntity == entityType) + { + var notification = new Notification + { + Title = $"Document for your project is verified", + Body = $"Document for your Project of type \"{documentType?.Name}\" is Verified by {name}" + }; + + await _firebase.SendProjectDocumentMessageAsync(documentAttachment.EntityId, notification, tenantId); + } + + }); return Ok(ApiResponse.SuccessResponse(new { }, "Document is verified successfully", 200)); } catch (Exception ex) @@ -1176,7 +1244,7 @@ namespace Marco.Pms.Services.Controllers oldAttachment.DocumentId = model.DocumentId; oldAttachment.Description = model.Description; oldAttachment.DocumentDataId = document.Id; - if (oldAttachment.IsVerified == true) + if (oldAttachment.IsVerified != null) { oldAttachment.IsVerified = null; _logger.LogInfo("Reset verification flag for AttachmentId: {AttachmentId}", oldAttachment.Id); @@ -1196,7 +1264,7 @@ namespace Marco.Pms.Services.Controllers oldAttachment.Name = model.Name; oldAttachment.DocumentId = model.DocumentId; oldAttachment.Description = model.Description; - if (oldAttachment.IsVerified == true) + if (oldAttachment.IsVerified != null) { oldAttachment.IsVerified = null; _logger.LogInfo("Reset verification flag for AttachmentId: {AttachmentId}", oldAttachment.Id); @@ -1288,6 +1356,38 @@ namespace Marco.Pms.Services.Controllers response.Version = newVersionMapping.Version; _logger.LogInfo("API completed successfully for AttachmentId: {AttachmentId}", newAttachment.Id); + _ = 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 _firebase = scope.ServiceProvider.GetRequiredService(); + + var name = $"{loggedInEmployee.FirstName} {loggedInEmployee.LastName}"; + + if (EmployeeEntity == entityType && newAttachment.EntityId != loggedInEmployee.Id) + { + var notification = new Notification + { + Title = $"Your Document is updated.", + Body = $"Your Document of type \"{documentType?.Name}\" is updated by {name}" + }; + + await _firebase.SendEmployeeDocumentMessageAsync(newAttachment.EntityId, notification, tenantId); + } + if (ProjectEntity == entityType) + { + var notification = new Notification + { + Title = "Your Project Document is updated.", + Body = $"Your Project Document of type \"{documentType?.Name}\" is updated by {name}" + }; + + await _firebase.SendProjectDocumentMessageAsync(newAttachment.EntityId, notification, tenantId); + } + + }); + return Ok(ApiResponse.SuccessResponse(response, "Document Updated successfully", 200)); } catch (Exception ex) @@ -1371,6 +1471,41 @@ namespace Marco.Pms.Services.Controllers // Log the successful completion of the operation _logger.LogInfo("DocumentAttachment ID: {DocumentId} has been {Message} by employee ID: {EmployeeId}", id, message, loggedInEmployee.Id); + _ = 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 _firebase = scope.ServiceProvider.GetRequiredService(); + + var entityType = documentAttachment.DocumentType?.DocumentCategory?.EntityTypeId; + var documentType = documentAttachment.DocumentType; + + var name = $"{loggedInEmployee.FirstName} {loggedInEmployee.LastName}"; + + if (EmployeeEntity == entityType && documentAttachment.EntityId != loggedInEmployee.Id) + { + var notification = new Notification + { + Title = $"Your Document is {message}.", + Body = $"Your Document of type \"{documentType?.Name}\" is {message} by {name}" + }; + + await _firebase.SendEmployeeDocumentMessageAsync(documentAttachment.EntityId, notification, tenantId); + } + if (ProjectEntity == entityType) + { + var notification = new Notification + { + Title = "Your Project Document is {message}.", + Body = $"Your Project Document of type \"{documentType?.Name}\" is {message} by {name}" + }; + + await _firebase.SendProjectDocumentMessageAsync(documentAttachment.EntityId, notification, tenantId); + } + + }); + // Return success response return Ok(ApiResponse.SuccessResponse(new { }, $"Document attachment is {message}", 200)); } diff --git a/Marco.Pms.Services/Service/FirebaseService.cs b/Marco.Pms.Services/Service/FirebaseService.cs index ef7e1fd..7299dea 100644 --- a/Marco.Pms.Services/Service/FirebaseService.cs +++ b/Marco.Pms.Services/Service/FirebaseService.cs @@ -1769,6 +1769,78 @@ namespace Marco.Pms.Services.Service await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); } + //Document Controller + public async Task SendEmployeeDocumentMessageAsync(Guid employeeId, Notification notification, Guid tenantId) + { + await using var _context = await _dbContextFactory.CreateDbContextAsync(); + using var scope = _serviceScopeFactory.CreateScope(); + + var data = new Dictionary() + { + { "Keyword", "Employee_Document_Modefied" } + }; + + var registrationTokensForNotification = await _context.FCMTokenMappings.Where(ft => ft.EmployeeId == employeeId && ft.ExpiredAt >= DateTime.UtcNow).Select(ft => ft.FcmToken).ToListAsync(); + + await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); + } + public async Task SendProjectDocumentMessageAsync(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; + }); + + await Task.WhenAll(assignedEmployeeIdsTask, manageProjectEmployeeIdsTask, viewDocumentEmployeeIdsTask); + + var assignedEmployeeIds = assignedEmployeeIdsTask.Result; + var manageProjectEmployeeIds = manageProjectEmployeeIdsTask.Result; + var viewDocumentEmployeeIds = viewDocumentEmployeeIdsTask.Result; + + assignedEmployeeIds.AddRange(manageProjectEmployeeIds); + + var finalEmployeeIds = assignedEmployeeIds.Intersect(viewDocumentEmployeeIds).ToList(); + + var data = new Dictionary() + { + { "Keyword", "Project_Document_Modefied" } + }; + + var registrationTokensForNotification = await _context.FCMTokenMappings.Where(ft => finalEmployeeIds.Contains(ft.EmployeeId) && ft.ExpiredAt >= DateTime.UtcNow).Select(ft => ft.FcmToken).ToListAsync(); + + await SendMessageToMultipleDevicesWithDataAsync(registrationTokensForNotification, notification, data); + } + #region =================================================================== Helper Functions =================================================================== public async Task SendMessageToMultipleDevicesWithDataAsync(List registrationTokens, Notification notificationFirebase, Dictionary data) diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IFirebaseService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IFirebaseService.cs index e0c69a1..1f57ef0 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IFirebaseService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IFirebaseService.cs @@ -28,5 +28,8 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task SendContactNoteAsync(List bucketIds, Notification notification, Guid tenantId); Task SendBucketAsync(Guid bucketId, Notification notification, Guid tenantId); Task SendAssignBucketAsync(List employeeIds, Notification notification, Guid tenantId); + + Task SendEmployeeDocumentMessageAsync(Guid employeeId, Notification notification, Guid tenantId); + Task SendProjectDocumentMessageAsync(Guid projectId, Notification notification, Guid tenantId); } }