public void ParseBBC(InputModels.ProcessedMessageInput processedMessageInput) { // NOTE: // If you do not want to encumber your software with the CodeKicker library, start with replacing this call. processedMessageInput.DisplayBody = BBCParser.ToHtml(processedMessageInput.DisplayBody); }
public async Task <InputModels.ProcessedMessageInput> ProcessMessageInput(ServiceModels.ServiceResponse serviceResponse, string messageBody) { InputModels.ProcessedMessageInput processedMessage = null; try { processedMessage = PreProcessMessageInput(messageBody); PreProcessSmileys(processedMessage); ParseBBC(processedMessage); ProcessSmileys(processedMessage); await ProcessMessageBodyUrls(processedMessage); FindMentionedUsers(processedMessage); PostProcessMessageInput(processedMessage); } catch (ArgumentException e) { serviceResponse.Error(nameof(InputModels.MessageInput.Body), $"An error occurred while processing the message. {e.Message}"); } if (processedMessage is null) { serviceResponse.Error(nameof(InputModels.MessageInput.Body), $"An error occurred while processing the message."); return(processedMessage); } return(processedMessage); }
public async Task <InputModels.ProcessedMessageInput> ProcessMessageInput(string messageBody) { var processedMessage = new InputModels.ProcessedMessageInput { OriginalBody = messageBody ?? string.Empty, DisplayBody = messageBody ?? string.Empty, MentionedUsers = new List <string>() }; try { processedMessage = await PreProcess(processedMessage); await ProcessSmileys(processedMessage); await ProcessMessageBodyUrls(processedMessage); await FindMentionedUsers(processedMessage); PostProcessMessageInput(processedMessage); } catch (ArgumentException ex) { processedMessage.Errors.Add("Body", $"An error occurred while processing the message. {ex.Message}"); } if (processedMessage is null) { processedMessage.Errors.Add("Body", $"An error occurred while processing the message."); return(processedMessage); } return(processedMessage); }
/// <summary> /// Searches a post for references to other users /// </summary> public async Task FindMentionedUsers(InputModels.ProcessedMessageInput processedMessageInput) { var regexUsers = new Regex(@"@(\S+)"); var matches = 0; foreach (Match regexMatch in regexUsers.Matches(processedMessageInput.DisplayBody)) { matches++; // DoS prevention if (matches > 10) { break; } var matchedTag = regexMatch.Groups[1].Value; var users = await AccountRepository.Records(); var user = users.FirstOrDefault(u => u.DisplayName.ToLower() == matchedTag.ToLower()); // try to guess what they meant if (user is null) { user = users.FirstOrDefault(u => u.UserName.ToLower().Contains(matchedTag.ToLower())); } if (user != null) { if (user.Id != UserContext.ApplicationUser.Id) { processedMessageInput.MentionedUsers.Add(user.Id); } // Eventually link to user profiles // returnObject.ProcessedBody = Regex.Replace(returnObject.ProcessedBody, @"@" + regexMatch.Groups[1].Value, "<a href='/Profile/Details/" + user.UserId + "' class='user'>" + user.DisplayName + "</span>"); } } }
/// <summary> /// Attempt to replace URLs in the message body with something better /// </summary> public async Task ProcessMessageBodyUrls(InputModels.ProcessedMessageInput processedMessageInput) { var displayBody = processedMessageInput.DisplayBody; var regexUrl = new Regex("(^| )((https?\\://){1}\\S+)", RegexOptions.Compiled | RegexOptions.Multiline); var matches = 0; foreach (Match regexMatch in regexUrl.Matches(displayBody)) { matches++; // DoS prevention if (matches > 10) { break; } var siteUrl = regexMatch.Groups[2].Value; if (!string.IsNullOrEmpty(siteUrl)) { var remoteUrlReplacement = await GetRemoteUrlReplacement(siteUrl); displayBody = remoteUrlReplacement.Regex.Replace(displayBody, remoteUrlReplacement.ReplacementText, 1); processedMessageInput.Cards += remoteUrlReplacement.Card; } } processedMessageInput.DisplayBody = displayBody; }
public void PreProcessSmileys(InputModels.ProcessedMessageInput processedMessageInput) { for (var i = 0; i < SmileyRepository.Count(); i++) { var pattern = @"(^|[\r\n\s])" + Regex.Escape(SmileyRepository[i].Code) + @"(?=$|[\r\n\s])"; var replacement = $"$1SMILEY_{i}_INDEX"; processedMessageInput.DisplayBody = Regex.Replace(processedMessageInput.DisplayBody, pattern, replacement, RegexOptions.Singleline); } }
public void ProcessSmileys(InputModels.ProcessedMessageInput processedMessageInput) { for (var i = 0; i < SmileyRepository.Count(); i++) { var pattern = $@"SMILEY_{i}_INDEX"; var replacement = "<img src='" + SmileyRepository[i].Path + "' />"; processedMessageInput.DisplayBody = Regex.Replace(processedMessageInput.DisplayBody, pattern, replacement); } }
public async Task ProcessSmileys(InputModels.ProcessedMessageInput processedMessageInput) { var smileys = await SmileyRepository.Records(); for (var i = 0; i < smileys.Count(); i++) { var pattern = $@"SMILEY_{i}_INDEX"; var replacement = $"<img src='{smileys[i].Path}' />"; processedMessageInput.DisplayBody = Regex.Replace(processedMessageInput.DisplayBody, pattern, replacement); } }
/// <summary> /// Minor post processing /// </summary> public void PostProcessMessageInput(InputModels.ProcessedMessageInput processedMessageInput) { // make absolutely sure it targets a new window. processedMessageInput.DisplayBody = new Regex(@"<a ").Replace(processedMessageInput.DisplayBody, "<a target='_blank' "); // trim extra lines from quotes processedMessageInput.DisplayBody = new Regex(@"<blockquote(.*?)>(\r|\n|\r\n)*").Replace(processedMessageInput.DisplayBody, match => $"<blockquote{match.Groups[1].Value}>"); processedMessageInput.DisplayBody = new Regex(@"(\r|\n|\r\n)*</blockquote>(\r|\n|\r\n)*").Replace(processedMessageInput.DisplayBody, "</blockquote>"); processedMessageInput.DisplayBody = processedMessageInput.DisplayBody.Trim(); processedMessageInput.ShortPreview = GetMessagePreview(processedMessageInput.DisplayBody, 100); processedMessageInput.LongPreview = GetMessagePreview(processedMessageInput.DisplayBody, 500, true); }
public async Task UpdateMessageRecord(InputModels.ProcessedMessageInput message, DataModels.Message record) { record.OriginalBody = message.OriginalBody; record.DisplayBody = message.DisplayBody; record.ShortPreview = message.ShortPreview; record.LongPreview = message.LongPreview; record.Cards = message.Cards; record.TimeEdited = DateTime.Now; DbContext.Update(record); await DbContext.SaveChangesAsync(); }
public void UpdateMessageRecord(InputModels.ProcessedMessageInput message, DataModels.Message record) { record.OriginalBody = message.OriginalBody; record.DisplayBody = message.DisplayBody; record.ShortPreview = message.ShortPreview; record.LongPreview = message.LongPreview; record.Cards = message.Cards; record.TimeEdited = DateTime.Now; record.EditedById = UserContext.ApplicationUser.Id; record.Processed = true; DbContext.Update(record); DbContext.SaveChanges(); }
/// <summary> /// Attempt to replace URLs in the message body with something better /// </summary> public async Task ProcessMessageBodyUrls(InputModels.ProcessedMessageInput processedMessageInput) { var displayBody = processedMessageInput.DisplayBody; var regexUrl = new Regex("(^| )((https?\\://){1}\\S+)", RegexOptions.Compiled | RegexOptions.Multiline); var matches = 0; var replacements = new Dictionary <string, string>(); foreach (Match regexMatch in regexUrl.Matches(displayBody)) { matches++; // DoS prevention if (matches > 10) { break; } var siteUrl = regexMatch.Groups[2].Value; if (string.IsNullOrEmpty(siteUrl)) { continue; } var key = $"SITEURL_{matches}"; displayBody = displayBody.Replace(siteUrl, key); var remoteUrlReplacement = await GetRemoteUrlReplacement(siteUrl); if (remoteUrlReplacement != null) { replacements.Add(key, remoteUrlReplacement.ReplacementText); processedMessageInput.Cards += remoteUrlReplacement.Card; } } foreach (var kvp in replacements) { displayBody = displayBody.Replace(kvp.Key, kvp.Value); } processedMessageInput.DisplayBody = displayBody; }
/// <summary> /// Searches a post for references to other users /// </summary> public async Task FindMentionedUsers(InputModels.ProcessedMessageInput processedMessageInput) { var regexUsers = new Regex(@"@(\S+)"); var matches = 0; foreach (Match regexMatch in regexUsers.Matches(processedMessageInput.DisplayBody)) { matches++; // DoS prevention if (matches > 10) { break; } var matchedTag = regexMatch.Groups[1].Value; var users = await AccountRepository.Records(); var user = users.FirstOrDefault(u => u.DisplayName.ToLower() == matchedTag.ToLower()); // try to guess what they meant if (user is null) { user = users.FirstOrDefault(u => u.UserName.ToLower().Contains(matchedTag.ToLower())); } if (user != null) { if (user.Id != CurrentUser.Id) { processedMessageInput.MentionedUsers.Add(user.Id); } // UNTESTED //processedMessageInput.DisplayBody = processedMessageInput.DisplayBody.Replace($"{regexMatch.Groups[1].Value}", $"<a href='/Messages/History/{user.Id}'>{user.DisplayName}</span>"); } } }
/// <summary> /// Some minor housekeeping on the message before we get into the heavy lifting. /// </summary> public InputModels.ProcessedMessageInput PreProcessMessageInput(string messageBody) { var processedMessageInput = new InputModels.ProcessedMessageInput { OriginalBody = messageBody ?? string.Empty, DisplayBody = messageBody ?? string.Empty, MentionedUsers = new List <string>() }; var displayBody = processedMessageInput.DisplayBody.Trim(); if (string.IsNullOrEmpty(displayBody)) { throw new ArgumentException("Message body is empty."); } // keep this as close to the smiley replacement as possible to prevent HTML-izing the bracket. displayBody = displayBody.Replace("*heartsmiley*", "<3"); processedMessageInput.DisplayBody = displayBody; return(processedMessageInput); }
public async Task <DataModels.Message> CreateMessageRecord(InputModels.ProcessedMessageInput processedMessage) { var now = DateTime.Now; var record = new DataModels.Message { OriginalBody = processedMessage.OriginalBody, DisplayBody = processedMessage.DisplayBody, ShortPreview = processedMessage.ShortPreview, LongPreview = processedMessage.LongPreview, Cards = processedMessage.Cards, TimePosted = now, TimeEdited = now, PostedById = CurrentUser.Id, }; DbContext.Messages.Add(record); await DbContext.SaveChangesAsync(); await NotifyMentionedUsers(processedMessage.MentionedUsers, record.Id); return(record); }
/// <summary> /// Some minor housekeeping on the message before we get into the heavy lifting. /// </summary> public async Task <InputModels.ProcessedMessageInput> PreProcess(InputModels.ProcessedMessageInput processedMessage) { processedMessage.DisplayBody = processedMessage.DisplayBody.Trim(); if (string.IsNullOrEmpty(processedMessage.DisplayBody)) { throw new ArgumentException("Message body is empty."); } var smileys = await SmileyRepository.Records(); // Ensures the smileys are safe from other HTML processing. for (var i = 0; i < smileys.Count(); i++) { var pattern = $@"(^|[\r\n\s]){Regex.Escape(smileys[i].Code)}(?=$|[\r\n\s])"; var replacement = $"$1SMILEY_{i}_INDEX"; processedMessage.DisplayBody = Regex.Replace(processedMessage.DisplayBody, pattern, replacement, RegexOptions.Singleline); } processedMessage.DisplayBody = BBCParser.ToHtml(processedMessage.DisplayBody); return(processedMessage); }
/// <summary> /// Some minor housekeeping on the message before we get into the heavy lifting. /// </summary> public async Task<InputModels.ProcessedMessageInput> PreProcessMessageInput(string messageBody) { var processedMessageInput = new InputModels.ProcessedMessageInput { OriginalBody = messageBody ?? string.Empty, DisplayBody = messageBody ?? string.Empty, MentionedUsers = new List<string>() }; processedMessageInput.DisplayBody = processedMessageInput.DisplayBody.Trim(); if (string.IsNullOrEmpty(processedMessageInput.DisplayBody)) { throw new ArgumentException("Message body is empty."); } var smileys = await SmileyRepository.Records(); // Ensures the smileys are safe from other HTML processing. for (var i = 0; i < smileys.Count(); i++) { var pattern = $@"(^|[\r\n\s]){Regex.Escape(smileys[i].Code)}(?=$|[\r\n\s])"; var replacement = $"$1SMILEY_{i}_INDEX"; processedMessageInput.DisplayBody = Regex.Replace(processedMessageInput.DisplayBody, pattern, replacement, RegexOptions.Singleline); } return processedMessageInput; }
public DataModels.Message CreateMessageRecord(InputModels.ProcessedMessageInput processedMessage, DataModels.Message replyRecord) { var parentId = 0; var replyId = 0; DataModels.Message parentMessage = null; if (replyRecord != null) { if (replyRecord.ParentId == 0) { parentId = replyRecord.Id; replyId = 0; parentMessage = replyRecord; } else { parentId = replyRecord.ParentId; replyId = replyRecord.Id; parentMessage = DbContext.Messages.First(item => item.Id == replyRecord.ParentId); } } var currentTime = DateTime.Now; var record = new DataModels.Message { OriginalBody = processedMessage.OriginalBody, DisplayBody = processedMessage.DisplayBody, ShortPreview = processedMessage.ShortPreview, LongPreview = processedMessage.LongPreview, Cards = processedMessage.Cards, TimePosted = currentTime, TimeEdited = currentTime, LastReplyPosted = currentTime, PostedById = UserContext.ApplicationUser.Id, EditedById = UserContext.ApplicationUser.Id, LastReplyById = UserContext.ApplicationUser.Id, ParentId = parentId, ReplyId = replyId, Processed = true }; DbContext.Messages.Add(record); DbContext.SaveChanges(); if (replyId > 0) { replyRecord.LastReplyId = record.Id; replyRecord.LastReplyById = UserContext.ApplicationUser.Id; replyRecord.LastReplyPosted = currentTime; DbContext.Update(replyRecord); if (replyRecord.PostedById != UserContext.ApplicationUser.Id) { var notification = new DataModels.Notification { MessageId = record.Id, UserId = replyRecord.PostedById, TargetUserId = UserContext.ApplicationUser.Id, Time = DateTime.Now, Type = Enums.ENotificationType.Quote, Unread = true, }; DbContext.Notifications.Add(notification); } } if (parentMessage != null && parentId != replyId) { parentMessage.ReplyCount++; parentMessage.LastReplyId = record.Id; parentMessage.LastReplyById = UserContext.ApplicationUser.Id; parentMessage.LastReplyPosted = currentTime; DbContext.Update(parentMessage); if (parentMessage.PostedById != UserContext.ApplicationUser.Id) { var notification = new DataModels.Notification { MessageId = record.Id, UserId = parentMessage.PostedById, TargetUserId = UserContext.ApplicationUser.Id, Time = DateTime.Now, Type = Enums.ENotificationType.Reply, Unread = true, }; DbContext.Notifications.Add(notification); } } NotifyMentionedUsers(processedMessage.MentionedUsers, record.Id); var topicId = parentId == 0 ? record.Id : parentId; UpdateTopicParticipation(topicId, UserContext.ApplicationUser.Id, DateTime.Now); DbContext.SaveChanges(); return(record); }
public void ParseBBC(InputModels.ProcessedMessageInput processedMessageInput) { processedMessageInput.DisplayBody = BBCParser.ToHtml(processedMessageInput.DisplayBody); }