add role
This commit is contained in:
parent
9a954d8551
commit
dda5c2a211
|
|
@ -14,6 +14,9 @@ public class UserFilter : Pagination
|
|||
[JsonPropertyName("roles")]
|
||||
public IEnumerable<string>? Roles { get; set; }
|
||||
|
||||
[JsonPropertyName("types")]
|
||||
public IEnumerable<string>? Types { get; set; }
|
||||
|
||||
[JsonPropertyName("sources")]
|
||||
public IEnumerable<string>? Sources { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ public interface IBotSharpRepository : IHaveServiceProvider
|
|||
#endregion
|
||||
|
||||
#region Role
|
||||
bool RefreshRoles(IEnumerable<Role> roles) => throw new NotImplementedException();
|
||||
IEnumerable<Role> GetRoles(RoleFilter filter) => throw new NotImplementedException();
|
||||
Role? GetRoleDetails(string roleId) => throw new NotImplementedException();
|
||||
bool UpdateRole(Role role, bool isUpdateRoleAgents = false) => throw new NotImplementedException();
|
||||
Role? GetRoleDetails(string roleId, bool includeAgent = false) => throw new NotImplementedException();
|
||||
bool UpdateRole(Role role, bool updateRoleAgents = false) => throw new NotImplementedException();
|
||||
#endregion
|
||||
|
||||
#region User
|
||||
|
|
@ -41,8 +42,8 @@ public interface IBotSharpRepository : IHaveServiceProvider
|
|||
void UpdateUserIsDisable(string userId, bool isDisable) => throw new NotImplementedException();
|
||||
void UpdateUsersIsDisable(List<string> userIds, bool isDisable) => throw new NotImplementedException();
|
||||
PagedItems<User> GetUsers(UserFilter filter) => throw new NotImplementedException();
|
||||
User? GetUserDetails(string userId) => throw new NotImplementedException();
|
||||
bool UpdateUser(User user, bool isUpdateUserAgents = false) => throw new NotImplementedException();
|
||||
User? GetUserDetails(string userId, bool includeAgent = false) => throw new NotImplementedException();
|
||||
bool UpdateUser(User user, bool updateUserAgents = false) => throw new NotImplementedException();
|
||||
#endregion
|
||||
|
||||
#region Agent
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace BotSharp.Abstraction.Roles;
|
|||
|
||||
public interface IRoleService
|
||||
{
|
||||
Task<bool> RefreshRoles();
|
||||
Task<IEnumerable<string>> GetRoleOptions();
|
||||
Task<IEnumerable<Role>> GetRoles(RoleFilter filter);
|
||||
Task<Role?> GetRoleDetails(string roleId);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public class Role
|
|||
public IEnumerable<RoleAgentAction> AgentActions { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("updated_time")]
|
||||
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
[JsonPropertyName("created_time")]
|
||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||
public DateTime CreatedTime { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ public class RoleAgent
|
|||
public Agent? Agent { get; set; }
|
||||
|
||||
[JsonPropertyName("updated_time")]
|
||||
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
[JsonPropertyName("created_time")]
|
||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||
public DateTime CreatedTime { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@ public static class UserAction
|
|||
{
|
||||
public const string Edit = "edit";
|
||||
public const string Chat = "chat";
|
||||
public const string Train = "train";
|
||||
public const string Evaluate = "evaluate";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,21 +2,23 @@ namespace BotSharp.Abstraction.Users.Enums;
|
|||
|
||||
public class UserRole
|
||||
{
|
||||
public const string Root = "root";
|
||||
|
||||
/// <summary>
|
||||
/// Admin account
|
||||
/// </summary>
|
||||
public const string Admin = "admin";
|
||||
|
||||
/// <summary>
|
||||
/// Customer service representative (CSR)
|
||||
/// </summary>
|
||||
public const string CSR = "csr";
|
||||
|
||||
/// <summary>
|
||||
/// Authorized user
|
||||
/// </summary>
|
||||
public const string User = "user";
|
||||
|
||||
/// <summary>
|
||||
/// Customer service representative (CSR)
|
||||
/// </summary>
|
||||
public const string CSR = "csr";
|
||||
|
||||
/// <summary>
|
||||
/// Back office operations
|
||||
/// </summary>
|
||||
|
|
@ -33,6 +35,4 @@ public class UserRole
|
|||
/// AI Assistant
|
||||
/// </summary>
|
||||
public const string Assistant = "assistant";
|
||||
|
||||
public const string Root = "root";
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ public interface IUserService
|
|||
Task<User> GetUser(string id);
|
||||
Task<PagedItems<User>> GetUsers(UserFilter filter);
|
||||
Task<User?> GetUserDetails(string userId);
|
||||
Task<bool> IsAuthorizedUser(string userId);
|
||||
Task<UserAuthorization> GetUserAuthorizations(string? agentId = null);
|
||||
Task<bool> UpdateUser(User user, bool isUpdateUserAgents = false);
|
||||
Task<User> CreateUser(User user);
|
||||
Task<Token> ActiveUser(UserActivationModel model);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
namespace BotSharp.Abstraction.Users.Models;
|
||||
|
||||
public class UserAuthorization
|
||||
{
|
||||
public bool IsAdmin { get; set; }
|
||||
public IEnumerable<string> Permissions { get; set; } = [];
|
||||
public IEnumerable<string> AgentActions { get; set; } = [];
|
||||
}
|
||||
|
|
@ -25,8 +25,11 @@ public partial class AgentService
|
|||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||
|
||||
var user = _db.GetUserById(_user.Id);
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var auth = await userService.GetUserAuthorizations();
|
||||
|
||||
_db.BulkInsertAgents(new List<Agent> { agentRecord });
|
||||
if (!UserConstant.AdminRoles.Contains(user.Role))
|
||||
if (auth.IsAdmin || auth.Permissions.Contains(UserPermission.CreateAgent))
|
||||
{
|
||||
_db.BulkInsertUserAgents(new List<UserAgent>
|
||||
{
|
||||
|
|
@ -34,7 +37,7 @@ public partial class AgentService
|
|||
{
|
||||
UserId = user.Id,
|
||||
AgentId = agentRecord.Id,
|
||||
Actions = new List<string> { UserAction.Edit, UserAction.Chat },
|
||||
Actions = new List<string> { UserAction.Edit, UserAction.Train, UserAction.Evaluate, UserAction.Chat },
|
||||
CreatedTime = DateTime.UtcNow,
|
||||
UpdatedTime = DateTime.UtcNow
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ public partial class AgentService
|
|||
{
|
||||
public async Task<bool> DeleteAgent(string id)
|
||||
{
|
||||
var user = _db.GetUserById(_user.Id);
|
||||
var userAgents = await GetUserAgents(user?.Id);
|
||||
var found = userAgents?.FirstOrDefault(x => x.AgentId == id);
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var auth = await userService.GetUserAuthorizations(id);
|
||||
|
||||
if (!UserConstant.AdminRoles.Contains(user?.Role) && (found?.Actions == null || !found.Actions.Contains(UserAction.Edit)))
|
||||
if (auth.IsAdmin || auth.AgentActions.Contains(UserAction.Edit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ public partial class AgentService
|
|||
return refreshResult;
|
||||
}
|
||||
|
||||
var user = _db.GetUserById(_user.Id);
|
||||
if (!UserConstant.AdminRoles.Contains(user.Role))
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var isValid = await userService.IsAuthorizedUser(_user.Id);
|
||||
if (!isValid)
|
||||
{
|
||||
return "Unauthorized user.";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,9 @@ public partial class AgentService
|
|||
if (agent == null || string.IsNullOrEmpty(agent.Id)) return;
|
||||
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
var auth = await userService.GetUserAuthorizations(agent.Id);
|
||||
|
||||
var userAgents = await GetUserAgents(user.Id);
|
||||
var found = userAgents?.FirstOrDefault(x => x.AgentId == agent.Id);
|
||||
|
||||
if (!UserConstant.AdminRoles.Contains(user?.Role) && (found?.Actions == null || found.Actions.Contains(UserAction.Edit)))
|
||||
if (!auth.IsAdmin && !auth.AgentActions.Contains(UserAction.Edit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using BotSharp.Abstraction.Users.Settings;
|
|||
using BotSharp.Abstraction.Interpreters.Settings;
|
||||
using BotSharp.Abstraction.Infrastructures;
|
||||
using BotSharp.Core.Processors;
|
||||
using BotSharp.Core.Roles.Services;
|
||||
|
||||
namespace BotSharp.Core;
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ public static class BotSharpCoreExtensions
|
|||
services.AddSingleton<DistributedLocker>();
|
||||
|
||||
services.AddScoped<ISettingService, SettingService>();
|
||||
services.AddScoped<IRoleService, RoleService>();
|
||||
services.AddScoped<IUserService, UserService>();
|
||||
services.AddScoped<ProcessorFactory>();
|
||||
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ namespace BotSharp.Core.Repository
|
|||
var agentDir = GetAgentDataDir(agentId);
|
||||
if (string.IsNullOrEmpty(agentDir)) return false;
|
||||
|
||||
// Delete agent user relationships
|
||||
// Delete user agents
|
||||
var usersDir = Path.Combine(_dbSettings.FileRepository, USERS_FOLDER);
|
||||
if (Directory.Exists(usersDir))
|
||||
{
|
||||
|
|
@ -546,6 +546,24 @@ namespace BotSharp.Core.Repository
|
|||
}
|
||||
}
|
||||
|
||||
// Delete role agents
|
||||
var rolesDir = Path.Combine(_dbSettings.FileRepository, ROLES_FOLDER);
|
||||
if (Directory.Exists(rolesDir))
|
||||
{
|
||||
foreach (var roleDir in Directory.GetDirectories(rolesDir))
|
||||
{
|
||||
var roleAgentFile = Directory.GetFiles(roleDir).FirstOrDefault(x => Path.GetFileName(x) == ROLE_AGENT_FILE);
|
||||
if (string.IsNullOrEmpty(roleAgentFile)) continue;
|
||||
|
||||
var text = File.ReadAllText(roleAgentFile);
|
||||
var roleAgents = JsonSerializer.Deserialize<List<RoleAgent>>(text, _options);
|
||||
if (roleAgents.IsNullOrEmpty()) continue;
|
||||
|
||||
roleAgents = roleAgents?.Where(x => x.AgentId != agentId)?.ToList() ?? [];
|
||||
File.WriteAllText(roleAgentFile, JsonSerializer.Serialize(roleAgents, _options));
|
||||
}
|
||||
}
|
||||
|
||||
// Delete agent folder
|
||||
Directory.Delete(agentDir, true);
|
||||
Reset();
|
||||
|
|
@ -561,6 +579,7 @@ namespace BotSharp.Core.Repository
|
|||
{
|
||||
_agents = [];
|
||||
_userAgents = [];
|
||||
_roleAgents = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,39 @@
|
|||
using BotSharp.Abstraction.Users.Models;
|
||||
using System.IO;
|
||||
|
||||
namespace BotSharp.Core.Repository;
|
||||
|
||||
public partial class FileRepository
|
||||
{
|
||||
public bool RefreshRoles(IEnumerable<Role> roles)
|
||||
{
|
||||
if (roles.IsNullOrEmpty()) return false;
|
||||
|
||||
var validRoles = roles.Where(x => !string.IsNullOrWhiteSpace(x.Id)
|
||||
&& !string.IsNullOrWhiteSpace(x.Name)).ToList();
|
||||
if (validRoles.IsNullOrEmpty()) return false;
|
||||
|
||||
var baseDir = Path.Combine(_dbSettings.FileRepository, ROLES_FOLDER);
|
||||
if (Directory.Exists(baseDir))
|
||||
{
|
||||
Directory.Delete(baseDir, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(baseDir);
|
||||
|
||||
foreach (var role in validRoles)
|
||||
{
|
||||
var dir = Path.Combine(baseDir, role.Id);
|
||||
Directory.CreateDirectory(dir);
|
||||
Thread.Sleep(50);
|
||||
var roleFile = Path.Combine(dir, ROLE_FILE);
|
||||
role.CreatedTime = DateTime.UtcNow;
|
||||
role.UpdatedTime = DateTime.UtcNow;
|
||||
File.WriteAllText(roleFile, JsonSerializer.Serialize(role, _options));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<Role> GetRoles(RoleFilter filter)
|
||||
{
|
||||
var roles = Roles;
|
||||
|
|
@ -22,7 +51,7 @@ public partial class FileRepository
|
|||
return roles.ToList();
|
||||
}
|
||||
|
||||
public Role? GetRoleDetails(string roleId)
|
||||
public Role? GetRoleDetails(string roleId, bool includeAgent = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleId)) return null;
|
||||
|
||||
|
|
@ -31,8 +60,20 @@ public partial class FileRepository
|
|||
|
||||
var agentActions = new List<RoleAgentAction>();
|
||||
var roleAgents = RoleAgents?.Where(x => x.RoleId == roleId)?.ToList() ?? [];
|
||||
var agentIds = roleAgents.Select(x => x.AgentId).Distinct().ToList();
|
||||
|
||||
if (!includeAgent)
|
||||
{
|
||||
agentActions = roleAgents.Select(x => new RoleAgentAction
|
||||
{
|
||||
Id = x.Id,
|
||||
AgentId = x.AgentId,
|
||||
Actions = x.Actions
|
||||
}).ToList();
|
||||
role.AgentActions = agentActions;
|
||||
return role;
|
||||
}
|
||||
|
||||
var agentIds = roleAgents.Select(x => x.AgentId).Distinct().ToList();
|
||||
if (!agentIds.IsNullOrEmpty())
|
||||
{
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
|
|
@ -56,7 +97,7 @@ public partial class FileRepository
|
|||
return role;
|
||||
}
|
||||
|
||||
public bool UpdateRole(Role role, bool isUpdateRoleAgents = false)
|
||||
public bool UpdateRole(Role role, bool updateRoleAgents = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(role?.Id) || string.IsNullOrEmpty(role?.Name))
|
||||
{
|
||||
|
|
@ -74,7 +115,7 @@ public partial class FileRepository
|
|||
role.UpdatedTime = DateTime.UtcNow;
|
||||
File.WriteAllText(roleFile, JsonSerializer.Serialize(role, _options));
|
||||
|
||||
if (isUpdateRoleAgents)
|
||||
if (updateRoleAgents)
|
||||
{
|
||||
var roleAgents = role.AgentActions?.Select(x => new RoleAgent
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using BotSharp.Abstraction.Agents.Models;
|
||||
using BotSharp.Abstraction.Users.Enums;
|
||||
using BotSharp.Abstraction.Users.Models;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BotSharp.Core.Repository;
|
||||
|
|
@ -97,6 +95,10 @@ public partial class FileRepository
|
|||
{
|
||||
users = users.Where(x => filter.Roles.Contains(x.Role));
|
||||
}
|
||||
if (!filter.Types.IsNullOrEmpty())
|
||||
{
|
||||
users = users.Where(x => filter.Types.Contains(x.Type));
|
||||
}
|
||||
if (!filter.Sources.IsNullOrEmpty())
|
||||
{
|
||||
users = users.Where(x => filter.Sources.Contains(x.Source));
|
||||
|
|
@ -109,17 +111,29 @@ public partial class FileRepository
|
|||
};
|
||||
}
|
||||
|
||||
public User? GetUserDetails(string userId)
|
||||
public User? GetUserDetails(string userId, bool includeAgent = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userId)) return null;
|
||||
|
||||
var user = Users.FirstOrDefault(x => x.Id == userId);
|
||||
var user = Users.FirstOrDefault(x => x.Id == userId || x.ExternalId == userId);
|
||||
if (user == null) return null;
|
||||
|
||||
var agentActions = new List<UserAgentAction>();
|
||||
var userAgents = UserAgents?.Where(x => x.UserId == userId)?.ToList() ?? [];
|
||||
var agentIds = userAgents.Select(x => x.AgentId)?.Distinct().ToList();
|
||||
|
||||
if (!includeAgent)
|
||||
{
|
||||
agentActions = userAgents.Select(x => new UserAgentAction
|
||||
{
|
||||
Id = x.Id,
|
||||
AgentId = x.AgentId,
|
||||
Actions = x.Actions
|
||||
}).ToList();
|
||||
user.AgentActions = agentActions;
|
||||
return user;
|
||||
}
|
||||
|
||||
var agentIds = userAgents.Select(x => x.AgentId)?.Distinct().ToList();
|
||||
if (!agentIds.IsNullOrEmpty())
|
||||
{
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
|
|
@ -143,7 +157,7 @@ public partial class FileRepository
|
|||
return user;
|
||||
}
|
||||
|
||||
public bool UpdateUser(User user, bool isUpdateUserAgents = false)
|
||||
public bool UpdateUser(User user, bool updateUserAgents = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(user?.Id)) return false;
|
||||
|
||||
|
|
@ -157,7 +171,7 @@ public partial class FileRepository
|
|||
user.UpdatedTime = DateTime.UtcNow;
|
||||
File.WriteAllText(userFile, JsonSerializer.Serialize(user, _options));
|
||||
|
||||
if (isUpdateUserAgents)
|
||||
if (updateUserAgents)
|
||||
{
|
||||
var userAgents = user.AgentActions?.Select(x => new UserAgent
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ public class RoleService : IRoleService
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<bool> RefreshRoles()
|
||||
{
|
||||
var allRoles = await GetRoleOptions();
|
||||
var roles = allRoles.Select(x => new Role { Id = Guid.NewGuid().ToString(), Name = x }).ToList();
|
||||
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
return db.RefreshRoles(roles);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetRoleOptions()
|
||||
{
|
||||
var fields = typeof(UserRole).GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||
|
|
@ -37,7 +46,7 @@ public class RoleService : IRoleService
|
|||
public async Task<Role?> GetRoleDetails(string roleId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var role = db.GetRoleDetails(roleId);
|
||||
var role = db.GetRoleDetails(roleId, includeAgent: true);
|
||||
return role;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -407,10 +407,54 @@ public class UserService : IUserService
|
|||
return users;
|
||||
}
|
||||
|
||||
public async Task<bool> IsAuthorizedUser(string userId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var user = db.GetUserById(userId);
|
||||
return user != null && UserConstant.AdminRoles.Contains(user.Role);
|
||||
}
|
||||
|
||||
public async Task<UserAuthorization> GetUserAuthorizations(string? agentId = null)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
var user = db.GetUserById(_user.Id);
|
||||
var auth = new UserAuthorization();
|
||||
|
||||
if (user == null) return auth;
|
||||
|
||||
var permissions = user.Permissions;
|
||||
|
||||
var role = db.GetRoles(new RoleFilter { Names = [ user.Role ] }).FirstOrDefault();
|
||||
if (role != null && !permissions.Any())
|
||||
{
|
||||
permissions = role.Permissions ?? [];
|
||||
}
|
||||
|
||||
auth.IsAdmin = UserConstant.AdminRoles.Contains(user.Role);
|
||||
auth.Permissions = permissions;
|
||||
|
||||
if (string.IsNullOrEmpty(agentId))
|
||||
{
|
||||
return auth;
|
||||
}
|
||||
|
||||
var userAgent = db.GetUserDetails(user.Id)?.AgentActions?.FirstOrDefault(x => x.AgentId == agentId);
|
||||
var actions = userAgent?.Actions ?? [];
|
||||
|
||||
if (role != null && !actions.Any())
|
||||
{
|
||||
var roleAgent = db.GetRoleDetails(role.Id)?.AgentActions?.FirstOrDefault(x => x.AgentId == agentId);
|
||||
actions = roleAgent?.Actions ?? [];
|
||||
}
|
||||
|
||||
auth.AgentActions = actions;
|
||||
return auth;
|
||||
}
|
||||
|
||||
public async Task<User?> GetUserDetails(string userId)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
return db.GetUserDetails(userId);
|
||||
return db.GetUserDetails(userId, includeAgent: true);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateUser(User user, bool isUpdateUserAgents = false)
|
||||
|
|
|
|||
|
|
@ -58,20 +58,11 @@ public class AgentController : ControllerBase
|
|||
rule.RedirectToAgentName = found.Name;
|
||||
}
|
||||
|
||||
var editable = true;
|
||||
var chatable = true;
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
if (!UserConstant.AdminRoles.Contains(user?.Role))
|
||||
{
|
||||
var userAgents = await _agentService.GetUserAgents(user?.Id);
|
||||
var actions = userAgents?.FirstOrDefault(x => x.AgentId == targetAgent.Id)?.Actions ?? [];
|
||||
editable = actions.Contains(UserAction.Edit);
|
||||
chatable = actions.Contains(UserAction.Chat);
|
||||
}
|
||||
var auth = await userService.GetUserAuthorizations(targetAgent.Id);
|
||||
|
||||
targetAgent.Editable = editable;
|
||||
targetAgent.Chatable = chatable;
|
||||
targetAgent.Editable = auth.IsAdmin || auth.AgentActions.Contains(UserAction.Edit);
|
||||
targetAgent.Chatable = auth.IsAdmin || auth.AgentActions.Contains(UserAction.Chat);
|
||||
return targetAgent;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,8 @@ public class PluginController : ControllerBase
|
|||
[HttpGet("/plugins")]
|
||||
public async Task<PagedItems<PluginDef>> GetPlugins([FromQuery] PluginFilter filter)
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
if (!UserConstant.AdminRoles.Contains(user?.Role))
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return new PagedItems<PluginDef>();
|
||||
}
|
||||
|
|
@ -55,7 +54,11 @@ public class PluginController : ControllerBase
|
|||
{
|
||||
Roles = new List<string> { UserRole.Root, UserRole.Admin }
|
||||
},
|
||||
new PluginMenuDef("Users", link: "page/users", icon: "bx bx-user", weight: 33)
|
||||
new PluginMenuDef("Roles", link: "page/roles", icon: "bx bx-group", weight: 33)
|
||||
{
|
||||
Roles = new List<string> { UserRole.Root, UserRole.Admin }
|
||||
},
|
||||
new PluginMenuDef("Users", link: "page/users", icon: "bx bx-user", weight: 34)
|
||||
{
|
||||
Roles = new List<string> { UserRole.Root, UserRole.Admin }
|
||||
}
|
||||
|
|
@ -91,4 +94,10 @@ public class PluginController : ControllerBase
|
|||
var loader = _services.GetRequiredService<PluginLoader>();
|
||||
return loader.UpdatePluginStatus(_services, id, false);
|
||||
}
|
||||
|
||||
private async Task<bool> IsValidUser()
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
return await userService.IsAuthorizedUser(_user.Id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,19 @@ public class RoleController : ControllerBase
|
|||
_user = user;
|
||||
}
|
||||
|
||||
[HttpPost("/role/refresh")]
|
||||
public async Task<bool> RefreshRoles()
|
||||
{
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return await _roleService.RefreshRoles();
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("/role/options")]
|
||||
public async Task<IEnumerable<string>> GetRoleOptions()
|
||||
{
|
||||
|
|
@ -35,6 +48,12 @@ public class RoleController : ControllerBase
|
|||
filter = RoleFilter.Empty();
|
||||
}
|
||||
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return Enumerable.Empty<RoleViewModel>();
|
||||
}
|
||||
|
||||
var roles = await _roleService.GetRoles(filter);
|
||||
return roles.Select(x => RoleViewModel.FromRole(x)).ToList();
|
||||
}
|
||||
|
|
@ -51,9 +70,8 @@ public class RoleController : ControllerBase
|
|||
{
|
||||
if (model == null) return false;
|
||||
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
if (user == null || !UserConstant.AdminRoles.Contains(user.Role))
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -61,4 +79,10 @@ public class RoleController : ControllerBase
|
|||
var role = RoleUpdateModel.ToRole(model);
|
||||
return await _roleService.UpdateRole(role, isUpdateRoleAgents: true);
|
||||
}
|
||||
|
||||
private async Task<bool> IsValidUser()
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
return await userService.IsAuthorizedUser(_user.Id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ public class UserController : ControllerBase
|
|||
public async Task<PagedItems<UserViewModel>> GetUsers([FromBody] UserFilter filter)
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
if (user == null || !UserConstant.AdminRoles.Contains(user.Role))
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return new PagedItems<UserViewModel>();
|
||||
}
|
||||
|
|
@ -211,13 +211,13 @@ public class UserController : ControllerBase
|
|||
{
|
||||
if (model == null) return false;
|
||||
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var user = await userService.GetUser(_user.Id);
|
||||
if (user == null || !UserConstant.AdminRoles.Contains(user.Role))
|
||||
var isValid = await IsValidUser();
|
||||
if (!isValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
var updated = await userService.UpdateUser(UserUpdateModel.ToUser(model), isUpdateUserAgents: true);
|
||||
return updated;
|
||||
}
|
||||
|
|
@ -252,6 +252,12 @@ public class UserController : ControllerBase
|
|||
|
||||
|
||||
#region Private methods
|
||||
private async Task<bool> IsValidUser()
|
||||
{
|
||||
var userService = _services.GetRequiredService<IUserService>();
|
||||
return await userService.IsAuthorizedUser(_user.Id);
|
||||
}
|
||||
|
||||
private FileContentResult BuildFileResult(string file)
|
||||
{
|
||||
var fileStorage = _services.GetRequiredService<IFileStorageService>();
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ public class RoleViewModel
|
|||
public IEnumerable<RoleAgentActionViewModel> AgentActions { get; set; } = [];
|
||||
|
||||
[JsonPropertyName("create_date")]
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime? CreateDate { get; set; }
|
||||
|
||||
[JsonPropertyName("update_date")]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
public DateTime? UpdateDate { get; set; }
|
||||
|
||||
public static RoleViewModel FromRole(Role? role)
|
||||
{
|
||||
|
|
@ -33,8 +33,8 @@ public class RoleViewModel
|
|||
Name = role.Name,
|
||||
Permissions = role.Permissions,
|
||||
AgentActions = role.AgentActions?.Select(x => RoleAgentActionViewModel.ToViewModel(x)) ?? [],
|
||||
CreateDate = role.CreatedTime,
|
||||
UpdateDate = role.UpdatedTime
|
||||
CreateDate = role.CreatedTime != default ? role.CreatedTime : null,
|
||||
UpdateDate = role.UpdatedTime != default ? role.UpdatedTime : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
using BotSharp.Abstraction.Roles.Models;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Collections;
|
||||
|
||||
public class RoleAgentDocument : MongoBase
|
||||
{
|
||||
public string RoleId { get; set; }
|
||||
public string AgentId { get; set; }
|
||||
public IEnumerable<string> Actions { get; set; } = [];
|
||||
public DateTime CreatedTime { get; set; }
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
public RoleAgent ToRoleAgent()
|
||||
{
|
||||
return new RoleAgent
|
||||
{
|
||||
Id = Id,
|
||||
RoleId = RoleId,
|
||||
AgentId = AgentId,
|
||||
Actions = Actions,
|
||||
CreatedTime = CreatedTime,
|
||||
UpdatedTime = UpdatedTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using BotSharp.Abstraction.Roles.Models;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Collections;
|
||||
|
||||
public class RoleDocument : MongoBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<string> Permissions { get; set; } = [];
|
||||
public DateTime CreatedTime { get; set; }
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
|
||||
public Role ToRole()
|
||||
{
|
||||
return new Role
|
||||
{
|
||||
Id = Id,
|
||||
Name = Name,
|
||||
Permissions = Permissions,
|
||||
CreatedTime = CreatedTime,
|
||||
UpdatedTime = UpdatedTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -159,4 +159,10 @@ public class MongoDbContext
|
|||
|
||||
public IMongoCollection<KnowledgeCollectionFileMetaDocument> KnowledgeCollectionFileMeta
|
||||
=> Database.GetCollection<KnowledgeCollectionFileMetaDocument>($"{_collectionPrefix}_KnowledgeCollectionFileMeta");
|
||||
|
||||
public IMongoCollection<RoleDocument> Roles
|
||||
=> Database.GetCollection<RoleDocument>($"{_collectionPrefix}_Roles");
|
||||
|
||||
public IMongoCollection<RoleAgentDocument> RoleAgents
|
||||
=> Database.GetCollection<RoleAgentDocument>($"{_collectionPrefix}_RoleAgents");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Models;
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Routing.Models;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Repository;
|
||||
|
||||
|
|
@ -332,8 +333,6 @@ public partial class MongoRepository
|
|||
|
||||
if (found.IsNullOrEmpty()) return [];
|
||||
|
||||
var agentIds = found.Select(x => x.AgentId).Distinct().ToList();
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
var res = found.Select(x => new UserAgent
|
||||
{
|
||||
Id = x.Id,
|
||||
|
|
@ -344,6 +343,8 @@ public partial class MongoRepository
|
|||
UpdatedTime = x.UpdatedTime
|
||||
}).ToList();
|
||||
|
||||
var agentIds = found.Select(x => x.AgentId).Distinct().ToList();
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
foreach (var item in res)
|
||||
{
|
||||
var agent = agents.FirstOrDefault(x => x.Id == item.AgentId);
|
||||
|
|
@ -455,6 +456,7 @@ public partial class MongoRepository
|
|||
try
|
||||
{
|
||||
_dc.UserAgents.DeleteMany(Builders<UserAgentDocument>.Filter.Empty);
|
||||
_dc.RoleAgents.DeleteMany(Builders<RoleAgentDocument>.Filter.Empty);
|
||||
_dc.Agents.DeleteMany(Builders<AgentDocument>.Filter.Empty);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -472,10 +474,12 @@ public partial class MongoRepository
|
|||
|
||||
var agentFilter = Builders<AgentDocument>.Filter.Eq(x => x.Id, agentId);
|
||||
var userAgentFilter = Builders<UserAgentDocument>.Filter.Eq(x => x.AgentId, agentId);
|
||||
var roleAgentFilter = Builders<RoleAgentDocument>.Filter.Eq(x => x.AgentId, agentId);
|
||||
var agentTaskFilter = Builders<AgentTaskDocument>.Filter.Eq(x => x.AgentId, agentId);
|
||||
|
||||
_dc.Agents.DeleteOne(agentFilter);
|
||||
_dc.UserAgents.DeleteMany(userAgentFilter);
|
||||
_dc.RoleAgents.DeleteMany(roleAgentFilter);
|
||||
_dc.AgentTasks.DeleteMany(agentTaskFilter);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
using BotSharp.Abstraction.Repositories.Filters;
|
||||
using BotSharp.Abstraction.Roles.Models;
|
||||
|
||||
namespace BotSharp.Plugin.MongoStorage.Repository;
|
||||
|
||||
public partial class MongoRepository
|
||||
{
|
||||
public bool RefreshRoles(IEnumerable<Role> roles)
|
||||
{
|
||||
if (roles.IsNullOrEmpty()) return false;
|
||||
|
||||
var validRoles = roles.Where(x => !string.IsNullOrWhiteSpace(x.Id)
|
||||
&& !string.IsNullOrWhiteSpace(x.Name)).ToList();
|
||||
if (validRoles.IsNullOrEmpty()) return false;
|
||||
|
||||
|
||||
// Clear data
|
||||
_dc.RoleAgents.DeleteMany(Builders<RoleAgentDocument>.Filter.Empty);
|
||||
_dc.Roles.DeleteMany(Builders<RoleDocument>.Filter.Empty);
|
||||
|
||||
var roleDocs = validRoles.Select(x => new RoleDocument
|
||||
{
|
||||
Id = x.Id,
|
||||
Name = x.Name,
|
||||
Permissions = x.Permissions,
|
||||
CreatedTime = DateTime.UtcNow,
|
||||
UpdatedTime = DateTime.UtcNow
|
||||
});
|
||||
_dc.Roles.InsertMany(roleDocs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<Role> GetRoles(RoleFilter filter)
|
||||
{
|
||||
if (filter == null)
|
||||
{
|
||||
filter = RoleFilter.Empty();
|
||||
}
|
||||
|
||||
var roleBuilder = Builders<RoleDocument>.Filter;
|
||||
var roleFilters = new List<FilterDefinition<RoleDocument>>() { roleBuilder.Empty };
|
||||
|
||||
// Apply filters
|
||||
if (!filter.Names.IsNullOrEmpty())
|
||||
{
|
||||
roleFilters.Add(roleBuilder.In(x => x.Name, filter.Names));
|
||||
}
|
||||
|
||||
// Search
|
||||
var roleDocs = _dc.Roles.Find(roleBuilder.And(roleFilters)).ToList();
|
||||
var roles = roleDocs.Select(x => x.ToRole()).ToList();
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
public Role? GetRoleDetails(string roleId, bool includeAgent = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleId)) return null;
|
||||
|
||||
var roleDoc = _dc.Roles.Find(Builders<RoleDocument>.Filter.Eq(x => x.Id, roleId)).FirstOrDefault();
|
||||
if (roleDoc == null) return null;
|
||||
|
||||
var agentActions = new List<RoleAgentAction>();
|
||||
var role = roleDoc.ToRole();
|
||||
var roleAgentDocs = _dc.RoleAgents.Find(Builders<RoleAgentDocument>.Filter.Eq(x => x.RoleId, roleId)).ToList();
|
||||
|
||||
if (!includeAgent)
|
||||
{
|
||||
agentActions = roleAgentDocs.Select(x => new RoleAgentAction
|
||||
{
|
||||
Id = x.Id,
|
||||
AgentId = x.AgentId,
|
||||
Actions = x.Actions
|
||||
}).ToList();
|
||||
role.AgentActions = agentActions;
|
||||
return role;
|
||||
}
|
||||
|
||||
var agentIds = roleAgentDocs.Select(x => x.AgentId).Distinct().ToList();
|
||||
if (!agentIds.IsNullOrEmpty())
|
||||
{
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
|
||||
foreach (var item in roleAgentDocs)
|
||||
{
|
||||
var found = agents.FirstOrDefault(x => x.Id == item.AgentId);
|
||||
if (found == null) continue;
|
||||
|
||||
agentActions.Add(new RoleAgentAction
|
||||
{
|
||||
Id = item.Id,
|
||||
AgentId = found.Id,
|
||||
Agent = found,
|
||||
Actions = item.Actions
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
role.AgentActions = agentActions;
|
||||
return role;
|
||||
}
|
||||
|
||||
public bool UpdateRole(Role role, bool updateRoleAgents = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(role?.Id)) return false;
|
||||
|
||||
var roleFilter = Builders<RoleDocument>.Filter.Eq(x => x.Id, role.Id);
|
||||
var roleUpdate = Builders<RoleDocument>.Update
|
||||
.Set(x => x.Name, role.Name)
|
||||
.Set(x => x.Permissions, role.Permissions)
|
||||
.Set(x => x.CreatedTime, DateTime.UtcNow)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||
|
||||
_dc.Roles.UpdateOne(roleFilter, roleUpdate, _options);
|
||||
|
||||
if (updateRoleAgents)
|
||||
{
|
||||
var roleAgentDocs = role.AgentActions?.Select(x => new RoleAgentDocument
|
||||
{
|
||||
Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(),
|
||||
RoleId = role.Id,
|
||||
AgentId = x.AgentId,
|
||||
Actions = x.Actions,
|
||||
CreatedTime = DateTime.UtcNow,
|
||||
UpdatedTime = DateTime.UtcNow
|
||||
})?.ToList() ?? [];
|
||||
|
||||
var toDelete = _dc.RoleAgents.Find(Builders<RoleAgentDocument>.Filter.And(
|
||||
Builders<RoleAgentDocument>.Filter.Eq(x => x.RoleId, role.Id),
|
||||
Builders<RoleAgentDocument>.Filter.Nin(x => x.Id, roleAgentDocs.Select(x => x.Id))
|
||||
)).ToList();
|
||||
|
||||
_dc.RoleAgents.DeleteMany(Builders<RoleAgentDocument>.Filter.In(x => x.Id, toDelete.Select(x => x.Id)));
|
||||
foreach (var doc in roleAgentDocs)
|
||||
{
|
||||
var roleAgentFilter = Builders<RoleAgentDocument>.Filter.Eq(x => x.Id, doc.Id);
|
||||
var roleAgentUpdate = Builders<RoleAgentDocument>.Update
|
||||
.Set(x => x.Id, doc.Id)
|
||||
.Set(x => x.RoleId, role.Id)
|
||||
.Set(x => x.AgentId, doc.AgentId)
|
||||
.Set(x => x.Actions, doc.Actions)
|
||||
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||
|
||||
_dc.RoleAgents.UpdateOne(roleAgentFilter, roleAgentUpdate, _options);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -200,6 +200,10 @@ public partial class MongoRepository
|
|||
{
|
||||
userFilters.Add(userBuilder.In(x => x.Role, filter.Roles));
|
||||
}
|
||||
if (!filter.Types.IsNullOrEmpty())
|
||||
{
|
||||
userFilters.Add(userBuilder.In(x => x.Type, filter.Types));
|
||||
}
|
||||
if (!filter.Sources.IsNullOrEmpty())
|
||||
{
|
||||
userFilters.Add(userBuilder.In(x => x.Source, filter.Sources));
|
||||
|
|
@ -221,15 +225,15 @@ public partial class MongoRepository
|
|||
};
|
||||
}
|
||||
|
||||
public User? GetUserDetails(string userId)
|
||||
public User? GetUserDetails(string userId, bool includeAgent = false)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(userId)) return null;
|
||||
|
||||
var userDoc = _dc.Users.Find(Builders<UserDocument>.Filter.Eq(x => x.Id, userId)).FirstOrDefault();
|
||||
var userDoc = _dc.Users.AsQueryable().FirstOrDefault(x => x.Id == userId || x.ExternalId == userId);
|
||||
if (userDoc == null) return null;
|
||||
|
||||
var agentActions = new List<UserAgentAction>();
|
||||
var user = userDoc.ToUser();
|
||||
|
||||
var userAgents = _dc.UserAgents.AsQueryable().Where(x => x.UserId == userId).Select(x => new UserAgent
|
||||
{
|
||||
Id = x.Id,
|
||||
|
|
@ -238,9 +242,19 @@ public partial class MongoRepository
|
|||
Actions = x.Actions ?? Enumerable.Empty<string>()
|
||||
}).ToList();
|
||||
|
||||
var agentActions = new List<UserAgentAction>();
|
||||
if (!includeAgent)
|
||||
{
|
||||
agentActions = userAgents.Select(x => new UserAgentAction
|
||||
{
|
||||
Id = x.Id,
|
||||
AgentId = x.AgentId,
|
||||
Actions = x.Actions
|
||||
}).ToList();
|
||||
user.AgentActions = agentActions;
|
||||
return user;
|
||||
}
|
||||
|
||||
var agentIds = userAgents.Select(x => x.AgentId)?.Distinct().ToList();
|
||||
|
||||
if (!agentIds.IsNullOrEmpty())
|
||||
{
|
||||
var agents = GetAgents(new AgentFilter { AgentIds = agentIds });
|
||||
|
|
@ -264,7 +278,7 @@ public partial class MongoRepository
|
|||
return user;
|
||||
}
|
||||
|
||||
public bool UpdateUser(User user, bool isUpdateUserAgents = false)
|
||||
public bool UpdateUser(User user, bool updateUserAgents = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(user?.Id)) return false;
|
||||
|
||||
|
|
@ -277,7 +291,7 @@ public partial class MongoRepository
|
|||
|
||||
_dc.Users.UpdateOne(userFilter, userUpdate);
|
||||
|
||||
if (isUpdateUserAgents)
|
||||
if (updateUserAgents)
|
||||
{
|
||||
var userAgentDocs = user.AgentActions?.Select(x => new UserAgentDocument
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue