BotSharp/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.User.cs
2025-08-11 15:46:35 -05:00

493 lines
18 KiB
C#

using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Users.Enums;
using BotSharp.Abstraction.Users.Models;
namespace BotSharp.Plugin.MongoStorage.Repository;
public partial class MongoRepository
{
public User? GetUserByEmail(string email)
{
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Email == email.ToLower());
return user != null ? user.ToUser() : null;
}
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
if (string.IsNullOrWhiteSpace(phone) || phone?.Length < 4)
{
return null;
}
if (regionCode == "CN")
{
phoneSecond = (phone ?? "").StartsWith("+86") ? (phone ?? "").Replace("+86", "") : ($"+86{phone ?? ""}");
}
else
{
phoneSecond = (phone ?? "").Substring(regionCode == "US" ? 2 : 3);
}
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;
}
public User? GetUserByPhoneV2(string phone, string source = UserType.Internal, string regionCode = "CN")
{
string phoneSecond = string.Empty;
// if phone number length is less than 4, return null
if (string.IsNullOrWhiteSpace(phone) || phone?.Length < 4)
{
return null;
}
if (regionCode == "CN")
{
phoneSecond = (phone ?? "").StartsWith("+86") ? (phone ?? "").Replace("+86", "") : ($"+86{phone ?? ""}");
}
else
{
phoneSecond = (phone ?? "").Substring(regionCode == "US" ? 2 : 3);
}
var user = _dc.Users.AsQueryable().FirstOrDefault(x => (x.Phone == phone || x.Phone == phoneSecond)
&& (x.RegionCode == regionCode || string.IsNullOrWhiteSpace(x.RegionCode))
&& (x.Source == source));
return user != null ? user.ToUser() : null;
}
public User? GetAffiliateUserByPhone(string phone)
{
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Phone == phone && x.Type == UserType.Affiliate);
return user != null ? user.ToUser() : null;
}
public User? GetUserById(string id)
{
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Id == id || (x.ExternalId != null && x.ExternalId == id));
return user != null ? user.ToUser() : null;
}
public List<User> GetUserByIds(List<string> ids)
{
var users = _dc.Users.AsQueryable().Where(x => ids.Contains(x.Id) || (x.ExternalId != null && ids.Contains(x.ExternalId))).ToList();
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : [];
}
public List<User> GetUsersByAffiliateId(string affiliateId)
{
var users = _dc.Users.AsQueryable().Where(x => x.AffiliateId == affiliateId).ToList();
return users?.Any() == true ? users.Select(x => x.ToUser()).ToList() : [];
}
public User? GetUserByUserName(string userName)
{
var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.UserName == userName.ToLower());
return user != null ? user.ToUser() : null;
}
public void CreateUser(User user)
{
if (user == null) return;
var userCollection = new UserDocument
{
Id = user.Id ?? Guid.NewGuid().ToString(),
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
Salt = user.Salt,
Password = user.Password,
Email = user.Email,
Phone = user.Phone,
Source = user.Source,
ExternalId = user.ExternalId,
Role = user.Role,
Type = user.Type,
VerificationCode = user.VerificationCode,
Verified = user.Verified,
RegionCode = user.RegionCode,
AffiliateId = user.AffiliateId,
EmployeeId = user.EmployeeId,
IsDisabled = user.IsDisabled,
CreatedTime = DateTime.UtcNow,
UpdatedTime = DateTime.UtcNow
};
_dc.Users.InsertOne(userCollection);
}
public void UpdateExistUser(string userId, User user)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update
.Set(x => x.Email, user.Email)
.Set(x => x.Phone, user.Phone)
.Set(x => x.Salt, user.Salt)
.Set(x => x.Password, user.Password)
.Set(x => x.VerificationCode, user.VerificationCode)
.Set(x => x.UpdatedTime, DateTime.UtcNow)
.Set(x => x.RegionCode, user.RegionCode);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserName(string userId, string userName)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update
.Set(x => x.UserName, userName);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserVerified(string userId)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Verified, true)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserVerificationCode(string userId, string verficationCode)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.VerificationCode, verficationCode)
.Set(x => x.VerificationCodeExpireAt, DateTime.UtcNow.AddMinutes(5))
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserPassword(string userId, string password)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Password, password)
.Set(x => x.UpdatedTime, DateTime.UtcNow)
.Set(x => x.Verified, true);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserEmail(string userId, string email)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Email, email)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserPhone(string userId, string phone, string regionCode)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Phone, phone)
.Set(x => x.UpdatedTime, DateTime.UtcNow)
.Set(x => x.RegionCode, regionCode)
//.Set(x => x.UserName, phone)
.Set(x => x.FirstName, phone);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUserIsDisable(string userId, bool isDisable)
{
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.IsDisabled, isDisable)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Users.UpdateOne(filter, update);
}
public void UpdateUsersIsDisable(List<string> userIds, bool isDisable)
{
foreach (var userId in userIds)
{
UpdateUserIsDisable(userId, isDisable);
}
}
public async ValueTask<PagedItems<User>> GetUsers(UserFilter filter)
{
if (filter == null)
{
filter = UserFilter.Empty();
}
var userBuilder = Builders<UserDocument>.Filter;
var userFilters = new List<FilterDefinition<UserDocument>>() { userBuilder.Empty };
// Apply filters
if (!filter.UserIds.IsNullOrEmpty())
{
userFilters.Add(userBuilder.In(x => x.Id, filter.UserIds));
}
if (!filter.UserNames.IsNullOrEmpty())
{
userFilters.Add(userBuilder.In(x => x.UserName, filter.UserNames));
}
if (!filter.ExternalIds.IsNullOrEmpty())
{
userFilters.Add(userBuilder.In(x => x.ExternalId, filter.ExternalIds));
}
if (!filter.Roles.IsNullOrEmpty())
{
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));
}
// Filter def and sort
var filterDef = userBuilder.And(userFilters);
var sortDef = Builders<UserDocument>.Sort.Descending(x => x.CreatedTime);
// Search
var docsTask = _dc.Users.FindAsync(filterDef, options: new()
{
Sort = sortDef,
Skip = filter.Offset,
Limit = filter.Size
});
var countTask = _dc.Users.CountDocumentsAsync(filterDef);
await Task.WhenAll([docsTask, countTask]);
var docs = docsTask.Result.ToList();
var count = countTask.Result;
var users = docs.Select(x => x.ToUser()).ToList();
return new PagedItems<User>
{
Items = users,
Count = count
};
}
public List<User> SearchLoginUsers(User filter, string source = UserSource.Internal)
{
List<User> searchResult = [];
// search by filters
if (!string.IsNullOrWhiteSpace(filter.Id))
{
var curUser = _dc.Users.AsQueryable().FirstOrDefault(x => x.Source == source && x.Id == filter.Id.ToLower());
User? user = curUser != null ? curUser.ToUser() : null;
if (user != null)
{
searchResult.Add(user);
}
}
else if (!string.IsNullOrWhiteSpace(filter.Phone) && !string.IsNullOrWhiteSpace(filter.RegionCode))
{
string[] regionCodeData = filter.RegionCode.Split('|');
if (regionCodeData.Length == 2)
{
string phoneNoCallingCode = filter.Phone;
string phoneWithCallingCode = filter.Phone;
if (!filter.Phone.StartsWith('+'))
{
phoneNoCallingCode = filter.Phone;
phoneWithCallingCode = $"{regionCodeData[1]}{filter.Phone}";
}
else
{
phoneNoCallingCode = filter.Phone.Replace(regionCodeData[1], "");
}
var phoneUsers = _dc.Users.AsQueryable()
.Where(x => x.Source == source && (x.Phone == phoneNoCallingCode || x.Phone == phoneWithCallingCode) && x.RegionCode == regionCodeData[0])
.ToList();
if (phoneUsers != null && phoneUsers.Count > 0)
{
foreach (var user in phoneUsers)
{
if (user != null)
{
searchResult.Add(user.ToUser());
}
}
}
}
}
else if (!string.IsNullOrWhiteSpace(filter.Email))
{
var curUser = _dc.Users.AsQueryable().FirstOrDefault(x => x.Source == source && x.Email == filter.Email.ToLower());
User? user = curUser != null ? curUser.ToUser() : null;
if (user != null)
{
searchResult.Add(user);
}
}
if (searchResult.Count == 0 && !string.IsNullOrWhiteSpace(filter.UserName))
{
var curUser = _dc.Users.AsQueryable().FirstOrDefault(x => x.Source == source && x.UserName == filter.UserName);
User? user = curUser != null ? curUser.ToUser() : null;
if (user != null)
{
searchResult.Add(user);
}
}
return searchResult;
}
public User? GetUserDetails(string userId, bool includeAgent = false)
{
if (string.IsNullOrWhiteSpace(userId)) return null;
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,
UserId = x.UserId,
AgentId = x.AgentId,
Actions = x.Actions ?? Enumerable.Empty<string>()
}).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 });
foreach (var item in userAgents)
{
var found = agents.FirstOrDefault(x => x.Id == item.AgentId);
if (found == null) continue;
agentActions.Add(new UserAgentAction
{
Id = item.Id,
AgentId = found.Id,
Agent = found,
Actions = item.Actions
});
}
}
user.AgentActions = agentActions;
return user;
}
public bool UpdateUser(User user, bool updateUserAgents = false)
{
if (string.IsNullOrEmpty(user?.Id)) return false;
var userFilter = Builders<UserDocument>.Filter.Eq(x => x.Id, user.Id);
var userUpdate = Builders<UserDocument>.Update
.Set(x => x.Type, user.Type)
.Set(x => x.Role, user.Role)
.Set(x => x.Permissions, user.Permissions)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.Users.UpdateOne(userFilter, userUpdate);
if (updateUserAgents)
{
var userAgentDocs = user.AgentActions?.Select(x => new UserAgentDocument
{
Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(),
UserId = user.Id,
AgentId = x.AgentId,
Actions = x.Actions,
CreatedTime = DateTime.UtcNow,
UpdatedTime = DateTime.UtcNow
})?.ToList() ?? [];
var toDelete = _dc.UserAgents.Find(Builders<UserAgentDocument>.Filter.And(
Builders<UserAgentDocument>.Filter.Eq(x => x.UserId, user.Id),
Builders<UserAgentDocument>.Filter.Nin(x => x.Id, userAgentDocs.Select(x => x.Id))
)).ToList();
_dc.UserAgents.DeleteMany(Builders<UserAgentDocument>.Filter.In(x => x.Id, toDelete.Select(x => x.Id)));
foreach (var doc in userAgentDocs)
{
var userAgentFilter = Builders<UserAgentDocument>.Filter.Eq(x => x.Id, doc.Id);
var userAgentUpdate = Builders<UserAgentDocument>.Update
.Set(x => x.Id, doc.Id)
.Set(x => x.UserId, user.Id)
.Set(x => x.AgentId, doc.AgentId)
.Set(x => x.Actions, doc.Actions)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
_dc.UserAgents.UpdateOne(userAgentFilter, userAgentUpdate, _options);
}
}
return true;
}
public Dashboard? GetDashboard(string? userId = null)
{
return null;
}
public void AddDashboardConversation(string userId, string conversationId)
{
var user = _dc.Users.AsQueryable()
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
if (user == null) return;
var curDash = user.Dashboard ?? new Dashboard();
curDash.ConversationList.Add(new DashboardConversation
{
Id = Guid.NewGuid().ToString(),
ConversationId = conversationId
});
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard, curDash)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
}
public void RemoveDashboardConversation(string userId, string conversationId)
{
var user = _dc.Users.AsQueryable()
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
if (user == null || user.Dashboard == null || user.Dashboard.ConversationList.IsNullOrEmpty()) return;
var curDash = user.Dashboard;
var unpinConv = user.Dashboard.ConversationList.FirstOrDefault(
x => string.Equals(x.ConversationId, conversationId, StringComparison.OrdinalIgnoreCase));
if (unpinConv == null) return;
curDash.ConversationList.Remove(unpinConv);
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard, curDash)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
}
public void UpdateDashboardConversation(string userId, DashboardConversation dashConv)
{
var user = _dc.Users.AsQueryable()
.FirstOrDefault(x => x.Id == userId || (x.ExternalId != null && x.ExternalId == userId));
if (user == null || user.Dashboard == null || user.Dashboard.ConversationList.IsNullOrEmpty()) return;
var curIdx = user.Dashboard.ConversationList.ToList().FindIndex(
x => string.Equals(x.ConversationId, dashConv.ConversationId, StringComparison.OrdinalIgnoreCase));
if (curIdx < 0) return;
var filter = Builders<UserDocument>.Filter.Eq(x => x.Id, userId);
var update = Builders<UserDocument>.Update.Set(x => x.Dashboard.ConversationList[curIdx], dashConv)
.Set(x => x.UpdatedTime, DateTime.UtcNow);
}
}