From ba8fb046d7eee3e77d2f6630331a18a1fa32b3b8 Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Sat, 8 Aug 2026 16:07:14 -0700 Subject: [PATCH] RG-T117 Fixes --- .../Providers/KeywordIntentClassifier.cs | 8 +++ Core/Resgrid.Services/ChatMessageService.cs | 13 ++++ .../M0113_FixNotesDocumentsCategoryColumn.cs | 31 +++++++++ .../Sql/M0001_InitialMigration.sql | Bin 330802 -> 323174 bytes ...M0113_FixNotesDocumentsCategoryColumnPg.cs | 37 +++++++++++ .../Sql/M0001_InitialMigration.sql | Bin 270256 -> 261268 bytes ...hatbotAvailabilityIntentClassifierTests.cs | 7 ++ .../Services/ChatMessageServiceTests.cs | 61 ++++++++++++++++++ .../Controllers/v4/ChatController.cs | 5 +- .../Resgrid.Web.Services.xml | 2 +- .../src/components/chat/ChatPanelElement.tsx | 9 ++- .../src/components/chat/ConversationView.tsx | 6 +- .../src/components/chat/atoms/Composer.tsx | 11 +++- .../components/chat/atoms/MessageBubble.tsx | 2 +- .../User/Apps/src/components/chat/chat.css | 8 ++- .../GoogleReCaptchaValidationAttribute.cs | 51 +++++++++++---- .../Controllers/AccountController.cs | 16 +++-- 17 files changed, 236 insertions(+), 31 deletions(-) create mode 100644 Providers/Resgrid.Providers.Migrations/Migrations/M0113_FixNotesDocumentsCategoryColumn.cs create mode 100644 Providers/Resgrid.Providers.MigrationsPg/Migrations/M0113_FixNotesDocumentsCategoryColumnPg.cs diff --git a/Core/Resgrid.Chatbot.NLU/Providers/KeywordIntentClassifier.cs b/Core/Resgrid.Chatbot.NLU/Providers/KeywordIntentClassifier.cs index 676de0ac1..f015e1bf9 100644 --- a/Core/Resgrid.Chatbot.NLU/Providers/KeywordIntentClassifier.cs +++ b/Core/Resgrid.Chatbot.NLU/Providers/KeywordIntentClassifier.cs @@ -173,6 +173,14 @@ public class KeywordIntentClassifier : INLUProvider "list_messages", null), (R(@"^(show|list|get|what'?s)\s+(on\s+)?(the\s+)?(calendar|schedule|agenda)"), "list_calendar", null), + // Upcoming-calendar phrasings: "when is the next event?", "what is upcoming in the + // calendar?", "upcoming events", "what's coming up", "next events". + (R(@"^when('?s|\s+is)\s+(the\s+)?next\s+(event|meeting|training|class)(s|es)?$"), + "list_calendar", null), + (R(@"^(what('?s|\s+is)\s+)?(upcoming|coming\s+up)(\s+(events?|meetings?|trainings?))?(\s+(on|in)\s+(the\s+)?(calendar|schedule|agenda))?$"), + "list_calendar", null), + (R(@"^(next|upcoming)\s+(events?|meetings?|trainings?)$"), + "list_calendar", null), (R(@"^(show|list|get|my)\s+shifts?"), "list_shifts", null), (R(@"^(weather\s+)?(alerts?|warnings?)"), diff --git a/Core/Resgrid.Services/ChatMessageService.cs b/Core/Resgrid.Services/ChatMessageService.cs index 90a49b9dd..1e9f3a68a 100644 --- a/Core/Resgrid.Services/ChatMessageService.cs +++ b/Core/Resgrid.Services/ChatMessageService.cs @@ -343,6 +343,19 @@ public async Task> GetThreadPageAsync(string threadRootMessage if (member != null && (member.IsBanned || (member.MutedUntil.HasValue && member.MutedUntil.Value > DateTime.UtcNow))) return false; + // Double-taps are common: bail out before the insert so the ordinary duplicate never + // reaches the database (RepositoryBase logs every insert exception, so relying on the + // unique-violation catch below alone floods the error log). The catch still covers the + // genuine concurrent race two requests can win simultaneously. + var existingReactions = await _chatMessageReactionRepository.GetByMessageIdsAsync(new[] { chatMessageId }); + var alreadyReacted = existingReactions != null && existingReactions.Any(r => + string.Equals(r.Emoji, emoji, StringComparison.Ordinal) + && (unitId.HasValue + ? r.UnitId == unitId + : r.UserId != null && string.Equals(r.UserId, userId, StringComparison.OrdinalIgnoreCase))); + if (alreadyReacted) + return true; + try { await _chatMessageReactionRepository.InsertAsync(new ChatMessageReaction diff --git a/Providers/Resgrid.Providers.Migrations/Migrations/M0113_FixNotesDocumentsCategoryColumn.cs b/Providers/Resgrid.Providers.Migrations/Migrations/M0113_FixNotesDocumentsCategoryColumn.cs new file mode 100644 index 000000000..5ef4f0a4a --- /dev/null +++ b/Providers/Resgrid.Providers.Migrations/Migrations/M0113_FixNotesDocumentsCategoryColumn.cs @@ -0,0 +1,31 @@ +using FluentMigrator; + +namespace Resgrid.Providers.Migrations.Migrations +{ + /// + /// The initial schema created Notes and Documents with a misspelled "Catery" column while the + /// entities (and the Dapper-generated INSERT/UPDATE statements) use "Category" β€” every save + /// against a database built from M0001 failed with "invalid column name 'Category'". Renames + /// the column where the typo exists; guarded so databases that already have the correct + /// column (or were hand-fixed) are untouched. + /// + [Migration(113)] + public class M0113_FixNotesDocumentsCategoryColumn : Migration + { + public override void Up() + { + Execute.Sql(@" +IF COL_LENGTH('dbo.Notes', 'Catery') IS NOT NULL AND COL_LENGTH('dbo.Notes', 'Category') IS NULL + EXEC sp_rename 'dbo.Notes.Catery', 'Category', 'COLUMN';"); + + Execute.Sql(@" +IF COL_LENGTH('dbo.Documents', 'Catery') IS NOT NULL AND COL_LENGTH('dbo.Documents', 'Category') IS NULL + EXEC sp_rename 'dbo.Documents.Catery', 'Category', 'COLUMN';"); + } + + public override void Down() + { + // One-way typo fix; nothing to restore. + } + } +} diff --git a/Providers/Resgrid.Providers.Migrations/Sql/M0001_InitialMigration.sql b/Providers/Resgrid.Providers.Migrations/Sql/M0001_InitialMigration.sql index fdaa887cf7327d2ba29458453d40031ae37c436f..25c4f74fdf606869dbbb8040d4863beb6b86d71d 100644 GIT binary patch literal 323174 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 IF~k4=KdJ2SJpcdz diff --git a/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0113_FixNotesDocumentsCategoryColumnPg.cs b/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0113_FixNotesDocumentsCategoryColumnPg.cs new file mode 100644 index 000000000..7c6701a18 --- /dev/null +++ b/Providers/Resgrid.Providers.MigrationsPg/Migrations/M0113_FixNotesDocumentsCategoryColumnPg.cs @@ -0,0 +1,37 @@ +using FluentMigrator; + +namespace Resgrid.Providers.MigrationsPg.Migrations +{ + ///

+ /// The initial schema created notes and documents with a misspelled "catery" column while the + /// entities (and the Dapper-generated INSERT/UPDATE statements) use "category" β€” every save + /// against a database built from M0001 failed with 42703 "column category does not exist". + /// Renames the column where the typo exists; guarded so databases that already have the + /// correct column (or were hand-fixed) are untouched. + /// + [Migration(113)] + public class M0113_FixNotesDocumentsCategoryColumnPg : Migration + { + public override void Up() + { + Execute.Sql(@" +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'notes' AND column_name = 'catery') + AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'notes' AND column_name = 'category') THEN + ALTER TABLE public.notes RENAME COLUMN catery TO category; + END IF; + + IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'documents' AND column_name = 'catery') + AND NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'documents' AND column_name = 'category') THEN + ALTER TABLE public.documents RENAME COLUMN catery TO category; + END IF; +END $$;"); + } + + public override void Down() + { + // One-way typo fix; nothing to restore. + } + } +} diff --git a/Providers/Resgrid.Providers.MigrationsPg/Sql/M0001_InitialMigration.sql b/Providers/Resgrid.Providers.MigrationsPg/Sql/M0001_InitialMigration.sql index 2786a0489b9a6d7a730e6383adfdf77661761fda..d1c04dfe5e7792a1c3fad86bb90e5ba47b49826f 100644 GIT binary patch literal 261268 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

3E4TW9h1ngdJ%J(V9F)%l_(Q{fjPcdg9 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 literal 270256 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 z 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 F{y!iUWE=nh diff --git a/Tests/Resgrid.Tests/Chatbot/ChatbotAvailabilityIntentClassifierTests.cs b/Tests/Resgrid.Tests/Chatbot/ChatbotAvailabilityIntentClassifierTests.cs index b09a49f15..7b81617e6 100644 --- a/Tests/Resgrid.Tests/Chatbot/ChatbotAvailabilityIntentClassifierTests.cs +++ b/Tests/Resgrid.Tests/Chatbot/ChatbotAvailabilityIntentClassifierTests.cs @@ -36,6 +36,13 @@ public void Setup() [TestCase("Whats my schedule?", "my_schedule")] [TestCase("my unread messages?", "list_messages")] [TestCase("new messages", "list_messages")] + [TestCase("When is the next event?", "list_calendar")] + [TestCase("when's the next meeting", "list_calendar")] + [TestCase("What is upcoming in the calendar?", "list_calendar")] + [TestCase("what's coming up", "list_calendar")] + [TestCase("upcoming events", "list_calendar")] + [TestCase("next events", "list_calendar")] + [TestCase("Whats my schedule", "my_schedule")] public async Task Classifies_intent(string text, string expectedIntent) { var result = await _classifier.ClassifyAsync(text); diff --git a/Tests/Resgrid.Tests/Services/ChatMessageServiceTests.cs b/Tests/Resgrid.Tests/Services/ChatMessageServiceTests.cs index 079c92c16..f66fd22ee 100644 --- a/Tests/Resgrid.Tests/Services/ChatMessageServiceTests.cs +++ b/Tests/Resgrid.Tests/Services/ChatMessageServiceTests.cs @@ -74,5 +74,66 @@ public async Task DeleteMessageAsync_should_use_one_effective_actor_classificati payload.Value("DeletedByModerator").Should().Be(expectedModerated); payload.Value("IsModerated").Should().Be(expectedModerated); } + + // Double-tapping a reaction fires two AddReaction calls; the second must no-op without + // attempting the insert (the unique-index violation would flood the error log). + [TestCase("πŸ™", true, false)] // same emoji already present -> success, no insert + [TestCase("πŸ”₯", true, true)] // different emoji -> insert proceeds + public async Task AddReactionAsync_is_idempotent_for_duplicate_reactions(string emoji, bool expectedResult, bool expectInsert) + { + var message = new ChatMessage + { + ChatMessageId = "message-1", + ChatChannelId = "channel-1", + DepartmentId = 1, + SenderUserId = "sender", + Body = "body" + }; + var channel = new ChatChannel { ChatChannelId = message.ChatChannelId, DepartmentId = message.DepartmentId }; + var channelRepository = new Mock(); + var messageRepository = new Mock(); + var reactionRepository = new Mock(); + + messageRepository.Setup(x => x.GetByIdAsync(message.ChatMessageId)).ReturnsAsync(message); + channelRepository.Setup(x => x.GetByIdAsync(channel.ChatChannelId)).ReturnsAsync(channel); + reactionRepository + .Setup(x => x.GetByMessageIdsAsync(It.IsAny>())) + .ReturnsAsync(new[] + { + new ChatMessageReaction + { + ChatMessageId = message.ChatMessageId, + ParticipantType = (int)ChatParticipantType.User, + UserId = "USER-1", + Emoji = "πŸ™" + } + }); + reactionRepository + .Setup(x => x.InsertAsync(It.IsAny(), It.IsAny(), false)) + .ReturnsAsync((ChatMessageReaction reaction, CancellationToken _, bool __) => reaction); + + var service = new ChatMessageService( + channelRepository.Object, + messageRepository.Object, + Mock.Of(), + Mock.Of(), + reactionRepository.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of()); + + // Case-insensitive user match: stored UserId is "USER-1", caller sends "user-1". + var result = await service.AddReactionAsync(message.ChatMessageId, "user-1", null, emoji); + + result.Should().Be(expectedResult); + reactionRepository.Verify( + x => x.InsertAsync(It.IsAny(), It.IsAny(), false), + expectInsert ? Times.Once() : Times.Never()); + } } } diff --git a/Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs b/Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs index 2b2684d91..7d2d56e4d 100644 --- a/Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs +++ b/Web/Resgrid.Web.Services/Controllers/v4/ChatController.cs @@ -902,6 +902,9 @@ public async Task> EditMessage(string message if (input == null || String.IsNullOrWhiteSpace(input.Body)) return BadRequest(); + if (await IsChatbotMessageChannelAsync(messageId)) + return BadRequest("Messages can't be edited in assistant conversations."); + var message = await _chatMessageService.EditMessageAsync(messageId, UserId, input.Body, cancellationToken); if (message == null) @@ -1589,7 +1592,7 @@ private async Task IsRateLimitedAsync(string action, int limitPerWindow) ///

/// True when the message lives in an assistant (chatbot) conversation, where reactions, - /// threads and deletes are not available. + /// threads, deletes and edits are not available. /// private async Task IsChatbotMessageChannelAsync(string messageId) { diff --git a/Web/Resgrid.Web.Services/Resgrid.Web.Services.xml b/Web/Resgrid.Web.Services/Resgrid.Web.Services.xml index 73c5b523c..1d8a0eda7 100644 --- a/Web/Resgrid.Web.Services/Resgrid.Web.Services.xml +++ b/Web/Resgrid.Web.Services/Resgrid.Web.Services.xml @@ -737,7 +737,7 @@ True when the message lives in an assistant (chatbot) conversation, where reactions, - threads and deletes are not available. + threads, deletes and edits are not available. diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx index 8d67e4739..eae3a7cc7 100644 --- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx +++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ChatPanelElement.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import './chat.css'; -import { getCurrentUserId, type ChatChannelDto, type ChatMessageDto } from './types'; +import { ChatChannelType, getCurrentUserId, type ChatChannelDto, type ChatMessageDto } from './types'; import { useChatBootstrap } from './useChatBootstrap'; import { useChatStore, shallowArrayEqual } from './useChatStore'; import { setActiveChannel } from './chatStore'; @@ -21,8 +21,11 @@ export interface ChatPanelElementProps { export default function ChatPanelElement({ hostElement, label = 'Chat' }: ChatPanelElementProps) { const { available, loaded, loadFailed, reload, connect } = useChatBootstrap(); - const channels = useChatStore((state) => state.channels, shallowArrayEqual); - const unread = useChatStore((state) => state.channels.reduce((total, channel) => total + Math.max(0, channel.UnreadCount), 0)); + const allChannels = useChatStore((state) => state.channels, shallowArrayEqual); + // The assistant has its own footer button/drawer (rg-assistant); keep its channel β€” and its + // unread count β€” out of the chat popout entirely. + const channels = allChannels.filter((channel) => channel.ChannelType !== ChatChannelType.Chatbot); + const unread = channels.reduce((total, channel) => total + Math.max(0, channel.UnreadCount), 0); const [open, setOpen] = useState(false); const [activeChannelId, setActiveChannelId] = useState(null); diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ConversationView.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ConversationView.tsx index dc273aef4..693253071 100644 --- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ConversationView.tsx +++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/ConversationView.tsx @@ -57,8 +57,8 @@ export default function ConversationView(props: ConversationViewProps) { const channelId = channel.ChatChannelId; // Assistant conversations are restricted regardless of where they're opened (footer drawer uses // variant='bot'; the chat page renders the same channel with the default variant): text only β€” - // no emoji picker, GIFs, images, urgent priority, reactions, threads or deletes. Pin, flag and - // editing your own messages stay available. + // no emoji picker, GIFs, images, urgent priority, reactions, threads, deletes or edits. Pin and + // flag stay available. const isBot = variant === 'bot' || channel.ChannelType === ChatChannelType.Chatbot; const allMessages = useChatStore((state) => state.messagesByChannel[channelId] ?? EMPTY_MESSAGES, shallowArrayEqual); @@ -313,7 +313,7 @@ export default function ConversationView(props: ConversationViewProps) { showAckStatus={message.Priority === 1 && (message.SenderUserId === currentUserId || !!canModerate)} onReact={isBot ? undefined : handleReact} onOpenThread={isBot ? undefined : props.onOpenThread} - onSaveEdit={handleSaveEdit} + onSaveEdit={isBot ? undefined : handleSaveEdit} onDelete={isBot ? undefined : handleDelete} onPin={canModerate ? handlePin : undefined} onFlag={props.onFlag} diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/Composer.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/Composer.tsx index 796a58096..b44b788e8 100644 --- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/Composer.tsx +++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/Composer.tsx @@ -312,7 +312,16 @@ export default function Composer({ )} - void handleFile(event.target.files?.[0])} /> + {allowImages && ( + void handleFile(event.target.files?.[0])} + /> + )} ); } diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/MessageBubble.tsx b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/MessageBubble.tsx index df2337004..5c8f4d72c 100644 --- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/MessageBubble.tsx +++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/atoms/MessageBubble.tsx @@ -79,7 +79,7 @@ function MessageBubble(props: MessageBubbleProps) { bubbleClasses.push('rgchat-bubble--bot'); } - const canEdit = isMine && message.MessageType === ChatMessageType.Text && !isDeleted && !isFailed; + const canEdit = isMine && message.MessageType === ChatMessageType.Text && !isDeleted && !isFailed && !!props.onSaveEdit; const canDelete = (isMine || canModerate) && !isDeleted && !isFailed; const renderContent = () => { diff --git a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chat.css b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chat.css index b20b9d75d..10361736f 100644 --- a/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chat.css +++ b/Web/Resgrid.Web/Areas/User/Apps/src/components/chat/chat.css @@ -999,10 +999,14 @@ rg-chat { animation: rgchat-pop-in 140ms ease; } -/* Narrow hosts (footer chat popout / assistant drawer): the quick-reactions row would extend - past the panel edge and get clipped, so wrap it into a compact grid instead. */ +/* Narrow hosts (footer chat popout / assistant drawer): anchored to the right edge of the + actions row, the quick-reactions popover extends left past the panel edge and gets clipped. + Anchor it to the LEFT edge instead so it grows rightward over the message area, and wrap it + into a compact grid as a guard for very narrow widths. */ .rgchat-panel .rgchat-popover--reactions, .rgchat-drawer .rgchat-popover--reactions { + left: 0; + right: auto; flex-wrap: wrap; justify-content: center; width: max-content; diff --git a/Web/Resgrid.Web/Attributes/GoogleReCaptchaValidationAttribute.cs b/Web/Resgrid.Web/Attributes/GoogleReCaptchaValidationAttribute.cs index b4c4d925f..618d13d22 100644 --- a/Web/Resgrid.Web/Attributes/GoogleReCaptchaValidationAttribute.cs +++ b/Web/Resgrid.Web/Attributes/GoogleReCaptchaValidationAttribute.cs @@ -1,14 +1,23 @@ -ο»Ώusing Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; using Resgrid.Config; using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Net; using System.Net.Http; +using System.Threading.Tasks; namespace Resgrid.WebCore.Attributes { public class GoogleReCaptchaValidationAttribute : ValidationAttribute { + // Shared client: a new HttpClient per validation leaks sockets under load ("Resource + // temporarily unavailable" on the register form). Validation attributes are synchronous, + // so the call is bounded by a short timeout instead of the 100-second default. + private static readonly HttpClient _httpClient = new HttpClient + { + Timeout = TimeSpan.FromSeconds(10) + }; protected override ValidationResult IsValid(object value, ValidationContext validationContext) { @@ -22,23 +31,37 @@ protected override ValidationResult IsValid(object value, ValidationContext vali String reCaptchResponse = value.ToString(); String reCaptchaSecret = WebConfig.RecaptchaPrivateKey; - - HttpClient httpClient = new HttpClient(); - var httpResponse = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={reCaptchaSecret}&response={reCaptchResponse}").Result; - if (httpResponse.StatusCode != HttpStatusCode.OK) + try { - return errorResult.Value; - } + // POST keeps the secret out of URLs (request logs, proxies). + using var content = new FormUrlEncodedContent(new Dictionary + { + ["secret"] = reCaptchaSecret, + ["response"] = reCaptchResponse + }); - String jsonResponse = httpResponse.Content.ReadAsStringAsync().Result; - dynamic jsonData = JObject.Parse(jsonResponse); - if (jsonData.success != true.ToString().ToLower()) - { - return errorResult.Value; - } + var httpResponse = _httpClient.PostAsync("https://www.google.com/recaptcha/api/siteverify", content).GetAwaiter().GetResult(); + if (httpResponse.StatusCode != HttpStatusCode.OK) + { + return errorResult.Value; + } - return ValidationResult.Success; + String jsonResponse = httpResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + dynamic jsonData = JObject.Parse(jsonResponse); + if (jsonData.success != true.ToString().ToLower()) + { + return errorResult.Value; + } + return ValidationResult.Success; + } + catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException || ex is OperationCanceledException) + { + // Transient network/DNS failure reaching Google: fail closed with a retryable + // validation message instead of letting the exception 500 the register page. + Framework.Logging.LogException(ex); + return new ValidationResult("We couldn't verify the reCAPTCHA right now. Please try again.", new String[] { validationContext.MemberName }); + } } } } diff --git a/Web/Resgrid.Web/Controllers/AccountController.cs b/Web/Resgrid.Web/Controllers/AccountController.cs index f5d33f6e4..0199932c2 100644 --- a/Web/Resgrid.Web/Controllers/AccountController.cs +++ b/Web/Resgrid.Web/Controllers/AccountController.cs @@ -782,17 +782,23 @@ public IActionResult AccessDenied() [HttpPost] public IActionResult SetLanugage(string culture, string returnUrl) { - if (!String.IsNullOrWhiteSpace(culture)) + // Whitelist the shipped locales: this anonymous endpoint gets scanner garbage ("'", + // paths, SQL fragments) and RequestCulture/CultureInfo throw on invalid names. + // Anything not supported is silently ignored instead of turning into a 500. + var supported = String.IsNullOrWhiteSpace(culture) + ? null + : Resgrid.Localization.SupportedLocales.GetSupportedCultures() + .FirstOrDefault(c => String.Equals(c, culture.Trim(), StringComparison.OrdinalIgnoreCase)); + + if (supported != null) { - Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), new CookieOptions { Expires = DateTime.UtcNow.AddYears(1) }); + Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(supported)), new CookieOptions { Expires = DateTime.UtcNow.AddYears(1) }); // This guy I think is causing issues with like DateTime rendering mm/dd/yy vs dd/mm/yy, so need to look into that more. -SJ //Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo(culture); - Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(culture); + Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(supported); if (!String.IsNullOrWhiteSpace(returnUrl)) return RedirectToLocal(returnUrl); - else - return RedirectToAction("LogOn"); } return RedirectToAction("LogOn");