diff --git a/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Events/IEventPublisher.cs b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Events/IEventPublisher.cs index f2276c13..31a708bc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Events/IEventPublisher.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/Events/IEventPublisher.cs @@ -10,7 +10,7 @@ public interface IEventPublisher /// Task BroadcastAsync(string channel, string message); - Task PublishAsync(string channel, string message, EventPriority? priority = null); + Task PublishAsync(string channel, string message, EventPriority? priority = null); Task ReDispatchAsync(string channel, int count = 10, string order = "asc"); diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 33be79c1..73577f45 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -5,6 +5,7 @@ using BotSharp.Abstraction.Roles.Models; using BotSharp.Abstraction.Shared; using BotSharp.Abstraction.Tasks.Models; using BotSharp.Abstraction.Translation.Models; +using BotSharp.Abstraction.Users.Enums; using BotSharp.Abstraction.Users.Models; using BotSharp.Abstraction.VectorStorage.Models; @@ -26,7 +27,7 @@ public interface IBotSharpRepository : IHaveServiceProvider #region User User? GetUserByEmail(string email) => throw new NotImplementedException(); - User? GetUserByPhone(string phone, string type = "client", string regionCode = "CN") => throw new NotImplementedException(); + User? GetUserByPhone(string phone, string type = UserType.Client, string regionCode = "CN") => throw new NotImplementedException(); User? GetAffiliateUserByPhone(string phone) => throw new NotImplementedException(); User? GetUserById(string id) => throw new NotImplementedException(); List GetUserByIds(List ids) => throw new NotImplementedException(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs index 8d136dc5..df1ff190 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs @@ -23,6 +23,7 @@ public class User public bool Verified { get; set; } public string RegionCode { get; set; } = "CN"; public string? AffiliateId { get; set; } + public string? AffiliateCode { get; set; } public string? EmployeeId { get; set; } public bool IsDisabled { get; set; } public IEnumerable Permissions { get; set; } = []; diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs index 8e5c7f23..4d21013b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/Pagination.cs @@ -1,7 +1,9 @@ using BotSharp.Abstraction.Infrastructures; +using System.Diagnostics; namespace BotSharp.Abstraction.Utilities; +[DebuggerStepThrough] public class Pagination : ICacheKey { private int _page; diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs index 27cbf566..32889f4f 100644 --- a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisPublisher.cs @@ -21,7 +21,7 @@ public class RedisPublisher : IEventPublisher await _subscriber.PublishAsync(channel, message); } - public async Task PublishAsync(string channel, string message, EventPriority? priority = null) + public async Task PublishAsync(string channel, string message, EventPriority? priority = null) { var db = _redis.GetDatabase(); @@ -34,7 +34,7 @@ public class RedisPublisher : IEventPublisher if (CheckMessageExists(db, channel, "message", message)) { _logger.LogError($"The message already exists {channel} {message}"); - return; + return null; } // Add a message to the stream, keeping only the latest 1 million messages @@ -46,6 +46,8 @@ public class RedisPublisher : IEventPublisher maxLength: 1000 * 10000); _logger.LogInformation($"Published message {channel} {message} ({messageId})"); + + return messageId; } private bool CheckMessageExists(IDatabase db, string channel, string fieldName, string desiredValue) @@ -91,7 +93,10 @@ public class RedisPublisher : IEventPublisher try { - var messageId = await db.StreamAddAsync(channel, "message", entry.Values[0].Value); + var messageId = await db.StreamAddAsync(channel, [ + new NameValueEntry("message", entry.Values[0].Value), + new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o")) + ]); _logger.LogWarning($"ReDispatched message: {channel} {entry.Values[0].Value} ({messageId})"); diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs index b93c22a2..89b38a8d 100644 --- a/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/Events/RedisSubscriber.cs @@ -42,6 +42,8 @@ public class RedisSubscriber : IEventSubscriber while (true) { + await Task.Delay(100); + if (priorityEnabled) { if (await HandleGroupMessage(db, $"{channel}-{EventPriority.High}", group, received) > 0) diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/Utilities.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/Utilities.cs index 4cb26888..613643f4 100644 --- a/src/Infrastructure/BotSharp.Core/Infrastructures/Utilities.cs +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/Utilities.cs @@ -23,7 +23,7 @@ public static class Utilities var data = sha256.ComputeHash(Encoding.UTF8.GetBytes(text)); var sb = new StringBuilder(); - foreach(var c in data) + foreach (var c in data) { sb.Append(c.ToString("x2")); } @@ -47,4 +47,36 @@ public static class Utilities memcache.Compact(100); } } + + public static string HideMiddleDigits(string input, bool isEmail = false) + { + if (string.IsNullOrWhiteSpace(input)) + { + return input; + } + + if (isEmail) + { + int atIndex = input.IndexOf('@'); + if (atIndex > 1) + { + string localPart = input.Substring(0, atIndex); + if (localPart.Length > 2) + { + string maskedLocalPart = $"{localPart[0]}{new string('*', localPart.Length - 2)}{localPart[^1]}"; + return $"{maskedLocalPart}@{input.Substring(atIndex + 1)}"; + } + } + } + else + { + if (input.Length > 6) + { + return $"{input.Substring(0, 3)}{new string('*', input.Length - 6)}{input.Substring(input.Length - 3)}"; + } + } + + return input; + } + } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs index 962bc941..317d6fc2 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.User.cs @@ -11,7 +11,7 @@ public partial class FileRepository return Users.FirstOrDefault(x => x.Email == email.ToLower()); } - public User? GetUserByPhone(string phone, string? type = "client", string regionCode = "CN") + public User? GetUserByPhone(string phone, string? type = UserType.Client, string regionCode = "CN") { var query = Users.Where(x => x.Phone == phone); diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 45f22937..3858d63d 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -172,7 +172,7 @@ public class UserService : IUserService var base64 = Encoding.UTF8.GetString(Convert.FromBase64String(authorization)); var (id, password) = base64.SplitAsTuple(":"); var db = _services.GetRequiredService(); - var record = db.GetUserByPhone(id, type: "internal"); + var record = db.GetUserByPhone(id, type: UserType.Internal); var isCanLogin = record != null && !record.IsDisabled && record.Type == UserType.Internal && new List { @@ -548,7 +548,7 @@ public class UserService : IUserService } var db = _services.GetRequiredService(); - var UserByphone = db.GetUserByPhone(phone, regionCode); + var UserByphone = db.GetUserByPhone(phone, regionCode: regionCode); if (UserByphone != null && UserByphone.Verified) { return true; diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs index c55da5fa..27bdc0aa 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserCreationModel.cs @@ -13,6 +13,7 @@ public class UserCreationModel public string Type { get; set; } = UserType.Client; public string Role { get; set; } = UserRole.User; public string RegionCode { get; set; } = "CN"; + public string? AffiliateCode { get; set; } public User ToUser() { return new User @@ -25,7 +26,8 @@ public class UserCreationModel Password = Password, Role = Role, Type = Type, - RegionCode = RegionCode + RegionCode = RegionCode, + AffiliateCode = AffiliateCode }; } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs index fae5873b..ff220e9d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Users.Enums; +using BotSharp.Core.Infrastructures; using System.Text.Json.Serialization; namespace BotSharp.OpenAPI.ViewModels.Users; @@ -57,8 +58,8 @@ public class UserViewModel UserName = user.UserName, FirstName = user.FirstName, LastName = user.LastName, - Email = user.Email, - Phone = !string.IsNullOrWhiteSpace(user.Phone) ? user.Phone.Replace("+86", String.Empty) : user.Phone, + Email = Utilities.HideMiddleDigits(user.Email, true), + Phone = Utilities.HideMiddleDigits((!string.IsNullOrWhiteSpace(user.Phone) ? user.Phone.Replace("+86", String.Empty) : user.Phone)), Type = user.Type, Role = user.Role, Source = user.Source, diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs index d72247aa..8a381069 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs @@ -13,7 +13,7 @@ public partial class MongoRepository return user != null ? user.ToUser() : null; } - public User? GetUserByPhone(string phone, string type = "client", string regionCode = "CN") + public User? GetUserByPhone(string phone, string type = UserType.Client, string regionCode = "CN") { string phoneSecond = string.Empty; // if phone number length is less than 4, return null @@ -24,7 +24,7 @@ public partial class MongoRepository phoneSecond = phone.StartsWith("+86") ? phone.Replace("+86", "") : $"+86{phone}"; - var user = _dc.Users.AsQueryable().FirstOrDefault(x => (x.Phone == phone || x.Phone == phoneSecond) + var user = _dc.Users.AsQueryable().FirstOrDefault(x => (x.Phone == phone || x.Phone == phoneSecond) && (x.RegionCode == regionCode || string.IsNullOrWhiteSpace(x.RegionCode)) && (x.Type == type)); return user != null ? user.ToUser() : null;