From ca6f60695db2f6e74b61cd729d5773efa804d756 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Sat, 2 Sep 2023 23:11:53 -0500 Subject: [PATCH] add routing item and profile --- .../Agents/Models/Agent.cs | 4 +- .../Repositories/IBotSharpRepository.cs | 6 ++ .../Repositories/Records/RoutingItemRecord.cs | 16 +++++- .../Records/RoutingProfileRecord.cs | 20 +++++++ .../Routing/IRoutingService.cs | 11 ++++ .../Routing/Models/RoutingItem.cs | 2 +- .../BotSharpServiceCollectionExtensions.cs | 3 + .../Repository/BotSharpDbContext.cs | 20 +++++++ .../Repository/FileRepository.cs | 24 +++++++- .../Routing/Services/RoutingService.cs | 45 +++++++++++++++ .../Controllers/RoutingController.cs | 46 +++++++++++++++ .../ViewModels/Agents/AgentCreationModel.cs | 2 + .../Routing/RoutingItemCreationModel.cs | 26 +++++++++ .../Routing/RoutingItemViewModel.cs | 26 +++++++++ .../Routing/RoutingProfileCreationModel.cs | 18 ++++++ .../Routing/RoutingProfileViewModel.cs | 18 ++++++ .../Collections/RoutingItemCollection.cs | 2 +- .../Repository/MongoRepository.cs | 56 +++++++++++++++++++ 18 files changed, 337 insertions(+), 8 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs create mode 100644 src/Infrastructure/BotSharp.Core/Routing/Services/RoutingService.cs create mode 100644 src/Infrastructure/BotSharp.OpenAPI/Controllers/RoutingController.cs create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemCreationModel.cs create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemViewModel.cs create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileCreationModel.cs create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileViewModel.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs index 2f1f1e6e..b9944764 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs @@ -44,13 +44,13 @@ public class Agent public Agent SetFunctions(List functions) { - Functions = functions; + Functions = functions ?? new List(); return this; } public Agent SetResponses(List responses) { - Responses = responses; + Responses = responses ?? new List(); ; return this; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 4197a52b..cbace0c2 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Repositories.Records; +using BotSharp.Abstraction.Routing.Models; using System.Linq; namespace BotSharp.Abstraction.Repositories; @@ -18,4 +19,9 @@ public interface IBotSharpRepository UserRecord GetUserByEmail(string email); void CreateUser(UserRecord user); void UpdateAgent(AgentRecord agent); + + List CreateRoutingItems(List routingItems); + List CreateRoutingProfiles(List profiles); + void DeleteRoutingItems(); + void DeleteRoutingProfiles(); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingItemRecord.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingItemRecord.cs index d443f90f..77a535d5 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingItemRecord.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingItemRecord.cs @@ -8,13 +8,14 @@ public class RoutingItemRecord : RecordBase public string Name { get; set; } public string Description { get; set; } public List RequiredFields { get; set; } = new List(); - public string RedirectTo { get; set; } + public string? RedirectTo { get; set; } public bool Disabled { get; set; } public RoutingItem ToRoutingItem() { return new RoutingItem { + AgentId = AgentId, Name = Name, Description = Description, RequiredFields = RequiredFields, @@ -22,4 +23,17 @@ public class RoutingItemRecord : RecordBase Disabled = Disabled }; } + + public static RoutingItemRecord FromRoutingItem(RoutingItem item) + { + return new RoutingItemRecord + { + AgentId = item.AgentId, + Name = item.Name, + Description = item.Description, + RequiredFields = item.RequiredFields, + RedirectTo = item.RedirectTo, + Disabled = item.Disabled + }; + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingProfileRecord.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingProfileRecord.cs index d54c4c40..ef8242cb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingProfileRecord.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Records/RoutingProfileRecord.cs @@ -1,7 +1,27 @@ +using BotSharp.Abstraction.Routing.Models; + namespace BotSharp.Abstraction.Repositories.Records; public class RoutingProfileRecord : RecordBase { public string Name { get; set; } public List AgentIds { get; set; } + + public RoutingProfile ToRoutingProfile() + { + return new RoutingProfile + { + Name = Name, + AgentIds = AgentIds.ToArray(), + }; + } + + public static RoutingProfileRecord FromRoutingProfile(RoutingProfile profile) + { + return new RoutingProfileRecord + { + Name = profile.Name, + AgentIds = profile.AgentIds.ToList(), + }; + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs new file mode 100644 index 00000000..e65bf0d5 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -0,0 +1,11 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.Abstraction.Routing; + +public interface IRoutingService +{ + Task> CreateRoutingItems(List routingItems); + Task> CreateRoutingProfiles(List routingProfiles); + Task DeleteRoutingItems(); + Task DeleteRoutingProfiles(); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs index 3295e70b..1515a05e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingItem.cs @@ -17,7 +17,7 @@ public class RoutingItem public List RequiredFields { get; set; } = new List(); [JsonPropertyName("redirect_to")] - public string RedirectTo { get; set; } + public string? RedirectTo { get; set; } [JsonPropertyName("disabled")] public bool Disabled { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs index 853205ef..0aa9d850 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs @@ -10,6 +10,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using BotSharp.Abstraction.Routing.Settings; using BotSharp.Abstraction.Templating; +using BotSharp.Abstraction.Routing; +using BotSharp.Core.Routing.Services; namespace BotSharp.Core; @@ -20,6 +22,7 @@ public static class BotSharpServiceCollectionExtensions services.AddScoped(); services.AddScoped(); + services.AddScoped(); var agentSettings = new AgentSettings(); config.Bind("Agent", agentSettings); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 26810f84..d1600b04 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -76,4 +76,24 @@ public class BotSharpDbContext : Database, IBotSharpRepository throw ex2; } } + + public void DeleteRoutingItems() + { + throw new NotImplementedException(); + } + + public void DeleteRoutingProfiles() + { + throw new NotImplementedException(); + } + + public List CreateRoutingItems(List routingItems) + { + throw new NotImplementedException(); + } + + public List CreateRoutingProfiles(List profiles) + { + throw new NotImplementedException(); + } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index c9c88ff9..e9c657c9 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -1,10 +1,8 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Repositories.Records; -using BotSharp.Abstraction.Routing.Models; -using SharpCompress.Common; using System.IO; -using System.Text.Json; + namespace BotSharp.Core.Repository; public class FileRepository : IBotSharpRepository @@ -324,4 +322,24 @@ public class FileRepository : IBotSharpRepository } return dir; } + + public void DeleteRoutingItems() + { + throw new NotImplementedException(); + } + + public void DeleteRoutingProfiles() + { + throw new NotImplementedException(); + } + + public List CreateRoutingItems(List routingItems) + { + throw new NotImplementedException(); + } + + public List CreateRoutingProfiles(List profiles) + { + throw new NotImplementedException(); + } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Services/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/Services/RoutingService.cs new file mode 100644 index 00000000..6087e1c9 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Services/RoutingService.cs @@ -0,0 +1,45 @@ +using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Repositories.Records; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.Core.Routing.Services; + +public class RoutingService : IRoutingService +{ + private readonly IServiceProvider _services; + + public RoutingService(IServiceProvider service) + { + _services = service; + } + public async Task> CreateRoutingItems(List routingItems) + { + var db = _services.GetRequiredService(); + var items = routingItems?.Select(x => RoutingItemRecord.FromRoutingItem(x))?.ToList() ?? new List(); + var savedItems = db.CreateRoutingItems(items); + return await Task.FromResult(savedItems.Select(x => x.ToRoutingItem()).ToList()); + } + + public async Task> CreateRoutingProfiles(List routingProfiles) + { + var db = _services.GetRequiredService(); + var profiles = routingProfiles?.Select(x => RoutingProfileRecord.FromRoutingProfile(x))?.ToList() ?? new List(); + var savedProfiles = db.CreateRoutingProfiles(profiles); + return await Task.FromResult(savedProfiles.Select(x => x.ToRoutingProfile()).ToList()); + } + + public async Task DeleteRoutingItems() + { + var db = _services.GetRequiredService(); + db.DeleteRoutingItems(); + await Task.CompletedTask; + } + + public async Task DeleteRoutingProfiles() + { + var db = _services.GetRequiredService(); + db.DeleteRoutingProfiles(); + await Task.CompletedTask; + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RoutingController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RoutingController.cs new file mode 100644 index 00000000..bdcb529f --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RoutingController.cs @@ -0,0 +1,46 @@ +using BotSharp.Abstraction.ApiAdapters; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Models; +using BotSharp.OpenAPI.ViewModels.Routing; +using NetTopologySuite.Index.HPRtree; + +namespace BotSharp.OpenAPI.Controllers; + +[Authorize] +[ApiController] +public class RoutingController : ControllerBase, IApiAdapter +{ + private readonly IRoutingService _routingService; + public RoutingController(IRoutingService routingService) + { + _routingService = routingService; + } + + [HttpPost("/routing-items")] + public async Task> CreateRoutingItems(List routingItems) + { + var items = routingItems?.Select(x => x.ToRoutingItem())?.ToList() ?? new List(); + var savedItems = await _routingService.CreateRoutingItems(items); + return savedItems.Select(x => RoutingItemViewModel.FromRoutingItem(x)).ToList(); + } + + [HttpPost("/routing-profiles")] + public async Task> CreateRoutingProfiles(List routingProfiles) + { + var profiles = routingProfiles?.Select(x => x.ToRoutingProfile())?.ToList() ?? new List(); + var savedProfiles = await _routingService.CreateRoutingProfiles(profiles); + return savedProfiles.Select(x => RoutingProfileViewModel.FromRoutingProfile(x)).ToList(); + } + + [HttpDelete("/routing-items")] + public async Task RemoveRoutingItems() + { + await _routingService.DeleteRoutingItems(); + } + + [HttpDelete("/routing-profiles")] + public async Task RemoveRoutingProfiles() + { + await _routingService.DeleteRoutingProfiles(); + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs index 0053adfd..af66f5d1 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs @@ -8,6 +8,7 @@ public class AgentCreationModel public string Description { get; set; } public string Instruction { get; set; } public List Functions { get; set; } + public List Responses { get; set; } public Agent ToAgent() { @@ -17,6 +18,7 @@ public class AgentCreationModel Description = Description, Instruction = Instruction, Functions = Functions, + Responses = Responses }; } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemCreationModel.cs new file mode 100644 index 00000000..941b7332 --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemCreationModel.cs @@ -0,0 +1,26 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.OpenAPI.ViewModels.Routing; + +public class RoutingItemCreationModel +{ + public string AgentId { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public List RequiredFields { get; set; } = new List(); + public string? RedirectTo { get; set; } + public bool Disabled { get; set; } + + public RoutingItem ToRoutingItem() + { + return new RoutingItem + { + AgentId = AgentId, + Name = Name, + Description = Description, + RequiredFields = RequiredFields, + RedirectTo = RedirectTo, + Disabled = Disabled + }; + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemViewModel.cs new file mode 100644 index 00000000..a91169d8 --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingItemViewModel.cs @@ -0,0 +1,26 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.OpenAPI.ViewModels.Routing; + +public class RoutingItemViewModel +{ + public string AgentId { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public List RequiredFields { get; set; } = new List(); + public string? RedirectTo { get; set; } + public bool Disabled { get; set; } + + public static RoutingItemViewModel FromRoutingItem(RoutingItem routingItem) + { + return new RoutingItemViewModel + { + AgentId = routingItem.AgentId, + Name = routingItem.Name, + Description = routingItem.Description, + RequiredFields = routingItem.RequiredFields, + RedirectTo = routingItem.RedirectTo, + Disabled = routingItem.Disabled + }; + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileCreationModel.cs new file mode 100644 index 00000000..4ea86c9c --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileCreationModel.cs @@ -0,0 +1,18 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.OpenAPI.ViewModels.Routing; + +public class RoutingProfileCreationModel +{ + public string Name { get; set; } + public string[] AgentIds { get; set; } + + public RoutingProfile ToRoutingProfile() + { + return new RoutingProfile + { + Name = Name, + AgentIds = AgentIds, + }; + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileViewModel.cs new file mode 100644 index 00000000..4f8f7237 --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Routing/RoutingProfileViewModel.cs @@ -0,0 +1,18 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.OpenAPI.ViewModels.Routing; + +public class RoutingProfileViewModel +{ + public string Name { get; set; } + public string[] AgentIds { get; set; } + + public static RoutingProfileViewModel FromRoutingProfile(RoutingProfile profile) + { + return new RoutingProfileViewModel + { + Name = profile.Name, + AgentIds = profile.AgentIds, + }; + } +} diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs index deab7774..63208306 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs @@ -6,6 +6,6 @@ public class RoutingItemCollection : MongoBase public string Name { get; set; } public string Description { get; set; } public List RequiredFields { get; set; } - public Guid RedirectTo { get; set; } + public Guid? RedirectTo { get; set; } public bool Disabled { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index fa0d67c7..657d7bb7 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Users.Models; using BotSharp.Plugin.MongoStorage.Collections; namespace BotSharp.Plugin.MongoStorage.Repository; @@ -381,4 +383,58 @@ public class MongoRepository : IBotSharpRepository _dc.Agents.UpdateOne(filter, update, _options); } + + public void DeleteRoutingItems() + { + _dc.RoutingItems.DeleteMany(Builders.Filter.Empty); + } + + public void DeleteRoutingProfiles() + { + _dc.RoutingProfiles.DeleteMany(Builders.Filter.Empty); + } + + public List CreateRoutingItems(List routingItems) + { + var collections = routingItems?.Select(x => new RoutingItemCollection + { + Id = Guid.NewGuid(), + AgentId = Guid.Parse(x.AgentId), + Name = x.Name, + Description = x.Description, + RequiredFields = x.RequiredFields, + RedirectTo = !string.IsNullOrEmpty(x.RedirectTo) ? Guid.Parse(x.RedirectTo) : null, + Disabled = x.Disabled + })?.ToList() ?? new List(); + + _dc.RoutingItems.InsertMany(collections); + return collections.Select(x => new RoutingItemRecord + { + Id = x.Id.ToString(), + AgentId = x.AgentId.ToString(), + Name = x.Name, + Description = x.Description, + RequiredFields = x.RequiredFields, + RedirectTo = x.RedirectTo?.ToString(), + Disabled = x.Disabled + }).ToList(); + } + + public List CreateRoutingProfiles(List profiles) + { + var collections = profiles?.Select(x => new RoutingProfileCollection + { + Id = Guid.NewGuid(), + Name = x.Name, + AgentIds = x.AgentIds.Select(x => Guid.Parse(x)).ToList() + })?.ToList() ?? new List(); + + _dc.RoutingProfiles.InsertMany(collections); + return collections.Select(x => new RoutingProfileRecord + { + Id = x.Id.ToString(), + Name = x.Name, + AgentIds = x.AgentIds.Select(x => x.ToString()).ToList() + }).ToList(); + } }