Addd the collection related permission in context and APIs

This commit is contained in:
ashutosh.nehete 2025-10-16 13:04:49 +05:30
parent 70aa5121fa
commit 843dc8edfc
6 changed files with 7177 additions and 9 deletions

View File

@ -1106,6 +1106,7 @@ namespace Marco.Pms.DataAccess.Data
// Project Module
new Feature { Id = new Guid("53176ebf-c75d-42e5-839f-4508ffac3def"), Description = "Manage Project", Name = "Project Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true },
new Feature { Id = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), Description = "Expense Management is the systematic process of tracking, controlling, and reporting business-related expenditures.", Name = "Expense Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true },
new Feature { Id = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), Description = "Collection Management is a feature that enables organizations to track, organize, and manage the status and recovery of receivables or assets efficiently throughout their lifecycle, supporting systematic follow-up and resolution of outstanding accounts.", Name = "Collection Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true },
new Feature { Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"), Description = "Manage Tasks", Name = "Task Management", ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), IsActive = true },
// Employee Module
@ -1177,6 +1178,13 @@ namespace Marco.Pms.DataAccess.Data
new FeaturePermission { Id = new Guid("ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Process", Description = "Allows a user to handle post-approval actions such as recording payments, updating financial records, or marking expenses as reimbursed or settled." },
new FeaturePermission { Id = new Guid("bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3"), FeatureId = new Guid("a4e25142-449b-4334-a6e5-22f70e4732d7"), IsEnabled = true, Name = "Manage", Description = "Allows a user to configure and control system settings, such as managing expense types, payment modes, permissions, and overall workflow rules." },
// Collection Management Feature
new FeaturePermission { Id = new Guid("dbf17591-09fe-4c93-9e1a-12db8f5cc5de"), FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), IsEnabled = true, Name = "Collection Admin", Description = "Collection Admin is a permission that grants a user full administrative control over collections, including creating, editing, managing access, and deleting collections within a system." },
new FeaturePermission { Id = new Guid("c8d7eea5-4033-4aad-9ebe-76de49896830"), FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), IsEnabled = true, Name = "View Collection", Description = "View Collection is a permission that allows users to see and browse assets or items within a collection without making any modifications or edits to its contents." },
new FeaturePermission { Id = new Guid("b93141fd-dbd3-4051-8f57-bf25d18e3555"), FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), IsEnabled = true, Name = "Create Collection", Description = "Authorizes users to create new collections for organizing related resources and managing access" },
new FeaturePermission { Id = new Guid("455187b4-fef1-41f9-b3d0-025d0b6302c3"), FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), IsEnabled = true, Name = "Edit Collection", Description = "Ability to modify collection properties, content, and access rights." },
new FeaturePermission { Id = new Guid("061d9ccd-85b4-4cb0-be06-2f9f32cebb72"), FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), IsEnabled = true, Name = "Add Payment", Description = " Enables entry and processing of payment transactions." },
// Organization Management Feature
new FeaturePermission { Id = new Guid("068cb3c1-49c5-4746-9f29-1fce16e820ac"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "Add Organization", Description = "Allow user to create new organization" },
new FeaturePermission { Id = new Guid("c1ae1363-ab8a-4bd9-a9d1-8c2c6083873a"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "Edit Organization", Description = "Allow the user to update the basic information of the organization" },

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,68 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
namespace Marco.Pms.DataAccess.Migrations
{
/// <inheritdoc />
public partial class Added_Collection_Related_Permissions : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "Features",
columns: new[] { "Id", "Description", "IsActive", "ModuleId", "Name" },
values: new object[] { new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), "Collection Management is a feature that enables organizations to track, organize, and manage the status and recovery of receivables or assets efficiently throughout their lifecycle, supporting systematic follow-up and resolution of outstanding accounts.", true, new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"), "Collection Management" });
migrationBuilder.InsertData(
table: "FeaturePermissions",
columns: new[] { "Id", "Description", "FeatureId", "IsEnabled", "Name" },
values: new object[,]
{
{ new Guid("061d9ccd-85b4-4cb0-be06-2f9f32cebb72"), " Enables entry and processing of payment transactions.", new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), true, "Add Payment" },
{ new Guid("455187b4-fef1-41f9-b3d0-025d0b6302c3"), "Ability to modify collection properties, content, and access rights.", new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), true, "Edit Collection" },
{ new Guid("b93141fd-dbd3-4051-8f57-bf25d18e3555"), "Authorizes users to create new collections for organizing related resources and managing access", new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), true, "Create Collection" },
{ new Guid("c8d7eea5-4033-4aad-9ebe-76de49896830"), "View Collection is a permission that allows users to see and browse assets or items within a collection without making any modifications or edits to its contents.", new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), true, "View Collection" },
{ new Guid("dbf17591-09fe-4c93-9e1a-12db8f5cc5de"), "Collection Admin is a permission that grants a user full administrative control over collections, including creating, editing, managing access, and deleting collections within a system.", new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"), true, "Collection Admin" }
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("061d9ccd-85b4-4cb0-be06-2f9f32cebb72"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("455187b4-fef1-41f9-b3d0-025d0b6302c3"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("b93141fd-dbd3-4051-8f57-bf25d18e3555"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("c8d7eea5-4033-4aad-9ebe-76de49896830"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("dbf17591-09fe-4c93-9e1a-12db8f5cc5de"));
migrationBuilder.DeleteData(
table: "Features",
keyColumn: "Id",
keyValue: new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"));
}
}
}

View File

@ -1955,6 +1955,46 @@ namespace Marco.Pms.DataAccess.Migrations
Name = "Manage"
},
new
{
Id = new Guid("dbf17591-09fe-4c93-9e1a-12db8f5cc5de"),
Description = "Collection Admin is a permission that grants a user full administrative control over collections, including creating, editing, managing access, and deleting collections within a system.",
FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
IsEnabled = true,
Name = "Collection Admin"
},
new
{
Id = new Guid("c8d7eea5-4033-4aad-9ebe-76de49896830"),
Description = "View Collection is a permission that allows users to see and browse assets or items within a collection without making any modifications or edits to its contents.",
FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
IsEnabled = true,
Name = "View Collection"
},
new
{
Id = new Guid("b93141fd-dbd3-4051-8f57-bf25d18e3555"),
Description = "Authorizes users to create new collections for organizing related resources and managing access",
FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
IsEnabled = true,
Name = "Create Collection"
},
new
{
Id = new Guid("455187b4-fef1-41f9-b3d0-025d0b6302c3"),
Description = "Ability to modify collection properties, content, and access rights.",
FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
IsEnabled = true,
Name = "Edit Collection"
},
new
{
Id = new Guid("061d9ccd-85b4-4cb0-be06-2f9f32cebb72"),
Description = " Enables entry and processing of payment transactions.",
FeatureId = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
IsEnabled = true,
Name = "Add Payment"
},
new
{
Id = new Guid("068cb3c1-49c5-4746-9f29-1fce16e820ac"),
Description = "Allow user to create new organization",
@ -3096,6 +3136,14 @@ namespace Marco.Pms.DataAccess.Migrations
Name = "Expense Management"
},
new
{
Id = new Guid("fc586e7d-ed1a-45e5-bb51-9f34af98ec13"),
Description = "Collection Management is a feature that enables organizations to track, organize, and manage the status and recovery of receivables or assets efficiently throughout their lifecycle, supporting systematic follow-up and resolution of outstanding accounts.",
IsActive = true,
ModuleId = new Guid("bf59fd88-b57a-4d67-bf01-3780f385896b"),
Name = "Collection Management"
},
new
{
Id = new Guid("9d4b5489-2079-40b9-bd77-6e1bf90bc19f"),
Description = "Manage Tasks",

View File

@ -47,6 +47,12 @@
public static readonly Guid DownloadDocument = Guid.Parse("404373d0-860f-490e-a575-1c086ffbce1d");
public static readonly Guid VerifyDocument = Guid.Parse("13a1f30f-38d1-41bf-8e7a-b75189aab8e0");
public static readonly Guid CollectionAdmin = Guid.Parse("dbf17591-09fe-4c93-9e1a-12db8f5cc5de");
public static readonly Guid ViewCollection = Guid.Parse("c8d7eea5-4033-4aad-9ebe-76de49896830");
public static readonly Guid CreateCollection = Guid.Parse("b93141fd-dbd3-4051-8f57-bf25d18e3555");
public static readonly Guid EditCollection = Guid.Parse("455187b4-fef1-41f9-b3d0-025d0b6302c3");
public static readonly Guid AddPayment = Guid.Parse("061d9ccd-85b4-4cb0-be06-2f9f32cebb72");
public static readonly Guid AddOrganization = Guid.Parse("068cb3c1-49c5-4746-9f29-1fce16e820ac");
public static readonly Guid EditOrganization = Guid.Parse("c1ae1363-ab8a-4bd9-a9d1-8c2c6083873a");
public static readonly Guid ViewOrganization = Guid.Parse("7a6cf830-0008-4e03-b31d-0d050cb634f4");

View File

@ -4,6 +4,7 @@ using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.Collection;
using Marco.Pms.Model.DocumentManager;
using Marco.Pms.Model.Dtos.Collection;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.MongoDBModels.Utility;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Activities;
@ -57,6 +58,75 @@ namespace Marco.Pms.Services.Controllers
"Fetching invoice list: Page {PageNumber}, Size {PageSize}, Active={IsActive}, PendingOnly={IsPending}, Search='{SearchString}', From={From}, To={To}",
pageNumber, pageSize, isActive, isPending, searchString ?? "", fromDate?.Date ?? DateTime.MinValue, toDate?.Date ?? DateTime.MaxValue);
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var viewPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.ViewCollection, loggedInEmployee.Id);
});
var createPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CreateCollection, loggedInEmployee.Id);
});
var editPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.EditCollection, loggedInEmployee.Id);
});
var addPaymentPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.AddPayment, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, viewPermissionTask, createPermissionTask, editPermissionTask, addPaymentPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasViewPermission = viewPermissionTask.Result;
var hasCreatePermission = createPermissionTask.Result;
var hasEditPermission = editPermissionTask.Result;
var hasAddPaymentPermission = addPaymentPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, View={View}, Create={Create}, Edit={Edit}, Add Payment={AddPayment}",
loggedInEmployee.Id, hasAdminPermission, hasViewPermission, hasCreatePermission, hasEditPermission, hasAddPaymentPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasViewPermission && !hasCreatePermission && !hasEditPermission && !hasAddPaymentPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
await using var _context = await _dbContextFactory.CreateDbContextAsync();
// Build base query with required includes and no tracking
@ -170,9 +240,77 @@ namespace Marco.Pms.Services.Controllers
{
_logger.LogInfo("Fetching details for InvoiceId: {InvoiceId}, TenantId: {TenantId}", id, tenantId);
await using var context = await _dbContextFactory.CreateDbContextAsync();
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var viewPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.ViewCollection, loggedInEmployee.Id);
});
var createPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CreateCollection, loggedInEmployee.Id);
});
var editPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.EditCollection, loggedInEmployee.Id);
});
var addPaymentPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.AddPayment, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, viewPermissionTask, createPermissionTask, editPermissionTask, addPaymentPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasViewPermission = viewPermissionTask.Result;
var hasCreatePermission = createPermissionTask.Result;
var hasEditPermission = editPermissionTask.Result;
var hasAddPaymentPermission = addPaymentPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, View={View}, Create={Create}, Edit={Edit}, Add Payment={AddPayment}",
loggedInEmployee.Id, hasAdminPermission, hasViewPermission, hasCreatePermission, hasEditPermission, hasAddPaymentPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasViewPermission && !hasCreatePermission && !hasEditPermission && !hasAddPaymentPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
await using var context = await _dbContextFactory.CreateDbContextAsync();
// Retrieve primary invoice details with related entities (project, created/updated by + roles)
var invoice = await context.Invoices
.Include(i => i.Project)
@ -241,9 +379,53 @@ namespace Marco.Pms.Services.Controllers
[HttpPost("invoice/create")]
public async Task<IActionResult> CreateInvoiceAsync([FromBody] InvoiceDto model)
{
await using var _context = await _dbContextFactory.CreateDbContextAsync();
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var createPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CreateCollection, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, createPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasCreatePermission = createPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, Create={Create}",
loggedInEmployee.Id, hasAdminPermission, hasCreatePermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasCreatePermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
await using var _context = await _dbContextFactory.CreateDbContextAsync();
_logger.LogInfo("Starting invoice creation for ProjectId: {ProjectId} by EmployeeId: {EmployeeId}",
model.ProjectId, loggedInEmployee.Id);
@ -437,6 +619,51 @@ namespace Marco.Pms.Services.Controllers
[HttpPost("invoice/payment/received")]
public async Task<IActionResult> CreateReceivedInvoicePaymentAsync([FromBody] ReceivedInvoicePaymentDto model)
{
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var addPaymentPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.AddPayment, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, addPaymentPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasAddPaymentPermission = addPaymentPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, Add Payment={AddPayment}",
loggedInEmployee.Id, hasAdminPermission, hasAddPaymentPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasAddPaymentPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
// Validate input model
if (model == null)
{
@ -445,7 +672,6 @@ namespace Marco.Pms.Services.Controllers
}
await using var _context = await _dbContextFactory.CreateDbContextAsync();
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Retrieve invoice with tenant isolation and no tracking for read-only access
var invoice = await _context.Invoices
@ -554,6 +780,75 @@ namespace Marco.Pms.Services.Controllers
[HttpPost("invoice/add/comment")]
public async Task<IActionResult> AddCommentToInvoiceAsync([FromBody] InvoiceCommentDto model)
{
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var viewPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.ViewCollection, loggedInEmployee.Id);
});
var createPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CreateCollection, loggedInEmployee.Id);
});
var editPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.EditCollection, loggedInEmployee.Id);
});
var addPaymentPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.AddPayment, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, viewPermissionTask, createPermissionTask, editPermissionTask, addPaymentPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasViewPermission = viewPermissionTask.Result;
var hasCreatePermission = createPermissionTask.Result;
var hasEditPermission = editPermissionTask.Result;
var hasAddPaymentPermission = addPaymentPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, View={View}, Create={Create}, Edit={Edit}, Add Payment={AddPayment}",
loggedInEmployee.Id, hasAdminPermission, hasViewPermission, hasCreatePermission, hasEditPermission, hasAddPaymentPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasViewPermission && !hasCreatePermission && !hasEditPermission && !hasAddPaymentPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
// Validate incoming data early to avoid unnecessary database calls.
if (string.IsNullOrWhiteSpace(model.Comment))
{
@ -565,7 +860,6 @@ namespace Marco.Pms.Services.Controllers
}
await using var _context = await _dbContextFactory.CreateDbContextAsync();
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Find the target invoice for the specified tenant.
var invoice = await _context.Invoices
@ -620,6 +914,51 @@ namespace Marco.Pms.Services.Controllers
[HttpPut("invoice/edit/{id}")]
public async Task<IActionResult> UpdateInvoiceAsync(Guid id, [FromBody] InvoiceDto model)
{
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initiate permission check tasks asynchronously
var adminPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
});
var editPermissionTask = Task.Run(async () =>
{
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await _permission.HasPermission(PermissionsMaster.EditCollection, loggedInEmployee.Id);
});
// Await all permission checks to complete concurrently
await Task.WhenAll(adminPermissionTask, editPermissionTask);
// Capture permission results
var hasAdminPermission = adminPermissionTask.Result;
var hasEditPermission = editPermissionTask.Result;
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}, Process={Process}",
loggedInEmployee.Id, hasAdminPermission, hasEditPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission && !hasEditPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
// Validate route and model ID consistency
if (!model.Id.HasValue || id != model.Id)
{
@ -634,8 +973,6 @@ namespace Marco.Pms.Services.Controllers
using var scope = _serviceScopeFactory.CreateScope();
var _updateLogHelper = scope.ServiceProvider.GetRequiredService<UtilityMongoDBHelper>();
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Retrieve the invoice with tenant isolation
var invoice = await _context.Invoices
.FirstOrDefaultAsync(i => i.Id == id && i.TenantId == tenantId);
@ -804,12 +1141,39 @@ namespace Marco.Pms.Services.Controllers
[HttpPut("invoice/marked/completed/{invoiceId}")]
public async Task<IActionResult> MarkAsCompletedAsync(Guid invoiceId)
{
// Create a scope for permission service resolution
using var scope = _serviceScopeFactory.CreateScope();
var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
// Get the currently logged-in employee
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Log starting permission checks
_logger.LogInfo("Starting permission checks for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Capture permission results
var hasAdminPermission = await _permission.HasPermission(PermissionsMaster.CollectionAdmin, loggedInEmployee.Id);
// Log permission results for audit
_logger.LogInfo("Permission results for EmployeeId {EmployeeId}: Admin={Admin}",
loggedInEmployee.Id, hasAdminPermission);
// Check if user has any relevant permission; if none, deny access
if (!hasAdminPermission)
{
_logger.LogWarning("Permission denied for EmployeeId {EmployeeId} - No collection-related permissions found.", loggedInEmployee.Id);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access Denied",
"User does not have permission to access collection data.",
403));
}
// Optionally log success or continue with further processing here
_logger.LogInfo("Permission granted for EmployeeId {EmployeeId} - Proceeding with collection access.", loggedInEmployee.Id);
// Create a new async database context for the current request's scope.
await using var _context = await _dbContextFactory.CreateDbContextAsync();
// Retrieve the current logged in employee for audit/logging (optional use).
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// Attempt to find the invoice with tenant isolation; use AsNoTracking if no updates needed (but here we update so tracking is okay).
var invoice = await _context.Invoices
.FirstOrDefaultAsync(i => i.Id == invoiceId && i.TenantId == tenantId);