diff --git a/ANAConversationPlatform/Attributes/BasicAuthenticationAttribute.cs b/ANAConversationPlatform/Attributes/BasicAuthenticationAttribute.cs new file mode 100644 index 0000000..b301fcd --- /dev/null +++ b/ANAConversationPlatform/Attributes/BasicAuthenticationAttribute.cs @@ -0,0 +1,38 @@ +using ANAConversationPlatform.Helpers; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ANAConversationPlatform.Attributes +{ + public class BasicAuthenticationAttribute : ActionFilterAttribute + { + public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + if (Utils.BasicAuth == null || string.IsNullOrWhiteSpace(Utils.BasicAuth.APIKey) || string.IsNullOrWhiteSpace(Utils.BasicAuth.APISecret)) + { + await next(); + return; + } + + var headers = context.HttpContext.Request.Headers; + var authHeader = headers["Authorization"].FirstOrDefault(); + if (string.IsNullOrWhiteSpace(authHeader)) + { + context.HttpContext.Response.StatusCode = 401; + return; + } + var savedAuthBase64 = Utils.BasicAuth.GetBase64(); + var givenAuthBase64 = authHeader.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Skip(1).FirstOrDefault()?.Trim(); + if (givenAuthBase64 != savedAuthBase64) + { + context.HttpContext.Response.StatusCode = 401; + return; + } + await next(); + } + } +} diff --git a/ANAConversationPlatform/Controllers/ActivityController.cs b/ANAConversationPlatform/Controllers/ActivityController.cs index e21cf0b..73f7011 100644 --- a/ANAConversationPlatform/Controllers/ActivityController.cs +++ b/ANAConversationPlatform/Controllers/ActivityController.cs @@ -1,24 +1,17 @@ using Microsoft.AspNetCore.Mvc; using ANAConversationPlatform.Models.Activity; using ANAConversationPlatform.Helpers; +using System.Threading.Tasks; namespace ANAConversationPlatform.Controllers { [Produces("application/json")] public class ActivityController : Controller { - [HttpGet] - public ActionResult Summary(string nodeIds) - { - var nodeIdList = nodeIds.Split(','); - - return Ok(new { Message = "Done" }); - } - [HttpPost] - public ActionResult Track([FromBody]ChatActivityEvent activityEvent) + public async Task Track([FromBody]ChatActivityEvent activityEvent) { - MongoHelper.InsertActivityEvent(activityEvent); + await MongoHelper.InsertActivityEventAsync(activityEvent); return Ok(); } } diff --git a/ANAConversationPlatform/Controllers/AgentChatController.cs b/ANAConversationPlatform/Controllers/AgentChatController.cs index c5e1ade..0b9b67d 100644 --- a/ANAConversationPlatform/Controllers/AgentChatController.cs +++ b/ANAConversationPlatform/Controllers/AgentChatController.cs @@ -35,7 +35,7 @@ public async Task UserInput(string CHAT_USER_ID, string CHAT_USER_ public async Task SubmitHistory([FromBody]SubmitChatHistoryModel history) { if (string.IsNullOrWhiteSpace(history.CHAT_USER_ID) || string.IsNullOrWhiteSpace(history.CHAT_USER_TOKEN)) - return BadRequest("Empty chat user id or chat user token"); + return BadRequest(new { Message = "Empty chat user id or chat user token" }); if (history == null || history.HISTORY == null || history.HISTORY.Count <= 0) return Ok(); diff --git a/ANAConversationPlatform/Controllers/ConversationController.cs b/ANAConversationPlatform/Controllers/ConversationController.cs index 60f6232..28c205a 100644 --- a/ANAConversationPlatform/Controllers/ConversationController.cs +++ b/ANAConversationPlatform/Controllers/ConversationController.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using ANAConversationPlatform.Helpers; -using System.Diagnostics; -using MongoDB.Bson; -using Newtonsoft.Json; using ANAConversationPlatform.Models; using ANAConversationPlatform.Models.Sections; using Microsoft.Extensions.Logging; using static ANAConversationPlatform.Helpers.Constants; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using System.IO; +using ANAConversationPlatform.Attributes; namespace ANAConversationPlatform.Controllers { @@ -22,19 +24,30 @@ public ConversationController(ILogger log) } [HttpGet] - public ActionResult Chat() + public async Task Chat([FromQuery]string projectId = null, [FromQuery]string projectName = null, [FromQuery]bool enableAgentChat = true) { try { - var chatNodes = MongoHelper.RetrieveRecordsFromChatNode(); + if (string.IsNullOrWhiteSpace(projectId) && string.IsNullOrWhiteSpace(projectName)) + return BadRequest(new { Message = "Either project id or project name has to be provided" }); + + ChatFlowPack chatFlowPack = null; + if (!string.IsNullOrWhiteSpace(projectId)) + chatFlowPack = await MongoHelper.GetChatFlowPackAsync(projectId); + else if (!string.IsNullOrWhiteSpace(projectName)) + chatFlowPack = await MongoHelper.GetChatFlowPackByProjectNameAsync(projectName); + + if (chatFlowPack == null) + return BadRequest(new { Message = "No chat flow found by the given project id or name" }); + + var chatNodes = ChatFlowBuilder.Build(chatFlowPack); if (chatNodes == null || chatNodes.Count == 0) return Ok(new object[] { }); - return Json(chatNodes, new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore, - Converters = new List { new CustomStringEnumConverter() } - }); + if (enableAgentChat) + AddAgentChatNodes(chatNodes); + + return Json(chatNodes, PublishJsonSettings); } catch (System.Exception ex) { @@ -44,20 +57,49 @@ public ActionResult Chat() } [HttpGet] - public ActionResult RefreshContent() + public ActionResult HybridChat() { - MongoHelper.RefreshContentInMemory(); - return Ok(new { Message = "Done" }); + return RedirectToAction(nameof(Chat)); } - [HttpGet] - public ActionResult HybridChat() + [Produces("text/plain"), HttpPost, BasicAuthentication] + public async Task SaveChatFlow() { try { - var chatNodes = MongoHelper.RetrieveRecordsFromChatNode(); + ChatFlowPack req = null; + using (var s = new StreamReader(Request.Body)) + req = BsonSerializer.Deserialize(s.ReadToEnd()); + + if (req == null) + return BadRequest(new { Message = "No chat flow received to save!" }); + + var saved = await MongoHelper.SaveChatFlowAsync(req); + if (saved) + return Content(new { Message = "Chat flow saved", Data = req }.ToJson(), "text/plain"); + } + catch (System.Exception ex) + { + return BadRequest(new { Message = "Unable to save chat flow!. Ex: " + ex.Message }); + } + return BadRequest(new { Message = "Unable to save chat flow!" }); + } + + [Produces("text/plain"), HttpGet, BasicAuthentication] + public async Task FetchChatFlow([FromQuery] string projectId) + { + if (string.IsNullOrWhiteSpace(projectId)) + return BadRequest(new { Message = "Project Id is not provided!" }); + + var proj = await MongoHelper.GetChatFlowPackAsync(projectId); + if (proj != null) + return Content(new { Message = "Fetched", Data = proj }.ToJson(), "text/plain"); + return BadRequest(new { Message = "Project with the given id was not found or could not be retrieved!" }); + } - chatNodes.AddRange(new[] + private void AddAgentChatNodes(List chatNodes) + { + chatNodes.AddRange(new[] { new ChatNode("INIT_CHAT_NODE") { @@ -115,21 +157,6 @@ public ActionResult HybridChat() VariableName = "TEXT" } }); - - if (chatNodes == null || chatNodes.Count == 0) - return Ok(new object[] { }); - - return Json(chatNodes, new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore, - Converters = new List { new CustomStringEnumConverter() } - }); - } - catch (System.Exception ex) - { - _log.LogError(new EventId((int)LoggerEventId.HYBRID_CHAT_ACTION_ERROR), ex, ex.Message); - return StatusCode(500, new { Message = ex.Message }); - } } } } \ No newline at end of file diff --git a/ANAConversationPlatform/Controllers/ProjectController.cs b/ANAConversationPlatform/Controllers/ProjectController.cs new file mode 100644 index 0000000..3d14913 --- /dev/null +++ b/ANAConversationPlatform/Controllers/ProjectController.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ANAConversationPlatform.Helpers; +using ANAConversationPlatform.Models; +using System.Collections.Generic; +using ANAConversationPlatform.Attributes; + +namespace ANAConversationPlatform.Controllers +{ + [Produces("application/json"), BasicAuthentication] + public class ProjectController : Controller + { + [HttpGet] + public async Task List() + { + var projs = await MongoHelper.GetProjectsAsync(); + if (projs != null) + return Json(new { Message = "Projects list", Data = projs }); + return BadRequest(new { Message = "Unable to list the projects!" }); + } + + [HttpPost] + public ActionResult Save([FromBody] List projects) + { + var projs = MongoHelper.SaveProjects(projects); + if (projs != null) + return Ok(new { Message = "Saved", Data = projects }); + + return BadRequest(new { Message = "Unable to save!" }); + } + } +} \ No newline at end of file diff --git a/ANAConversationPlatform/Controllers/ServicesController.cs b/ANAConversationPlatform/Controllers/ServicesController.cs index ee1934d..1278962 100644 --- a/ANAConversationPlatform/Controllers/ServicesController.cs +++ b/ANAConversationPlatform/Controllers/ServicesController.cs @@ -18,21 +18,21 @@ public ServicesController(IHostingEnvironment env) [HttpPost] public ActionResult ReceiveFile(string fileName) { - if (string.IsNullOrWhiteSpace(fileName)) return BadRequest("fileName cannot be empty"); + if (string.IsNullOrWhiteSpace(fileName)) return BadRequest(new { Message = "fileName cannot be empty" }); fileName = Path.GetFileNameWithoutExtension(fileName) + "-" + Guid.NewGuid() + Path.GetExtension(fileName); using (var fileStream = Request.Body) { if (fileStream == null) - return BadRequest("Unable to read file content"); + return BadRequest(new { Message = "Unable to read file content" }); var fullFileName = Path.Combine(_env.WebRootPath, Constants.CHAT_MEDIA_FOLDER_NAME, fileName); var done = FileSaveHelper.Save(fullFileName, fileStream); if (done) return Ok(new { Url = $"{Request.Scheme}://{Request.Host}/{Constants.CHAT_MEDIA_FOLDER_NAME}/{fileName}" }); else - return StatusCode(500, "Unable to save received file"); + return StatusCode(500, "Unable to save received file"); } } } diff --git a/ANAConversationPlatform/Controllers/StudioDistController.cs b/ANAConversationPlatform/Controllers/StudioDistController.cs index 4e715a3..51d0135 100644 --- a/ANAConversationPlatform/Controllers/StudioDistController.cs +++ b/ANAConversationPlatform/Controllers/StudioDistController.cs @@ -29,7 +29,7 @@ public ActionResult Latest() }); } } - return BadRequest("Studio Distribution Status Unknown"); + return BadRequest(new { Message = "Studio Distribution Status Unknown" }); } [HttpGet] diff --git a/ANAConversationPlatform/Helpers/ChatFlowBuilder.cs b/ANAConversationPlatform/Helpers/ChatFlowBuilder.cs new file mode 100644 index 0000000..8421d86 --- /dev/null +++ b/ANAConversationPlatform/Helpers/ChatFlowBuilder.cs @@ -0,0 +1,143 @@ +using MongoDB.Driver; +using ANAConversationPlatform.Models; +using ANAConversationPlatform.Models.Sections; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; +using static ANAConversationPlatform.Helpers.Constants; + +namespace ANAConversationPlatform.Helpers +{ + public static class ChatFlowBuilder + { + public static ILogger Logger { get; set; } + + public static List Build(ChatFlowPack chatFlow) + { + try + { + var filter = Builders.Filter; + + var nodesList = new ConcurrentBag(chatFlow.ChatNodes); + var content = new ConcurrentBag(chatFlow.ChatContent); + Parallel.ForEach(nodesList, chatNode => + { + try + { + foreach (Section section in chatNode.Sections) + FillSectionWithContent(section, content); + foreach (Button button in chatNode.Buttons) + button.ButtonText = content.GetFor(button)?.ButtonText; + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "RetrieveRecordsFromChatNode Error: {0}", ex.Message); + } + }); + + var startNode = nodesList.FirstOrDefault(x => x.IsStartNode); + if (startNode != null) //If start chat node is present, move it up + { + var result = nodesList.Where(x => x != startNode).ToList(); + result.Insert(0, startNode); + return result; + } + return nodesList.ToList(); + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "RetrieveRecordsFromChatNode Error: {0}", ex.Message); + } + return null; + } + + private static readonly Random rand = new Random(); + private static void FillSectionWithContent(Section emptySection, ConcurrentBag contents) + { + switch (emptySection.SectionType) + { + case SectionTypeEnum.Image: + case SectionTypeEnum.Gif: + var imgSection = emptySection as ImageSection; + var imgContent = contents.GetFor(imgSection) as TitleCaptionSectionContent; + if (imgContent != null) + { + imgSection.Title = imgContent.Title; + imgSection.Caption = imgContent.Caption; + } + break; + + case SectionTypeEnum.Text: + var textSection = emptySection as TextSection; + var textContent = contents.GetFor(textSection) as TextSectionContent; + if (textContent != null) + { + textSection.Text = textContent.SectionText; + if (textSection.DelayInMs == 0) + textSection.DelayInMs = Math.Min(Utils.Settings.MaxCapTimeTakenToType, textSection.Text.Length * (Utils.Settings.BaseTimeTakenToTypePerChar + rand.Next(0, Utils.Settings.VariableTimeTakenToTypePerChar))); + } + break; + + case SectionTypeEnum.Audio: + var audioSection = emptySection as AudioSection; + var audioContent = contents.GetFor(audioSection) as TitleCaptionSectionContent; + if (audioContent != null) + { + audioSection.Title = audioContent.Title; + audioSection.Caption = audioContent.Caption; + } + break; + + case SectionTypeEnum.Video: + var videoSection = emptySection as VideoSection; + var videoContent = contents.GetFor(videoSection) as TitleCaptionSectionContent; + if (videoContent != null) + { + videoSection.Title = videoContent.Title; + videoSection.Caption = videoContent.Caption; + } + break; + + case SectionTypeEnum.EmbeddedHtml: + var embeddedHtmlSection = emptySection as EmbeddedHtmlSection; + var embeddedHtmlContent = contents.GetFor(embeddedHtmlSection) as TitleCaptionSectionContent; + if (embeddedHtmlContent != null) + { + embeddedHtmlSection.Title = embeddedHtmlContent.Title; + embeddedHtmlSection.Caption = embeddedHtmlContent.Caption; + } + break; + + case SectionTypeEnum.Carousel: + var carouselSection = emptySection as CarouselSection; + var carContent = contents.GetFor(carouselSection) as TitleCaptionSectionContent; + if (carContent != null) + { + carouselSection.Title = carContent.Title; + carouselSection.Caption = carContent.Caption; + } + if (carouselSection.Items != null) + foreach (var carItem in carouselSection.Items) + { + var content = contents.GetFor(carItem); + if (content != null) + { + carItem.Title = content.Title; + carItem.Caption = content.Caption; + } + if (carItem.Buttons != null) + foreach (var carBtn in carItem.Buttons) + { + var carBtnContent = contents.GetFor(carBtn); + carBtn.Text = carBtnContent?.ButtonText; + } + } + break; + } + } + + } +} diff --git a/ANAConversationPlatform/Helpers/Constants.cs b/ANAConversationPlatform/Helpers/Constants.cs index 10afa70..20d29e9 100644 --- a/ANAConversationPlatform/Helpers/Constants.cs +++ b/ANAConversationPlatform/Helpers/Constants.cs @@ -1,4 +1,8 @@ -namespace ANAConversationPlatform.Helpers +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System.Collections.Generic; + +namespace ANAConversationPlatform.Helpers { public static class Constants { @@ -15,5 +19,11 @@ public enum LoggerEventId CHAT_ACTION_ERROR = 7, HYBRID_CHAT_ACTION_ERROR = 8, } + + public static readonly JsonSerializerSettings PublishJsonSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Converters = new List { new StringEnumConverter() } + }; } } diff --git a/ANAConversationPlatform/Helpers/Extensions.cs b/ANAConversationPlatform/Helpers/Extensions.cs index 105f1b9..2c11e3d 100644 --- a/ANAConversationPlatform/Helpers/Extensions.cs +++ b/ANAConversationPlatform/Helpers/Extensions.cs @@ -5,47 +5,30 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -using System.Threading.Tasks; namespace ANAConversationPlatform.Helpers { public static class Extensions { - public static Content GetFor(this IEnumerable contentCollection, ChatNode node) - { - if (string.IsNullOrWhiteSpace(node.Id)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.NodeId) && x.NodeId == node.Id); - } - - public static Content GetFor(this IEnumerable contentCollection, Section section) + public static SectionContent GetFor(this IEnumerable contentCollection, Section section) { if (string.IsNullOrWhiteSpace(section._id)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.SectionId) && x.SectionId == section._id); + return contentCollection.FirstOrDefault(x => x is SectionContent && !string.IsNullOrWhiteSpace((x as SectionContent).SectionId) && (x as SectionContent).SectionId == section._id) as SectionContent; } - - public static Content GetFor(this IEnumerable contentCollection, CarouselItem carouselItem) + public static CarouselItemContent GetFor(this IEnumerable contentCollection, CarouselItem carouselItem) { if (string.IsNullOrWhiteSpace(carouselItem._id)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.CarouselItemId) && x.CarouselItemId == carouselItem._id); + return contentCollection.FirstOrDefault(x => x is CarouselItemContent && !string.IsNullOrWhiteSpace((x as CarouselItemContent).CarouselItemId) && (x as CarouselItemContent).CarouselItemId == carouselItem._id) as CarouselItemContent; } - - public static Content GetFor(this IEnumerable contentCollection, CarouselButton carouselBtn) + public static CarouselButtonContent GetFor(this IEnumerable contentCollection, CarouselButton carouselBtn) { if (string.IsNullOrWhiteSpace(carouselBtn._id)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.CarouselButtonId) && x.CarouselButtonId == carouselBtn._id); + return contentCollection.FirstOrDefault(x => x is CarouselButtonContent && !string.IsNullOrWhiteSpace((x as CarouselButtonContent).CarouselButtonId) && (x as CarouselButtonContent).CarouselButtonId == carouselBtn._id) as CarouselButtonContent; } - - public static Content GetFor(this IEnumerable contentCollection, Button btn) - { - if (string.IsNullOrWhiteSpace(btn._id)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.ButtonId) && x.ButtonId == btn._id); - } - public static Content GetFor(this IEnumerable contentCollection, Coordinates coordiates) + public static ButtonContent GetFor(this IEnumerable contentCollection, Button btn) { - if (string.IsNullOrWhiteSpace(coordiates.CoordinateListId)) return null; - return contentCollection.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.ButtonId) && x.ButtonId == coordiates.CoordinateListId); + return contentCollection.FirstOrDefault(x => x is ButtonContent && !string.IsNullOrWhiteSpace((x as ButtonContent).ButtonId) && (x as ButtonContent).ButtonId == btn._id) as ButtonContent; } - public static string GetDescriptionOrDefault(this Enum value) { var field = value.GetType().GetField(value.ToString()); @@ -56,7 +39,6 @@ public static string GetDescriptionOrDefault(this Enum value) else return value.ToString(); } - public static T ParseEnum(this string value) { return (T)Enum.Parse(typeof(T), value, true); diff --git a/ANAConversationPlatform/Helpers/MongoHelper.cs b/ANAConversationPlatform/Helpers/MongoHelper.cs index 28e884e..0f99fcd 100644 --- a/ANAConversationPlatform/Helpers/MongoHelper.cs +++ b/ANAConversationPlatform/Helpers/MongoHelper.cs @@ -7,12 +7,9 @@ using ANAConversationPlatform.Models.Settings; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using ANAConversationPlatform.Models.Activity; using System.Threading.Tasks; -using System.Collections.Concurrent; -using ANAConversationPlatform.Controllers; using Microsoft.Extensions.Logging; using static ANAConversationPlatform.Helpers.Constants; @@ -22,10 +19,53 @@ public static class MongoHelper { static MongoHelper() { - ConventionRegistry.Register(typeof(IgnoreExtraElementsConvention).Name, new ConventionPack { new IgnoreExtraElementsConvention(true) }, t => true); + #region Initialize Mongo Driver + ConventionRegistry.Register(nameof(IgnoreExtraElementsConvention), new ConventionPack { new IgnoreExtraElementsConvention(true) }, t => true); + ConventionRegistry.Register(nameof(EnumRepresentationConvention), new ConventionPack { new EnumRepresentationConvention(BsonType.String) }, t => true); + if (!BsonClassMap.IsClassMapRegistered(typeof(GifSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(TextSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(ImageSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(AudioSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(VideoSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(EmbeddedHtmlSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(CarouselSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(SectionContent))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(TextSectionContent))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(TitleCaptionSectionContent))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(ButtonContent))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(PrintOTPSection))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(CarouselButtonContent))) + BsonClassMap.RegisterClassMap(); + + if (!BsonClassMap.IsClassMapRegistered(typeof(CarouselItemContent))) + BsonClassMap.RegisterClassMap(); + #endregion } public static ILogger Logger { get; set; } - public static DatabaseConnectionSettings Settings { get; set; } private static MongoClient _chatClient; @@ -46,278 +86,173 @@ private static IMongoDatabase ChatDB } } - private static ConcurrentBag _contents; - private static ConcurrentBag Contents + public static async Task InsertActivityEventAsync(ChatActivityEvent activityEvent) { - get + try { - if (_contents == null) - _contents = new ConcurrentBag(GetContentCollection()); - return _contents; + if (activityEvent != null && string.IsNullOrWhiteSpace(activityEvent._id)) + activityEvent._id = ObjectId.GenerateNewId().ToString(); + + var coll = ChatDB.GetCollection(Settings.ActivityEventLogCollectionName); + await coll.InsertOneAsync(activityEvent); + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "InsertActivityEvent: {0}", ex.Message); } } - public static List GetContentCollection() => ChatDB.GetCollection(Settings.ContentCollectionName).Find(new BsonDocument()).ToList(); + public static async Task> GetProjectsAsync() + { + try + { + return await ChatDB.GetCollection(Settings.ProjectsCollectionName).Find(new BsonDocument()).ToListAsync(); + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "GetProjectsAsync: {0}", ex.Message); + return null; + } + } - public static void RefreshContentInMemory() + public static async Task GetProjectAsync(string projectId) { - _contents = new ConcurrentBag(GetContentCollection()); + try + { + return await ChatDB.GetCollection(Settings.ProjectsCollectionName).Find(x => x._id == projectId).SingleOrDefaultAsync(); + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "GetProjectAsync: {0}", ex.Message); + return null; + } } - public static List RetrieveRecordsFromChatNode() + public static async Task GetProjectByNameAsync(string projectName) { try { - if (!Settings.CacheContent) - RefreshContentInMemory(); + return await ChatDB.GetCollection(Settings.ProjectsCollectionName).Find(x => x.Name == projectName).SingleOrDefaultAsync(); + } + catch (Exception ex) + { + Logger.LogError(new EventId((int)LoggerEventId.MONGO_HELPER_ERROR), ex, "GetProjectAsync: {0}", ex.Message); + return null; + } + } - var nodeTemplateCollection = ChatDB.GetCollection(Settings.TemplateCollectionName); + public static List SaveProjects(List projects) + { + try + { + var coll = ChatDB.GetCollection(Settings.ProjectsCollectionName); - // Retrieving records, if no/invalid limit is specified then all records are retrieved otherwise records as per specified limit and offset are retrieved - var nodeList = nodeTemplateCollection.Find(new BsonDocument()).Project(Builders.Projection.Exclude("Sections._t").Exclude("Buttons._t")).ToList(); + projects = projects.Where(x => x != null).ToList(); - var chatNodes = new ConcurrentBag(); - Parallel.ForEach(nodeList, node => + Parallel.ForEach(projects, async proj => { try { - var chatNode = BsonSerializer.Deserialize(node); - - chatNode.Sections = new List
(); - chatNode.Buttons = new List