Skip to content

Commit f933b5f

Browse files
committed
RE1-T112 Bug fixes
1 parent 2d36c91 commit f933b5f

10 files changed

Lines changed: 74 additions & 84 deletions

File tree

Core/Resgrid.Services/WeatherAlertService.cs

Lines changed: 32 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ public async Task ProcessWeatherAlertSourceAsync(Guid sourceId, CancellationToke
195195
var existing = await _weatherAlertRepository.GetByExternalIdAndSourceIdAsync(
196196
alert.ExternalId, source.WeatherAlertSourceId);
197197

198+
TruncateAlertFields(alert);
199+
198200
if (existing == null)
199201
{
200202
// New alert
@@ -525,78 +527,31 @@ private static string FormatAlertMessageBody(WeatherAlert alert, Department depa
525527
{
526528
var sb = new System.Text.StringBuilder();
527529

528-
// Header
529-
sb.AppendLine($"=== WEATHER ALERT: {alert.Event?.ToUpper()} ===");
530-
sb.AppendLine();
530+
sb.AppendLine($"WEATHER ALERT: {alert.Event?.ToUpper()}");
531+
sb.AppendLine($"Severity: {SeverityNames[Math.Min(alert.Severity, 4)]}");
531532

532-
// Headline
533-
if (!string.IsNullOrEmpty(alert.Headline))
533+
if (alert.ExpiresUtc.HasValue)
534534
{
535-
sb.AppendLine(alert.Headline);
536-
sb.AppendLine();
535+
if (department != null)
536+
sb.AppendLine($"Expires: {alert.ExpiresUtc.Value.TimeConverter(department):MM/dd/yyyy h:mm tt}");
537+
else
538+
sb.AppendLine($"Expires: {alert.ExpiresUtc.Value:yyyy-MM-dd HH:mm} UTC");
537539
}
538540

539-
// Classification grid
540-
sb.AppendLine("--- Alert Details ---");
541-
sb.AppendLine($"Severity: {SeverityNames[Math.Min(alert.Severity, 4)]}");
542-
sb.AppendLine($"Urgency: {UrgencyNames[Math.Min(alert.Urgency, 4)]}");
543-
sb.AppendLine($"Certainty: {CertaintyNames[Math.Min(alert.Certainty, 4)]}");
544-
sb.AppendLine($"Category: {CategoryNames[Math.Min(alert.AlertCategory, 4)]}");
545541
sb.AppendLine();
546542

547-
// Timing
548-
sb.AppendLine("--- Timing ---");
549-
if (department != null)
550-
{
551-
sb.AppendLine($"Effective: {alert.EffectiveUtc.TimeConverter(department):MM/dd/yyyy h:mm tt}");
552-
if (alert.OnsetUtc.HasValue)
553-
sb.AppendLine($"Onset: {alert.OnsetUtc.Value.TimeConverter(department):MM/dd/yyyy h:mm tt}");
554-
if (alert.ExpiresUtc.HasValue)
555-
sb.AppendLine($"Expires: {alert.ExpiresUtc.Value.TimeConverter(department):MM/dd/yyyy h:mm tt}");
556-
}
557-
else
558-
{
559-
sb.AppendLine($"Effective: {alert.EffectiveUtc:yyyy-MM-dd HH:mm} UTC");
560-
if (alert.OnsetUtc.HasValue)
561-
sb.AppendLine($"Onset: {alert.OnsetUtc.Value:yyyy-MM-dd HH:mm} UTC");
562-
if (alert.ExpiresUtc.HasValue)
563-
sb.AppendLine($"Expires: {alert.ExpiresUtc.Value:yyyy-MM-dd HH:mm} UTC");
564-
}
565-
sb.AppendLine();
566-
567-
// Affected area
568-
if (!string.IsNullOrEmpty(alert.AreaDescription))
569-
{
570-
sb.AppendLine("--- Affected Area ---");
571-
sb.AppendLine(alert.AreaDescription);
572-
sb.AppendLine();
573-
}
574-
575-
// Description
576-
if (!string.IsNullOrEmpty(alert.Description))
577-
{
578-
sb.AppendLine("--- Description ---");
579-
sb.AppendLine(alert.Description);
580-
sb.AppendLine();
581-
}
543+
if (!string.IsNullOrEmpty(alert.Headline))
544+
sb.AppendLine(alert.Headline);
582545

583-
// Instructions (critical for responders)
584546
if (!string.IsNullOrEmpty(alert.Instruction))
585547
{
586-
sb.AppendLine("--- INSTRUCTIONS ---");
587-
sb.AppendLine(alert.Instruction);
588548
sb.AppendLine();
549+
sb.AppendLine(alert.Instruction);
589550
}
590551

591-
// Source info
592-
if (!string.IsNullOrEmpty(alert.Sender))
593-
sb.AppendLine($"Source: {alert.Sender}");
594-
595-
sb.AppendLine($"Alert ID: {alert.ExternalId}");
596552
sb.AppendLine();
597-
sb.AppendLine("This is an automated weather alert from the Resgrid Weather Alert System.");
553+
sb.AppendLine("View active weather alerts for full details.");
598554

599-
// Respect the 4000 char body limit
600555
var body = sb.ToString();
601556
if (body.Length > 3950)
602557
body = body.Substring(0, 3947) + "...";
@@ -619,5 +574,24 @@ private static double CalculateDistanceMiles(double lat1, double lng1, double la
619574
private static double ToRadians(double degrees) => degrees * Math.PI / 180;
620575

621576
#endregion
577+
578+
private static void TruncateAlertFields(WeatherAlert alert)
579+
{
580+
alert.ExternalId = Truncate(alert.ExternalId, 500);
581+
alert.Sender = Truncate(alert.Sender, 500);
582+
alert.Event = Truncate(alert.Event, 500);
583+
alert.Headline = Truncate(alert.Headline, 500);
584+
alert.AreaDescription = Truncate(alert.AreaDescription, 500);
585+
alert.CenterGeoLocation = Truncate(alert.CenterGeoLocation, 100);
586+
alert.ReferencesExternalId = Truncate(alert.ReferencesExternalId, 500);
587+
}
588+
589+
private static string Truncate(string value, int maxLength)
590+
{
591+
if (string.IsNullOrEmpty(value) || value.Length <= maxLength)
592+
return value;
593+
594+
return value.Substring(0, maxLength);
595+
}
622596
}
623597
}

Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ internal class RabbitConnection
1313
private static ConnectionFactory _factory { get; set; }
1414
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
1515

16+
/// <summary>
17+
/// Raised when the connection is reset so callers can clear cached declaration state.
18+
/// </summary>
19+
public static event Action ConnectionReset;
1620

1721
public static async Task<bool> VerifyAndCreateClients(string clientName)
1822
{
@@ -21,6 +25,7 @@ public static async Task<bool> VerifyAndCreateClients(string clientName)
2125
_connection.Dispose();
2226
_connection = null;
2327
_factory = null;
28+
ConnectionReset?.Invoke();
2429
}
2530

2631
if (_connection == null)
@@ -77,7 +82,7 @@ public static async Task<bool> VerifyAndCreateClients(string clientName)
7782
{
7883
try
7984
{
80-
var channel = await _connection.CreateChannelAsync();
85+
using var channel = await _connection.CreateChannelAsync();
8186

8287
await channel.QueueDeclareAsync(queue: SetQueueNameForEnv(ServiceBusConfig.SystemQueueName),
8388
durable: true,
@@ -180,6 +185,7 @@ public static async Task<IConnection> CreateConnection(string clientName)
180185
_connection.Dispose();
181186
_connection = null;
182187
_factory = null;
188+
ConnectionReset?.Invoke();
183189

184190
await VerifyAndCreateClients(clientName);
185191
}

Providers/Resgrid.Providers.Bus.Rabbit/RabbitTopicProvider.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ namespace Resgrid.Providers.Bus.Rabbit
1414
public class RabbitTopicProvider
1515
{
1616
private readonly string _clientName = "Resgrid-Topic";
17+
private static volatile bool _exchangeDeclared;
18+
19+
static RabbitTopicProvider()
20+
{
21+
RabbitConnection.ConnectionReset += () => _exchangeDeclared = false;
22+
}
1723

1824
public async Task<bool> PersonnelStatusChanged(UserStatusEvent message)
1925
{
@@ -115,6 +121,9 @@ public async Task<bool> UnitLocationUpdatedChanged(UnitLocationUpdatedEvent mess
115121

116122
private static async Task<bool> VerifyAndCreateClients(string clientName)
117123
{
124+
if (_exchangeDeclared)
125+
return true;
126+
118127
try
119128
{
120129
var connection = await RabbitConnection.CreateConnection(clientName);
@@ -125,6 +134,8 @@ private static async Task<bool> VerifyAndCreateClients(string clientName)
125134
{
126135
await channel.ExchangeDeclareAsync(RabbitConnection.SetQueueNameForEnv(Topics.EventingTopic), "fanout");
127136
}
137+
138+
_exchangeDeclared = true;
128139
}
129140
}
130141
catch (Exception ex)

Web/Resgrid.Web.Services/Controllers/TwilioController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ public async Task<ActionResult> VoiceCallAction(string userId, int callId, [From
598598

599599
int index = int.Parse(twilioRequest.Digits) - 2;
600600

601-
if (index >= 0 && index < 8)
601+
if (index >= 0 && index < stations.Count)
602602
{
603603
var station = stations[index];
604604

Web/Resgrid.Web/Areas/User/Controllers/CustomStatusesController.cs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ where key.ToString().StartsWith("buttonText_")
102102
if (gpsValue == "on")
103103
gps = true;
104104

105-
var noteType = int.Parse(form["noteType_" + i]);
106-
var detailType = int.Parse(form["detailType_" + i]);
105+
int.TryParse(form["noteType_" + i], out var noteType);
106+
int.TryParse(form["detailType_" + i], out var detailType);
107107

108108
var detail = new CustomStateDetail();
109109
detail.ButtonText = text;
@@ -113,15 +113,8 @@ where key.ToString().StartsWith("buttonText_")
113113
detail.DetailType = detailType;
114114
detail.TextColor = textColor;
115115

116-
if (!string.IsNullOrWhiteSpace(order))
117-
detail.Order = int.Parse(order);
118-
else
119-
detail.Order = 0;
120-
121-
if (!string.IsNullOrWhiteSpace(baseType))
122-
detail.BaseType = int.Parse(baseType);
123-
else
124-
detail.BaseType = 0;
116+
detail.Order = int.TryParse(order, out var parsedNewOrder) ? parsedNewOrder : 0;
117+
detail.BaseType = int.TryParse(baseType, out var parsedNewBaseType) ? parsedNewBaseType : -1;
125118

126119
model.State.Details.Add(detail);
127120
}
@@ -217,6 +210,8 @@ public async Task<IActionResult> EditDetail(EditDetailView model, CancellationTo
217210

218211
model.DetailTypes = model.DetailType.ToSelectList();
219212
model.NoteTypes = model.NoteType.ToSelectList();
213+
model.BaseTypes = model.BaseType.ToSelectList();
214+
model.Detail.CustomState = await _customStateService.GetCustomSateByIdAsync(model.Detail.CustomStateId);
220215

221216
if (ModelState.IsValid)
222217
{
@@ -248,8 +243,6 @@ public async Task<IActionResult> EditDetail(EditDetailView model, CancellationTo
248243
return RedirectToAction("Edit", new { id = detail.CustomStateId });
249244
}
250245

251-
model.Detail.CustomState = await _customStateService.GetCustomSateByIdAsync(model.Detail.CustomStateId);
252-
253246
return View(model);
254247
}
255248

@@ -292,8 +285,8 @@ where key.ToString().StartsWith("buttonText_")
292285
if (gpsValue == "on")
293286
gps = true;
294287

295-
var noteType = int.Parse(form["noteType_" + i]);
296-
var detailType = int.Parse(form["detailType_" + i]);
288+
int.TryParse(form["noteType_" + i], out var noteType);
289+
int.TryParse(form["detailType_" + i], out var detailType);
297290

298291
var detail = new CustomStateDetail();
299292
detail.ButtonText = text;
@@ -302,8 +295,8 @@ where key.ToString().StartsWith("buttonText_")
302295
detail.NoteType = noteType;
303296
detail.DetailType = detailType;
304297
detail.TextColor = textColor;
305-
detail.Order = int.Parse(order);
306-
detail.BaseType = int.Parse(baseType);
298+
detail.Order = int.TryParse(order, out var parsedOrder) ? parsedOrder : 0;
299+
detail.BaseType = int.TryParse(baseType, out var parsedBaseType) ? parsedBaseType : -1;
307300

308301
if (!string.IsNullOrWhiteSpace(customStateDetailId))
309302
detail.CustomStateDetailId = int.Parse(customStateDetailId);

Web/Resgrid.Web/Areas/User/Controllers/GroupsController.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,8 @@ public async Task<IActionResult> Geofence(int departmentGroupId)
606606
if (model.Group.DepartmentId != DepartmentId)
607607
return Unauthorized();
608608

609-
model.Coordinates = await _departmentGroupsService.GetMapCenterCoordinatesForGroupAsync(departmentGroupId);
609+
model.Coordinates = await _departmentGroupsService.GetMapCenterCoordinatesForGroupAsync(departmentGroupId)
610+
?? new Coordinates { Latitude = 39.8283, Longitude = -98.5795 };
610611

611612
return View(model);
612613
}

Web/Resgrid.Web/Areas/User/Views/Shifts/Index.cshtml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
@section Styles
1111
{
12-
<link rel="stylesheet" href="~/lib/fullcalendar/index.global.min.css" />
1312
<style>
1413
.nohover {
1514
text-decoration: none !important;
@@ -191,6 +190,4 @@
191190

192191
@section Scripts
193192
{
194-
<script src="~/lib/fullcalendar/index.global.min.js"></script>
195-
<script src="~/js/app/internal/shifts/resgrid.shifts.index.js"></script>
196193
}

Web/Resgrid.Web/Areas/User/Views/Templates/EditCallNote.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
@section Scripts
9494
{
9595
<script>
96-
document.querySelector("input[name='Sort']").addEventListener("keypress", function (evt) {
96+
document.querySelector("input[name='Autofill.Sort']").addEventListener("keypress", function (evt) {
9797
if(evt.which == 8){return} // to allow BackSpace
9898
if (evt.which < 48 || evt.which > 57)
9999
{

Web/Resgrid.Web/wwwroot/js/app/internal/statuses/resgrid.statuses.editstatus.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ var resgrid;
8282
function addOption() {
8383
$('#newStatusModal').modal('hide');
8484
resgrid.statuses.editstatus.optionsCount++;
85-
$('#options tbody').first().append("<tr><td><input type='number' min='0' id='order_" + editstatus.optionsCount + "' name='order_" + editstatus.optionsCount + "' value='0' class='numberEntry'></td><td>" + $('#buttonText').val() + "<input type='hidden' id='buttonText_" + editstatus.optionsCount + "' name='buttonText_" + editstatus.optionsCount + "' value='" + $('#buttonText').val() + "'></input><input type='hidden' id='baseType_" + editstatus.optionsCount + "' name='baseType_" + editstatus.optionsCount + "' value='" + $('#baseType').val() + "'></input></td><td><a class='btn btn-default' role='button' style='color:" + $('#textColor').val() + ";background:" + $('#buttonColor').val() + ";'>" + $('#buttonText').val() + "</a><input type='hidden' id='buttonColor_" + editstatus.optionsCount + "' name='buttonColor_" + editstatus.optionsCount + "' value='" + $('#buttonColor').val() + "'><input type='hidden' id='textColor_" + editstatus.optionsCount + "' name='textColor_" + editstatus.optionsCount + "' value='" + $('#textColor').val() + "'><input type='hidden' id='detailType_" + editstatus.optionsCount + "' name='detailType_" + editstatus.optionsCount + "' value='" + $('#detailType').val() + "'></input><input type='hidden' id='noteType_" + editstatus.optionsCount + "' name='noteType_" + editstatus.optionsCount + "' value='" + $('#noteType').val() + "'></input><input type='hidden' id='requireGps_" + editstatus.optionsCount + "' name='requireGps_" + editstatus.optionsCount + "' value='" + $('#requireGps').val() + "'></input></td><td style='text-align:center;'><a onclick='$(this).parent().parent().remove();' class='btn btn-xs btn-danger' data-original-title='Remove this option'>Remove</a></td></tr>");
85+
var baseTypeVal = $('#baseType').length ? $('#baseType').val() : '-1';
86+
var detailTypeVal = $('#detailType').length ? $('#detailType').val() : '0';
87+
var noteTypeVal = $('#noteType').length ? $('#noteType').val() : '0';
88+
var requireGpsVal = $('#requireGps').length ? $('#requireGps').val() : 'false';
89+
$('#options tbody').first().append("<tr><td><input type='number' min='0' id='order_" + editstatus.optionsCount + "' name='order_" + editstatus.optionsCount + "' value='0' class='numberEntry'></td><td>" + $('#buttonText').val() + "<input type='hidden' id='buttonText_" + editstatus.optionsCount + "' name='buttonText_" + editstatus.optionsCount + "' value='" + $('#buttonText').val() + "'></input><input type='hidden' id='baseType_" + editstatus.optionsCount + "' name='baseType_" + editstatus.optionsCount + "' value='" + baseTypeVal + "'></input></td><td><a class='btn btn-default' role='button' style='color:" + $('#textColor').val() + ";background:" + $('#buttonColor').val() + ";'>" + $('#buttonText').val() + "</a><input type='hidden' id='buttonColor_" + editstatus.optionsCount + "' name='buttonColor_" + editstatus.optionsCount + "' value='" + $('#buttonColor').val() + "'><input type='hidden' id='textColor_" + editstatus.optionsCount + "' name='textColor_" + editstatus.optionsCount + "' value='" + $('#textColor').val() + "'><input type='hidden' id='detailType_" + editstatus.optionsCount + "' name='detailType_" + editstatus.optionsCount + "' value='" + detailTypeVal + "'></input><input type='hidden' id='noteType_" + editstatus.optionsCount + "' name='noteType_" + editstatus.optionsCount + "' value='" + noteTypeVal + "'></input><input type='hidden' id='requireGps_" + editstatus.optionsCount + "' name='requireGps_" + editstatus.optionsCount + "' value='" + requireGpsVal + "'></input></td><td style='text-align:center;'><a onclick='$(this).parent().parent().remove();' class='btn btn-xs btn-danger' data-original-title='Remove this option'>Remove</a></td></tr>");
8690
}
8791
editstatus.addOption = addOption;
8892
function isNumber(evt) {

Web/Resgrid.Web/wwwroot/js/app/internal/statuses/resgrid.statuses.newstatus.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ var resgrid;
9090
$('#newStatusModal').modal('hide');
9191
$("#addOptionErrors").hide();
9292
resgrid.statuses.newstatus.optionsCount++;
93-
$('#options tbody').first().append("<tr><td><input type='number' min='0' id='order_" + newstatus.optionsCount + "' name='order_" + newstatus.optionsCount + "' value='0' onkeypress='return resgrid.statuses.newstatus.isNumber(event)'></td><td>" + $('#buttonText').val() + "<input type='hidden' id='buttonText_" + newstatus.optionsCount + "' name='buttonText_" + newstatus.optionsCount + "' value='" + $('#buttonText').val() + "'></input><input type='hidden' id='baseType_" + newstatus.optionsCount + "' name='baseType_" + newstatus.optionsCount + "' value='" + $('#baseType').val() + "'></input></td><td><a class='btn btn-default' role='button' style='color:" + $('#textColor').val() + ";background:" + $('#buttonColor').val() + ";'>" + $('#buttonText').val() + "</a><input type='hidden' id='buttonColor_" + newstatus.optionsCount + "' name='buttonColor_" + newstatus.optionsCount + "' value='" + $('#buttonColor').val() + "'><input type='hidden' id='textColor_" + newstatus.optionsCount + "' name='textColor_" + newstatus.optionsCount + "' value='" + $('#textColor').val() + "'><input type='hidden' id='detailType_" + newstatus.optionsCount + "' name='detailType_" + newstatus.optionsCount + "' value='" + $('#detailType').val() + "'></input><input type='hidden' id='noteType_" + newstatus.optionsCount + "' name='noteType_" + newstatus.optionsCount + "' value='" + $('#noteType').val() + "'></input><input type='hidden' id='requireGps_" + newstatus.optionsCount + "' name='requireGps_" + newstatus.optionsCount + "' value='" + $('#requireGps').val() + "'></input></td><td style='text-align:center;'><a onclick='$(this).parent().parent().remove();' class='btn btn-xs btn-danger' data-original-title='Remove this option'>Remove</a></td></tr>");
93+
var baseTypeVal = $('#baseType').length ? $('#baseType').val() : '-1';
94+
var detailTypeVal = $('#detailType').length ? $('#detailType').val() : '0';
95+
var noteTypeVal = $('#noteType').length ? $('#noteType').val() : '0';
96+
var requireGpsVal = $('#requireGps').length ? $('#requireGps').val() : 'false';
97+
$('#options tbody').first().append("<tr><td><input type='number' min='0' id='order_" + newstatus.optionsCount + "' name='order_" + newstatus.optionsCount + "' value='0' onkeypress='return resgrid.statuses.newstatus.isNumber(event)'></td><td>" + $('#buttonText').val() + "<input type='hidden' id='buttonText_" + newstatus.optionsCount + "' name='buttonText_" + newstatus.optionsCount + "' value='" + $('#buttonText').val() + "'></input><input type='hidden' id='baseType_" + newstatus.optionsCount + "' name='baseType_" + newstatus.optionsCount + "' value='" + baseTypeVal + "'></input></td><td><a class='btn btn-default' role='button' style='color:" + $('#textColor').val() + ";background:" + $('#buttonColor').val() + ";'>" + $('#buttonText').val() + "</a><input type='hidden' id='buttonColor_" + newstatus.optionsCount + "' name='buttonColor_" + newstatus.optionsCount + "' value='" + $('#buttonColor').val() + "'><input type='hidden' id='textColor_" + newstatus.optionsCount + "' name='textColor_" + newstatus.optionsCount + "' value='" + $('#textColor').val() + "'><input type='hidden' id='detailType_" + newstatus.optionsCount + "' name='detailType_" + newstatus.optionsCount + "' value='" + detailTypeVal + "'></input><input type='hidden' id='noteType_" + newstatus.optionsCount + "' name='noteType_" + newstatus.optionsCount + "' value='" + noteTypeVal + "'></input><input type='hidden' id='requireGps_" + newstatus.optionsCount + "' name='requireGps_" + newstatus.optionsCount + "' value='" + requireGpsVal + "'></input></td><td style='text-align:center;'><a onclick='$(this).parent().parent().remove();' class='btn btn-xs btn-danger' data-original-title='Remove this option'>Remove</a></td></tr>");
9498
}
9599
}
96100
newstatus.addOption = addOption;

0 commit comments

Comments
 (0)