Skip to content

RE1-T117 Checkin Timer fixes, Weather Alert Fixes, MsgQ fix.#409

Merged
ucswift merged 2 commits into
masterfrom
develop
Jun 12, 2026
Merged

RE1-T117 Checkin Timer fixes, Weather Alert Fixes, MsgQ fix.#409
ucswift merged 2 commits into
masterfrom
develop

Conversation

@ucswift

@ucswift ucswift commented Jun 12, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Fixed message queue connection semaphore handling to prevent release errors
    • Improved input parsing to gracefully skip malformed numeric fields instead of rejecting requests
  • New Features

    • Enhanced weather alert notifications with decision-based scheduling and time window support
    • Strengthened check-in timer validation with improved concurrent-save handling
  • Improvements

    • Updated weather alert scheduling UI with clearer 0–24 hour range clarification
    • Added specific error messages for invalid timer and alert configurations
    • Check-in timers now default to department-level auto-enable settings

@request-info

request-info Bot commented Jun 12, 2026

Copy link
Copy Markdown

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

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ucswift, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 35 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8af309d6-3f27-4c9e-bde8-721d81ab00a7

📥 Commits

Reviewing files that changed from the base of the PR and between c746a08 and 8e8fba4.

⛔ Files ignored due to path filters (1)
  • Tests/Resgrid.Tests/Services/CheckInTimerServiceTests.cs is excluded by !**/Tests/**
📒 Files selected for processing (4)
  • Core/Resgrid.Services/CheckInTimerService.cs
  • Web/Resgrid.Web.Services/Controllers/v4/WeatherAlertsController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs
  • Web/Resgrid.Web/Areas/User/Views/WeatherAlerts/Settings.cshtml
📝 Walkthrough

Walkthrough

This PR adds stricter validation and race-condition handling to timer persistence, batch-loads state data to improve active-timer filtering, introduces schedule-based weather alert auto-notification deferral with decision-driven logic, hardens controller input validation, and corrects semaphore handling in the RabbitMQ connection pool.

Changes

Check-In Timer Robustness & Unit Type Filtering

Layer / File(s) Summary
Timer persistence with race condition and validation handling
Core/Resgrid.Services/CheckInTimerService.cs
SaveTimerConfigAsync and SaveTimerOverrideAsync validate timer values, clear UnitTypeId when not unit-type-scoped, reuse existing rows, preserve creation metadata during updates, and recover from unique-index races by re-querying the winner row and retrying. A new ValidateTimerValues helper enforces allowed target types and minimum durations.
Call type resolution and unit type mapping
Core/Resgrid.Services/CheckInTimerService.cs
ResolveAllTimersForCallAsync determines callTypeId by attempting to parse legacy numeric call.Type; when parsing fails, it queries department call types and matches by name. GetActiveTimerStatusesForCallAsync precomputes a UnitId → UnitTypeId dictionary when any resolved timer is unit-type-scoped and passes it to filtering. A new GetUnitTypeIdsByUnitIdAsync helper maps every department unit to its resolved unit type.
Active state filtering refactor with batch loading
Core/Resgrid.Services/CheckInTimerService.cs
FilterTimersByActiveStatesAsync signature now accepts unit-type mapping and was refactored to batch-load personnel action types (via department last-action-logs query) and unit states (via department latest-status query), replacing per-dispatch/per-unit calls. Timer status computation applies unit-type filtering to check-ins, allowing only matches within the configured unit type.
Per-user active call check-in lookup
Core/Resgrid.Services/CheckInTimerService.cs
Check-in summary endpoint now loads all call check-in records once and filters in-memory by personnel type and user, replacing the repository's targeted "last check-in for user on call" query.
API and Web controller exception handling and input validation
Web/Resgrid.Web.Services/Controllers/v4/CheckInTimersController.cs, Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs, Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs
CheckInTimersController and DepartmentController wrap timer save/delete calls in try/catch blocks, translating InvalidOperationException to 400 BadRequest (with message) and UnauthorizedAccessException to 404 NotFound. CheckInTimersController.PerformCheckIn validates CheckInType against defined enum values. UnitStatusController.ProcessSetUnitState defensively parses stateInput.Id using int.TryParse and skips malformed telemetry fields (latitude, longitude, accuracy, altitude, speed, heading) instead of throwing; Type remains validation-critical. Role construction skips non-numeric RoleId entries. RespondingTo destination is only set when parsed id is > 0.
Dispatch controller check-in timer auto-enable default
Web/Resgrid.Web/Areas/User/Controllers/DispatchController.cs
NewCall now defaults CheckInTimersEnabled using the department's auto-enable setting from GetCheckInTimersAutoEnableForNewCallsAsync, ensuring the check-in timers checkbox reflects server configuration when creating a new call.

Weather Alert Scheduling & Auto-Message Decisions

Layer / File(s) Summary
AutoMessageDecision enum and schedule-based decision logic
Core/Resgrid.Services/WeatherAlertService.cs
New AutoMessageDecision enum distinguishes Send, SkipPermanently, and DeferOutsideWindow. GetAutoMessageDecision helper computes department-local hour and determines eligibility: returns SkipPermanently when severity is absent or disabled; treats legacy StartHour=0/EndHour=0 as always-send; for enabled severities with configured windows, returns Send if within the window (treating end hour as exclusive), or DeferOutsideWindow if outside, including correct handling for overnight windows.
Notification flow using auto-message decision
Core/Resgrid.Services/WeatherAlertService.cs
SendPendingNotificationsAsync now uses GetAutoMessageDecision for each alert. Alerts with DeferOutsideWindow are skipped without setting NotificationSent, allowing them to be processed later when the delivery window opens. Alerts with SkipPermanently are marked as notified without sending.
API validation and schedule normalization
Web/Resgrid.Web.Services/Controllers/v4/WeatherAlertsController.cs
SaveSettings validates each AutoMessageSchedule entry: enforces valid hour ranges (start 0–23, end 0–24) and ensures enabled rows have a forward window (end > start), returning specific BadRequest messages on violation. GetWeatherAlertSettingsDataAsync normalizes legacy entries with StartHour == 0 and EndHour == 0 by setting EndHour to 24, so returned schedules use the canonical representation.
UI scheduling controls and form validation
Web/Resgrid.Web/Areas/User/Views/WeatherAlerts/Settings.cshtml
Help text now documents that delivery runs from start hour up to (but not including) end hour, with 0–24 representing full-day delivery. Per-severity input rows now allow sched-end values 0–24 (previously 0–23) with default 24. saveSettings() introduces severity-name mapping and validates each enabled severity's start/end hours, rejecting same start/end or end-before-start windows and alerting on error before persisting.

RabbitMQ Connection Semaphore Correction

Layer / File(s) Summary
Semaphore handling in VerifyAndCreateClients
Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs
Semaphore release corrected to occur exactly once after acquisition, including across all connection-host fallback (primary, host2, host3) and rethrow paths. Removes the prior pattern that could release more than once during fallback, preventing SemaphoreFullException. Comments document the single-release guarantee.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Resgrid/Core#327: Both PRs modify weather alert auto-message scheduling flow—WeatherAlertService.SendPendingNotificationsAsync decision logic, WeatherAlertsController persistence/loading, and WeatherAlerts settings UI to support per-severity schedules.
  • Resgrid/Core#328: Both PRs modify WeatherAlertService.SendPendingNotificationsAsync to change the auto-notification decision/sending flow (main PR refactors scheduling/deferral logic; retrieved PR adds excluded-event handling).
  • Resgrid/Core#408: Both PRs modify Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs in VerifyAndCreateClients connection handling, creating direct code-level overlap.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions three distinct areas of fixes (Checkin Timer, Weather Alert, MsgQ) corresponding to multiple significant changes across the changeset, covering the primary improvements made.
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 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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs (1)

31-77: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Missing double-checked locking causes race condition.

After acquiring the semaphore on line 33, the code does not re-check whether _connection is still null. If two threads both observe _connection == null on line 31 before either acquires the semaphore, the second thread will overwrite the first thread's connection and potentially leak resources.

🔒 Proposed fix: Add second null check inside semaphore
 		if (_connection == null)
 		{
 			await _semaphore.WaitAsync();
 
 			try
 			{
+				// Double-checked locking: recheck null after acquiring semaphore to prevent race
+				if (_connection == null)
+				{
 				_factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword };
 				_connection = await _factory.CreateConnectionAsync(clientName);
+				}
 			}
 			catch (Exception ex)
 			{
 				Logging.LogException(ex);
 
 				if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname2))
 				{
 					try
 					{
+						if (_connection == null)
+						{
 						_factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname2, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword };
 						_connection = await _factory.CreateConnectionAsync(clientName);
+						}
 					}
 					catch (Exception ex2)
 					{
 						Logging.LogException(ex2);
 
 						if (!String.IsNullOrWhiteSpace(ServiceBusConfig.RabbitHostname3))
 						{
 							try
 							{
+								if (_connection == null)
+								{
 								_factory = new ConnectionFactory() { HostName = ServiceBusConfig.RabbitHostname3, UserName = ServiceBusConfig.RabbitUsername, Password = ServiceBusConfig.RabbbitPassword };
 								_connection = await _factory.CreateConnectionAsync(clientName);
+								}
 							}
 							catch (Exception ex3)
 							{
 								Logging.LogException(ex3);
 								throw;
 							}
 						}
 					}
 				}
 			}
 			finally
 			{
 				// Single release: the semaphore is acquired once above, so release it exactly once here.
 				// The outer finally covers every path (primary success, host2/host3 fallback, and rethrow);
 				// a second release in the fallback branch previously threw SemaphoreFullException.
 				_semaphore.Release();
 			}
🤖 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 `@Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs` around lines 31 -
77, After acquiring _semaphore in the connection creation block, perform a
second null-check on _connection and skip creating/overwriting it if another
thread already set it; specifically, in the try block after await
_semaphore.WaitAsync(), add if (_connection == null) { ...existing
create/fallback logic... } so ConnectionFactory/await
_factory.CreateConnectionAsync(clientName) only run when still necessary,
preserving the single _semaphore.Release() in the finally and preventing races
that overwrite/ leak connections.
🧹 Nitpick comments (3)
Core/Resgrid.Services/WeatherAlertService.cs (1)

704-708: 💤 Low value

Overnight window branch may be unreachable given API validation.

The API validation in WeatherAlertsController.SaveSettings rejects schedules where EndHour <= StartHour for enabled entries, which prevents overnight windows (e.g., StartHour=22, EndHour=6) from being configured. This makes the overnight branch at lines 704-708 unreachable for newly saved schedules.

If overnight windows are intentionally unsupported, consider removing this branch to avoid confusion. If they should be supported in the future, the API validation at WeatherAlertsController.cs:380-382 would need to be updated to allow StartHour > EndHour for overnight scenarios.

As-is, this code is defensive and handles pre-existing data gracefully, so not blocking.

🤖 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/WeatherAlertService.cs` around lines 704 - 708, The
overnight-window branch in WeatherAlertService (the inWindow calculation that
handles StartHour > EndHour) is effectively unreachable because
WeatherAlertsController.SaveSettings currently rejects enabled schedules with
EndHour <= StartHour; either remove the overnight branch to clean up dead code
(replace the conditional with the straightforward inWindow = currentHour >=
entry.StartHour && currentHour < entry.EndHour logic in the method containing
the inWindow calculation) or, if overnight schedules should be supported, update
WeatherAlertsController.SaveSettings validation (the checks around lines
referenced in that method) to allow StartHour > EndHour for enabled entries and
add/update unit tests to cover overnight scenarios.
Core/Resgrid.Services/CheckInTimerService.cs (2)

145-150: ⚖️ Poor tradeoff

Consider a direct query instead of loading all overrides.

The method loads all department overrides via GetByDepartmentIdAsync and filters in-memory twice (lines 145-150 for initial check, lines 193-198 for race recovery). For departments with many overrides, a direct repository query like GetByDepartmentAndTargetAsync (as used for configs at line 55) would be more efficient.

If adding such a method is non-trivial, this is acceptable for now given typical override counts are likely low.

Also applies to: 193-198

🤖 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/CheckInTimerService.cs` around lines 145 - 150, Replace
the in-memory filtering of department overrides with a direct repository query:
instead of calling GetByDepartmentIdAsync and then using
departmentOverrides?.FirstOrDefault(...) to produce existingForTarget, add/use a
repository method like GetByDepartmentAndTargetAsync (same pattern used for
configs) that accepts DepartmentId, CallTypeId, CallPriority, TimerTargetType
and UnitTypeId and returns the matching override; update both the initial check
(where existingForTarget is computed) and the race-recovery check (the later
block that repeats the filtering) to call this new method so we avoid loading
all overrides into memory.

91-109: 💤 Low value

Add logging when recovering from insert race condition.

The race condition handling logic is correct, but when the exception path is taken, there's no logging to aid debugging. Per coding guidelines, use Resgrid.Framework.Logging to capture exceptions.

 			catch (Exception) when (isInsert)
 			{
+				Resgrid.Framework.Logging.LogInfo($"CheckInTimerConfig insert race for DepartmentId={config.DepartmentId}, TargetType={config.TimerTargetType}, UnitTypeId={config.UnitTypeId}; adopting winner row");
 				// Two concurrent saves can both pass the lookup above and race the unique
 				// target index; the loser lands here — adopt the winner's row and update it
🤖 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/CheckInTimerService.cs` around lines 91 - 109, The
catch block in CheckInTimerService that handles the insert race (the catch
(Exception) when (isInsert) around the _configRepository.SaveOrUpdateAsync call)
should log the caught exception and context before attempting recovery; change
the handler to catch (Exception ex) when (isInsert) and use
Resgrid.Framework.Logging to write an error including the exception and
identifying details (config.DepartmentId, config.TimerTargetType,
config.UnitTypeId and that we are recovering by calling
GetByDepartmentAndTargetAsync and re-saving via SaveOrUpdateAsync) so failures
and race recoveries are visible in logs, then continue with the existing
winner-adoption logic.

Source: Coding guidelines

🤖 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/CheckInTimerService.cs`:
- Around line 547-557: The ValidateTimerValues method currently checks enums and
minimums but not that the warning window is shorter than the total duration;
update ValidateTimerValues (method name) to validate that
warningThresholdMinutes < durationMinutes and throw an InvalidOperationException
(same exception type used) with a clear message like "Check-in timer warning
threshold must be less than the duration." so misconfigurations where
warningThresholdMinutes >= durationMinutes are rejected.

In `@Web/Resgrid.Web.Services/Controllers/v4/WeatherAlertsController.cs`:
- Around line 374-386: The SaveSettings validation currently rejects overnight
schedules by returning BadRequest when entry.EndHour <= entry.StartHour; update
WeatherAlertsController.SaveSettings to allow overnight windows (where EndHour <
StartHour) but still reject empty windows (EndHour == StartHour) for enabled
entries: keep the existing range checks for entry.StartHour (0-23) and
entry.EndHour (0-24), and change the enabled-window check to only return
BadRequest when entry.Enabled && entry.EndHour == entry.StartHour. Reference
input.AutoMessageSchedule and the entry.StartHour/entry.EndHour/entry.Enabled
fields when making the change.

In `@Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs`:
- Around line 2072-2079: The DepartmentController method that calls
_checkInTimerService.SaveTimerOverrideAsync currently only catches
InvalidOperationException; to match CheckInTimersController.SaveTimerOverride
add an additional catch for UnauthorizedAccessException and return
Unauthorized() (or BadRequest with the exception message if project convention
differs) so unauthorized errors are handled consistently—update the try/catch
around the call to _checkInTimerService.SaveTimerOverrideAsync in the
DepartmentController method to include a catch (UnauthorizedAccessException ex)
and map it to the appropriate HTTP response.
- Around line 2016-2023: The DepartmentController method calling
_checkInTimerService.SaveTimerConfigAsync currently only catches
InvalidOperationException and returns BadRequest; add a catch for
UnauthorizedAccessException (same handling as in
CheckInTimersController.SaveTimerConfig) and return NotFound() to handle
service-layer authorization failures (e.g., when configId belongs to another
department) and avoid returning a 500.

In `@Web/Resgrid.Web/Areas/User/Views/WeatherAlerts/Settings.cshtml`:
- Line 69: The help text in Settings.cshtml incorrectly says "the end hour must
be greater than the start hour"; update that copy to reflect that overnight
windows are supported by WeatherAlertService.GetAutoMessageDecision (i.e.,
delivery runs from start hour up to but not including end hour, and if StartHour
> EndHour it wraps overnight — e.g., 18–6 for 6pm–6am; use 0–24 for always).
Change the sentence to remove the restriction and add a brief example mentioning
the overnight wrap to match the service logic.

---

Outside diff comments:
In `@Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs`:
- Around line 31-77: After acquiring _semaphore in the connection creation
block, perform a second null-check on _connection and skip creating/overwriting
it if another thread already set it; specifically, in the try block after await
_semaphore.WaitAsync(), add if (_connection == null) { ...existing
create/fallback logic... } so ConnectionFactory/await
_factory.CreateConnectionAsync(clientName) only run when still necessary,
preserving the single _semaphore.Release() in the finally and preventing races
that overwrite/ leak connections.

---

Nitpick comments:
In `@Core/Resgrid.Services/CheckInTimerService.cs`:
- Around line 145-150: Replace the in-memory filtering of department overrides
with a direct repository query: instead of calling GetByDepartmentIdAsync and
then using departmentOverrides?.FirstOrDefault(...) to produce
existingForTarget, add/use a repository method like
GetByDepartmentAndTargetAsync (same pattern used for configs) that accepts
DepartmentId, CallTypeId, CallPriority, TimerTargetType and UnitTypeId and
returns the matching override; update both the initial check (where
existingForTarget is computed) and the race-recovery check (the later block that
repeats the filtering) to call this new method so we avoid loading all overrides
into memory.
- Around line 91-109: The catch block in CheckInTimerService that handles the
insert race (the catch (Exception) when (isInsert) around the
_configRepository.SaveOrUpdateAsync call) should log the caught exception and
context before attempting recovery; change the handler to catch (Exception ex)
when (isInsert) and use Resgrid.Framework.Logging to write an error including
the exception and identifying details (config.DepartmentId,
config.TimerTargetType, config.UnitTypeId and that we are recovering by calling
GetByDepartmentAndTargetAsync and re-saving via SaveOrUpdateAsync) so failures
and race recoveries are visible in logs, then continue with the existing
winner-adoption logic.

In `@Core/Resgrid.Services/WeatherAlertService.cs`:
- Around line 704-708: The overnight-window branch in WeatherAlertService (the
inWindow calculation that handles StartHour > EndHour) is effectively
unreachable because WeatherAlertsController.SaveSettings currently rejects
enabled schedules with EndHour <= StartHour; either remove the overnight branch
to clean up dead code (replace the conditional with the straightforward inWindow
= currentHour >= entry.StartHour && currentHour < entry.EndHour logic in the
method containing the inWindow calculation) or, if overnight schedules should be
supported, update WeatherAlertsController.SaveSettings validation (the checks
around lines referenced in that method) to allow StartHour > EndHour for enabled
entries and add/update unit tests to cover overnight scenarios.
🪄 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: 341c02bb-c150-46db-a118-0215be107614

📥 Commits

Reviewing files that changed from the base of the PR and between 2b8c5f9 and c746a08.

⛔ Files ignored due to path filters (1)
  • Tests/Resgrid.Tests/Services/CheckInTimerServiceTests.cs is excluded by !**/Tests/**
📒 Files selected for processing (9)
  • Core/Resgrid.Services/CheckInTimerService.cs
  • Core/Resgrid.Services/WeatherAlertService.cs
  • Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs
  • Web/Resgrid.Web.Services/Controllers/v4/CheckInTimersController.cs
  • Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs
  • Web/Resgrid.Web.Services/Controllers/v4/WeatherAlertsController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs
  • Web/Resgrid.Web/Areas/User/Controllers/DispatchController.cs
  • Web/Resgrid.Web/Areas/User/Views/WeatherAlerts/Settings.cshtml

Comment thread Core/Resgrid.Services/CheckInTimerService.cs
Comment thread Web/Resgrid.Web.Services/Controllers/v4/WeatherAlertsController.cs
Comment thread Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs
Comment thread Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs
Comment thread Web/Resgrid.Web/Areas/User/Views/WeatherAlerts/Settings.cshtml Outdated

// Validate the unit id up front: this runs before the try/catch and ModelState check below, so a
// non-numeric id would otherwise throw an unhandled FormatException (HTTP 500) instead of a 400.
if (!int.TryParse(stateInput.Id, out var unitId))
@ucswift

ucswift commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Approve

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit 0221b30 into master Jun 12, 2026
18 of 19 checks passed
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.

2 participants