Skip to content

Develop#395

Open
ucswift wants to merge 2 commits into
masterfrom
develop
Open

Develop#395
ucswift wants to merge 2 commits into
masterfrom
develop

Conversation

@ucswift
Copy link
Copy Markdown
Member

@ucswift ucswift commented Jun 3, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Inventory by Unit" view to filter and display inventory transactions organized by unit.
    • Enhanced audit log retrieval with pagination and date-range filtering capabilities.
    • Added system audit history queries with improved date-bounded filtering and paging.
  • Improvements

    • Expanded localization support across inventory features for better multi-language support.
    • Improved IP address detection for audit logging accuracy.
  • Refactor

    • Streamlined internal audit event handling architecture.

@request-info
Copy link
Copy Markdown

request-info Bot commented Jun 3, 2026

Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a paged audit query layer to replace event-based enqueueing, adds an inventory-by-unit feature with unit population, hardens audit log persistence, and updates IP resolution and datetime handling in shift calendar generation.

Changes

Audit Query Layer Infrastructure

Layer / File(s) Summary
Audit query repository interface contracts
Core/Resgrid.Model/Repositories/IAuditLogsRepository.cs, IPaymentProviderEventsRepository.cs, ISystemAuditsRepository.cs, Core/Resgrid.Model/Services/IAuditService.cs
IAuditLogsRepository, ISystemAuditsRepository, and IPaymentProviderEventsRepository declare paged async query methods filtered by department/user/customer ID with optional date ranges and type filters; IAuditService mirrors the audit method signature for service layer consistency.
SQL query builders for paged audit/payment queries
Repositories/.../Queries/AuditLogs/SelectAuditLogs*.cs, SystemAudits/SelectSystemAudits*.cs, Payments/SelectPaymentProviderEventsByCustomerIdQuery.cs
Five new ISelectQuery implementations generate database-specific paged SQL: two variants for audit logs (with/without log-type filter), two for system audits (user-filtered and department-filtered), and one for payment events by customer, each handling PostgreSQL and SQL Server dialects.
Repository implementations of paged queries
Repositories/.../AuditLogsRepository.cs, PaymentProviderEventsRepository.cs, SystemAuditRepository.cs
AuditLogsRepository, PaymentProviderEventsRepository, and SystemAuditRepository implement the async paged methods using Dapper QueryAsync with dynamic parameters, conditional query selection, transaction management, and connection lifecycle handling.
Audit service interface and implementation
Core/Resgrid.Model/Services/IAuditService.cs, Core/Resgrid.Services/AuditService.cs
IAuditService declares and AuditService implements GetAuditLogsForDepartmentPagedAsync, wiring repository paged queries to the service API.
Audit queue processing fallback message generation
Workers/Resgrid.Workers.Framework/Logic/AuditQueueLogic.cs
ProcessAuditQueueItem now guarantees audit log persistence for unknown event types by generating a human-readable fallback message via IAuditService.GetAuditLogTypeString and unconditionally persisting the log.

Inventory By-Unit Feature

Layer / File(s) Summary
InventoryService unit population
Core/Resgrid.Services/InventoryService.cs
InventoryService now depends on IUnitsService and populates inventory.Unit for both single-item and batch-fetched collections, preloading units per department to avoid repeated lookups.
InventoryController localization and by-unit actions
Web/Resgrid.Web/Areas/User/Controllers/InventoryController.cs
InventoryController injects two IStringLocalizer instances for localized fallback text in adjustment validation errors and missing field displays; adds ByUnit view action and GetInventoryByUnitList JSON endpoint returning unit-filtered inventory with localized field fallbacks.
By-unit view and client-side implementation
Web/Resgrid.Web/Areas/User/Views/Inventory/ByUnit.cshtml, resgrid.inventory.byunit.js, Index.cshtml, History.cshtml, _references.js, resgrid.inventory.history.js
New ByUnit.cshtml view with breadcrumb and table placeholder; new resgrid.inventory.byunit.js DataTable module with server-side pagination and unit sorting; updated Index.cshtml with by-unit navigation button, History.cshtml with unit column, and script references.

Infrastructure Updates

Layer / File(s) Summary
IP address resolution via helper
Web/Resgrid.Web.Services/Controllers/v4/ContactVerificationController.cs, Web/Resgrid.Web/Areas/User/Controllers/HomeController.cs
ContactVerificationController and HomeController ConfirmVerificationCode methods replace direct HttpContext.Connection.RemoteIpAddress with IpAddressHelper.GetRequestIP(Request, true) for proxy-aware IP detection in audit logging.
Shift calendar datetime kind normalization
Web/Resgrid.Web/Areas/User/Controllers/ShiftsController.cs
GetShiftCalendarItems and GetShiftCalendarItemsForShift construct calendar item Start/End datetimes with DateTimeKind.Unspecified instead of Local for all shift time values and fallback boundaries.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • Resgrid/Core#294: Extends AuditQueueLogic.ProcessAuditQueueItem with additional audit case handling and custom field audit logic alongside the fallback message generation in this PR.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The pull request title 'Develop' is vague and does not meaningfully describe the changeset, which includes audit service refactoring, new paged query methods, inventory enhancements, and UI improvements. Replace 'Develop' with a specific, descriptive title summarizing the primary changes, such as 'Refactor audit services and add paged query methods' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
Web/Resgrid.Web/Areas/User/Controllers/InventoryController.cs (1)

300-342: ⚡ Quick win

Consider extracting common inventory JSON population logic.

GetInventoryByUnitList (lines 300-342) duplicates the JSON population loop from GetInventoryList (lines 252-292). Both methods fetch department/items/names, loop over inventories, and populate InventoryJson with identical null-check fallbacks. Only the filtering (line 310) and ordering (lines 311-312) differ. Extracting a helper method (e.g., MapInventoryToJson(Inventory item, Department department, IEnumerable<PersonName> names)) would reduce duplication and improve maintainability.

♻️ Example refactor with helper method
+private InventoryJson MapInventoryToJson(Inventory item, Department department, IEnumerable<PersonName> names)
+{
+  var inventory = new InventoryJson
+  {
+    InventoryId = item.InventoryId,
+    Type = item.Type.Type,
+    Amount = item.Amount,
+    Batch = item.Batch,
+    Timestamp = item.TimeStamp.FormatForDepartment(department),
+    Unit = item.Unit != null ? item.Unit.Name : _localizer["NoUnit"],
+    Group = item.Group != null ? item.Group.Name : _localizer["NoGroup"]
+  };
+
+  var name = names.FirstOrDefault(x => x.UserId == item.AddedByUserId);
+  inventory.UserName = name != null ? name.Name : _commonLocalizer["Unknown"];
+
+  return inventory;
+}

 public async Task<IActionResult> GetInventoryList()
 {
   // ...
   foreach (var item in items)
   {
-    var inventory = new InventoryJson();
-    inventory.InventoryId = item.InventoryId;
-    // ... (lines 264-286)
+    inventoryJson.Add(MapInventoryToJson(item, department, names));
   }
   // ...
 }

 public async Task<IActionResult> GetInventoryByUnitList()
 {
   // ...
   foreach (var item in items.Where(...).OrderBy(...).ThenBy(...))
   {
-    var inventory = new InventoryJson();
-    inventory.InventoryId = item.InventoryId;
-    // ... (lines 314-336)
+    inventoryJson.Add(MapInventoryToJson(item, department, names));
   }
   // ...
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web/Areas/User/Controllers/InventoryController.cs` around lines
300 - 342, GetInventoryByUnitList duplicates the InventoryJson population loop
from GetInventoryList; extract a private helper like
MapInventoryToJson(Inventory item, Department department,
IEnumerable<PersonName> names) that builds and returns an InventoryJson
(handling null checks for item.Unit, item.Group, lookup of AddedByUserId and
timestamp formatting), then replace the loops in both GetInventoryByUnitList and
GetInventoryList to call this helper after applying their specific
filtering/ordering so the mapping logic is centralized and maintainability is
improved.
Core/Resgrid.Services/InventoryService.cs (1)

69-84: ⚡ Quick win

Inconsistent prefetch pattern for groups.

The method now prefetches units once (line 73) and uses them in the loop (line 80), which avoids N+1 queries. However, groups are still fetched individually inside the loop (line 77), creating N sequential async calls. Consider prefetching groups using GetAllGroupsForDepartmentAsync (or equivalent) and performing in-memory lookups, consistent with the new unit-loading pattern.

♻️ Proposed refactor to prefetch groups
 public async Task<List<Inventory>> GetAllTransactionsForDepartmentAsync(int departmentId)
 {
   var inventories = await _inventoryRepository.GetAllInventoriesByDepartmentIdAsync(departmentId);
 
   var units = await _unitsService.GetUnitsForDepartmentAsync(departmentId);
+  var groups = await _departmentGroupsService.GetAllGroupsForDepartmentAsync(departmentId);
 
   foreach (var inventory in inventories)
   {
-    inventory.Group = await _departmentGroupsService.GetGroupByIdAsync(inventory.GroupId);
+    inventory.Group = groups?.FirstOrDefault(x => x.DepartmentGroupId == inventory.GroupId);
 
     if (inventory.UnitId.HasValue && inventory.UnitId.Value > 0)
       inventory.Unit = units?.FirstOrDefault(x => x.UnitId == inventory.UnitId.Value);
   }
 
   return inventories.ToList();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Resgrid.Services/InventoryService.cs` around lines 69 - 84,
GetAllTransactionsForDepartmentAsync currently causes N+1 calls by calling
_departmentGroupsService.GetGroupByIdAsync inside the loop; instead call the
bulk loader (e.g. _departmentGroupsService.GetAllGroupsForDepartmentAsync or
equivalent) once alongside _unitsService.GetUnitsForDepartmentAsync, build an
in-memory lookup (dictionary keyed by GroupId), then in the foreach assign
inventory.Group = groupLookup[inventory.GroupId] (or TryGetValue) and remove the
per-iteration GetGroupByIdAsync call so groups are pre-fetched similarly to
units.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Core/Resgrid.Services/AuditService.cs`:
- Around line 40-44: GetAuditLogsForDepartmentPagedAsync should validate/clamp
the incoming paging parameters before calling the repository: ensure page is at
least 1 (if <=0 set to 1) and ensure pageSize is a positive value (e.g., set to
a min of 1 and optionally clamp to a sensible max like 1000) to avoid generating
negative OFFSET or invalid LIMIT/FETCH; update
GetAuditLogsForDepartmentPagedAsync to compute safePage and safePageSize and
pass those to
_auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId,
startDate, endDate, (int?)logType, safePage, safePageSize).

In `@Repositories/Resgrid.Repositories.DataRepository/AuditLogsRepository.cs`:
- Around line 42-43: The offset computation can go negative when page <= 0;
update validation to clamp/validate page and pageSize at the service entry
(AuditService.GetAuditLogsForDepartmentPagedAsync) so page >= 1 and pageSize >
0, or alternatively ensure the repository computes Offset as Math.Max(0, (page -
1) * pageSize) before adding dynamicParameters ("Offset") in AuditLogsRepository
(and mirror the fix in SystemAuditsRepository.GetByUserIdPagedAsync and
GetByDepartmentIdPagedAsync) so SQL OFFSET never receives a negative value.

In `@Web/Resgrid.Web.Services/Controllers/v4/ContactVerificationController.cs`:
- Around line 91-93: The call to IpAddressHelper.GetRequestIP(Request, true) in
the ContactVerificationController action can throw and crash the request; wrap
the call in a safe guard (try/catch) around
IpAddressHelper.GetRequestIP(Request, true), handle any exception by logging a
warning and falling back to a safe default (e.g., null or empty string) so
verification proceeds even if IP resolution fails, and ensure any downstream use
of the ipAddress variable (in this controller action) tolerates the fallback
value.

---

Nitpick comments:
In `@Core/Resgrid.Services/InventoryService.cs`:
- Around line 69-84: GetAllTransactionsForDepartmentAsync currently causes N+1
calls by calling _departmentGroupsService.GetGroupByIdAsync inside the loop;
instead call the bulk loader (e.g.
_departmentGroupsService.GetAllGroupsForDepartmentAsync or equivalent) once
alongside _unitsService.GetUnitsForDepartmentAsync, build an in-memory lookup
(dictionary keyed by GroupId), then in the foreach assign inventory.Group =
groupLookup[inventory.GroupId] (or TryGetValue) and remove the per-iteration
GetGroupByIdAsync call so groups are pre-fetched similarly to units.

In `@Web/Resgrid.Web/Areas/User/Controllers/InventoryController.cs`:
- Around line 300-342: GetInventoryByUnitList duplicates the InventoryJson
population loop from GetInventoryList; extract a private helper like
MapInventoryToJson(Inventory item, Department department,
IEnumerable<PersonName> names) that builds and returns an InventoryJson
(handling null checks for item.Unit, item.Group, lookup of AddedByUserId and
timestamp formatting), then replace the loops in both GetInventoryByUnitList and
GetInventoryList to call this helper after applying their specific
filtering/ordering so the mapping logic is centralized and maintainability is
improved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68672df5-550b-4122-ab92-56efac642120

📥 Commits

Reviewing files that changed from the base of the PR and between 443333f and f844247.

⛔ Files ignored due to path filters (9)
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.ar.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.de.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.en.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.es.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.fr.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.it.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.pl.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.sv.resx is excluded by !**/*.resx
  • Core/Resgrid.Localization/Areas/User/Inventory/Inventory.uk.resx is excluded by !**/*.resx
📒 Files selected for processing (29)
  • Core/Resgrid.Model/Providers/IAuditEventProvider.cs
  • Core/Resgrid.Model/Repositories/IAuditLogsRepository.cs
  • Core/Resgrid.Model/Repositories/IPaymentProviderEventsRepository.cs
  • Core/Resgrid.Model/Repositories/ISystemAuditsRepository.cs
  • Core/Resgrid.Model/Services/IAuditEventService.cs
  • Core/Resgrid.Model/Services/IAuditService.cs
  • Core/Resgrid.Services/AuditEventService.cs
  • Core/Resgrid.Services/AuditService.cs
  • Core/Resgrid.Services/InventoryService.cs
  • Providers/Resgrid.Providers.Bus/AuditEventProvider.cs
  • Repositories/Resgrid.Repositories.DataRepository/AuditLogsRepository.cs
  • Repositories/Resgrid.Repositories.DataRepository/PaymentProviderEventsRepository.cs
  • Repositories/Resgrid.Repositories.DataRepository/Queries/AuditLogs/SelectAuditLogsForDepartmentByTypePagedQuery.cs
  • Repositories/Resgrid.Repositories.DataRepository/Queries/AuditLogs/SelectAuditLogsForDepartmentPagedQuery.cs
  • Repositories/Resgrid.Repositories.DataRepository/Queries/Payments/SelectPaymentProviderEventsByCustomerIdQuery.cs
  • Repositories/Resgrid.Repositories.DataRepository/Queries/SystemAudits/SelectSystemAuditsByDepartmentIdPagedQuery.cs
  • Repositories/Resgrid.Repositories.DataRepository/Queries/SystemAudits/SelectSystemAuditsByUserIdPagedQuery.cs
  • Repositories/Resgrid.Repositories.DataRepository/SystemAuditRepository.cs
  • Web/Resgrid.Web.Services/Controllers/v4/ContactVerificationController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/HomeController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/InventoryController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/ShiftsController.cs
  • Web/Resgrid.Web/Areas/User/Views/Inventory/ByUnit.cshtml
  • Web/Resgrid.Web/Areas/User/Views/Inventory/History.cshtml
  • Web/Resgrid.Web/Areas/User/Views/Inventory/Index.cshtml
  • Web/Resgrid.Web/wwwroot/_references.js
  • Web/Resgrid.Web/wwwroot/js/app/internal/inventory/resgrid.inventory.byunit.js
  • Web/Resgrid.Web/wwwroot/js/app/internal/inventory/resgrid.inventory.history.js
  • Workers/Resgrid.Workers.Framework/Logic/AuditQueueLogic.cs
💤 Files with no reviewable changes (4)
  • Core/Resgrid.Model/Services/IAuditEventService.cs
  • Core/Resgrid.Model/Providers/IAuditEventProvider.cs
  • Core/Resgrid.Services/AuditEventService.cs
  • Providers/Resgrid.Providers.Bus/AuditEventProvider.cs

Comment on lines +40 to +44
public async Task<List<AuditLog>> GetAuditLogsForDepartmentPagedAsync(int departmentId, DateTime startDate, DateTime endDate, AuditLogTypes? logType, int page, int pageSize)
{
var logs = await _auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId, startDate, endDate, (int?)logType, page, pageSize);
return logs.ToList();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate/clamp page and pageSize before delegating.

This is the single entry point feeding the paged repository methods. Without a guard, page <= 0 propagates a negative Offset to the SQL builders and fails at execution on both SQL Server and PostgreSQL. Likewise a non-positive pageSize produces an invalid LIMIT/FETCH NEXT.

🛡️ Suggested guard
 public async Task<List<AuditLog>> GetAuditLogsForDepartmentPagedAsync(int departmentId, DateTime startDate, DateTime endDate, AuditLogTypes? logType, int page, int pageSize)
 {
+	if (page < 1) page = 1;
+	if (pageSize < 1) pageSize = 1;
 	var logs = await _auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId, startDate, endDate, (int?)logType, page, pageSize);
 	return logs.ToList();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Resgrid.Services/AuditService.cs` around lines 40 - 44,
GetAuditLogsForDepartmentPagedAsync should validate/clamp the incoming paging
parameters before calling the repository: ensure page is at least 1 (if <=0 set
to 1) and ensure pageSize is a positive value (e.g., set to a min of 1 and
optionally clamp to a sensible max like 1000) to avoid generating negative
OFFSET or invalid LIMIT/FETCH; update GetAuditLogsForDepartmentPagedAsync to
compute safePage and safePageSize and pass those to
_auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId,
startDate, endDate, (int?)logType, safePage, safePageSize).

Comment on lines +42 to +43
dynamicParameters.Add("Offset", (page - 1) * pageSize);
dynamicParameters.Add("PageSize", pageSize);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against negative Offset for non-positive page.

(page - 1) * pageSize yields a negative offset when page <= 0, which throws on both SQL Server (OFFSET ... ROWS) and PostgreSQL (OFFSET). The same computation is repeated in SystemAuditsRepository.GetByUserIdPagedAsync/GetByDepartmentIdPagedAsync. Best handled once at the service entry point (AuditService.GetAuditLogsForDepartmentPagedAsync) by clamping/validating page and pageSize; flagging the root computation here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Repositories/Resgrid.Repositories.DataRepository/AuditLogsRepository.cs`
around lines 42 - 43, The offset computation can go negative when page <= 0;
update validation to clamp/validate page and pageSize at the service entry
(AuditService.GetAuditLogsForDepartmentPagedAsync) so page >= 1 and pageSize >
0, or alternatively ensure the repository computes Offset as Math.Max(0, (page -
1) * pageSize) before adding dynamicParameters ("Offset") in AuditLogsRepository
(and mirror the fix in SystemAuditsRepository.GetByUserIdPagedAsync and
GetByDepartmentIdPagedAsync) so SQL OFFSET never receives a negative value.

Comment on lines +91 to +93
// Use the X-Forwarded-For aware helper so the audit log records the real client IP
// rather than the reverse-proxy / load-balancer address.
string ipAddress = IpAddressHelper.GetRequestIP(Request, true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Potential 500 from unguarded IP resolution

IpAddressHelper.GetRequestIP(Request, true) can throw when request metadata is missing, and this action does not handle that path. A failed IP lookup should not fail code confirmation.

Suggested hardening
-			string ipAddress = IpAddressHelper.GetRequestIP(Request, true);
+			string ipAddress;
+			try
+			{
+				ipAddress = IpAddressHelper.GetRequestIP(Request, true);
+			}
+			catch
+			{
+				ipAddress = HttpContext?.Connection?.RemoteIpAddress?.ToString();
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Use the X-Forwarded-For aware helper so the audit log records the real client IP
// rather than the reverse-proxy / load-balancer address.
string ipAddress = IpAddressHelper.GetRequestIP(Request, true);
// Use the X-Forwarded-For aware helper so the audit log records the real client IP
// rather than the reverse-proxy / load-balancer address.
string ipAddress;
try
{
ipAddress = IpAddressHelper.GetRequestIP(Request, true);
}
catch (Exception ex)
{
Logging.LogException(ex, "Failed to resolve request IP, falling back to RemoteIpAddress");
ipAddress = HttpContext?.Connection?.RemoteIpAddress?.ToString();
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Web/Resgrid.Web.Services/Controllers/v4/ContactVerificationController.cs`
around lines 91 - 93, The call to IpAddressHelper.GetRequestIP(Request, true) in
the ContactVerificationController action can throw and crash the request; wrap
the call in a safe guard (try/catch) around
IpAddressHelper.GetRequestIP(Request, true), handle any exception by logging a
warning and falling back to a safe default (e.g., null or empty string) so
verification proceeds even if IP resolution fails, and ensure any downstream use
of the ipAddress variable (in this controller action) tolerates the fallback
value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant