// *********************************************************************** // // AgileWebs // // *********************************************************************** using Core.Thalos.Adapters; using Core.Thalos.Adapters.Common.Enums; using Core.Blueprint.Mongo; using Core.Blueprint.Redis; using Core.Blueprint.Redis.Helpers; using Mapster; using Microsoft.Extensions.Options; using MongoDB.Driver; using Core.Thalos.Provider.Contracts; using MongoDB.Bson; using System.Text.RegularExpressions; using MongoDB.Bson.Serialization; namespace Core.Thalos.Provider.Providers.Onboarding { /// /// Handles all services and business rules related to . /// public class UserProvider : IUserProvider { private readonly CollectionRepository repository; private readonly CacheSettings cacheSettings; private readonly IRedisCacheProvider cacheProvider; public UserProvider(CollectionRepository repository, IRedisCacheProvider cacheProvider, IOptions cacheSettings) { this.repository = repository; this.repository.CollectionInitialization(); this.cacheSettings = cacheSettings.Value; this.cacheProvider = cacheProvider; } /// /// Creates a new User. /// /// The User to be created. /// A representing /// the asynchronous execution of the service. public async ValueTask CreateUser(Core.Thalos.Domain.Contexts.Onboarding.Request.UserRequest newUser, CancellationToken cancellationToken) { var userCollection = newUser.Adapt(); await repository.InsertOneAsync(userCollection); return userCollection; } /// /// Gets an User by identifier. /// /// The User identifier. /// A representing /// the asynchronous execution of the service. public async ValueTask GetUserById(string _id, CancellationToken cancellationToken) { var cacheKey = CacheKeyHelper.GenerateCacheKey(this, "GetUserById", _id); var cachedData = await cacheProvider.GetAsync(cacheKey); if (cachedData is not null) { return cachedData; } var user = await repository.FindByIdAsync(_id); await cacheProvider.SetAsync(cacheKey, user); return user; } /// /// Gets all the users. /// /// A representing /// the asynchronous execution of the service. public async ValueTask> GetAllUsers(CancellationToken cancellationToken) { var cacheKey = CacheKeyHelper.GenerateCacheKey(this, "GetAllUsers"); var cachedData = await cacheProvider.GetAsync>(cacheKey) ?? []; if (cachedData.Any()) return cachedData; var users = await repository.AsQueryable(); await cacheProvider.SetAsync(cacheKey, users); return users; } /// /// Gets an User by email. /// /// The User email. /// A representing /// the asynchronous execution of the service. public async ValueTask GetUserByEmail(string? email, CancellationToken cancellationToken) { var cacheKey = CacheKeyHelper.GenerateCacheKey(this, "GetUserByEmail", email); var cachedData = await cacheProvider.GetAsync(cacheKey); if (cachedData is not null) { return cachedData; } var user = await repository.FindOneAsync( u => u.Email == email && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); await cacheProvider.SetAsync(cacheKey, user); return user; } /// /// Validates if a users exists by email.. /// /// The User email. /// A representing /// the asynchronous execution of the service. public async ValueTask ValidateUserExistence(string? email, CancellationToken cancellationToken) { var cacheKey = CacheKeyHelper.GenerateCacheKey(this, "GetUserByEmail", email); var cachedData = await cacheProvider.GetAsync(cacheKey); if (cachedData is not null) { return cachedData; } var user = await repository.FindOneAsync( u => u.Email == email && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); await cacheProvider.SetAsync(cacheKey, user); return user; } /// /// Changes the status of the user. /// /// The user identifier. /// The new status of the user. /// A representing /// the asynchronous execution of the service. public async ValueTask ChangeUserStatus(string id, Core.Blueprint.Mongo.StatusEnum newStatus, CancellationToken cancellationToken) { var entity = await repository.FindByIdAsync(id); entity.Status = newStatus; await repository.ReplaceOneAsync(entity); return entity; } /// /// Updates a User by id. /// /// The User to be updated. /// The User identifier. /// A representing /// the asynchronous execution of the service. public async ValueTask UpdateUser(UserAdapter entity, CancellationToken cancellationToken) { await repository.ReplaceOneAsync(entity); return entity; } /// /// Logs in the user. /// /// The User identifier. /// A representing /// the asynchronous execution of the service. public async ValueTask LogInUser(string email, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Email == email && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); user.LastLogIn = DateTime.UtcNow; await repository.ReplaceOneAsync(user); return user; } /// /// Logs out the user's session. /// /// The User email. /// A representing /// the asynchronous execution of the service. public async ValueTask LogOutUserSession(string email, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Email == email && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); user.LastLogOut = DateTime.UtcNow; await repository.ReplaceOneAsync(user); return user; } /// /// Adds a company to the user's list of companies. /// /// The identifier of the user to whom the company will be added. /// The identifier of the company to add. /// A representing the asynchronous operation, with the updated user object. public async ValueTask AddCompanyToUser(string userId, string companyId, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Id == userId && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); var updatedCompanies = user.Companies.Append(companyId).Distinct().ToArray(); user.Companies = updatedCompanies; await repository.ReplaceOneAsync(user); return user; } /// /// Removes a company from the user's list of companies. /// /// The identifier of the user from whom the company will be removed. /// The identifier of the company to remove. /// A representing the asynchronous operation, with the updated user object. public async ValueTask RemoveCompanyFromUser(string userId, string companyId, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Id == userId && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); var updatedCompanies = user.Companies ?.Where(c => c != companyId) .ToArray(); user.Companies = updatedCompanies; await repository.ReplaceOneAsync(user); return user; } /// /// Adds a project to the user's list of projects. /// /// The identifier of the user to whom the project will be added. /// The identifier of the project to add. /// A representing the asynchronous operation, with the updated user object. public async ValueTask AddProjectToUser(string userId, string projectId, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Id == userId && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); var updatedProjects = user.Projects.Append(projectId).Distinct().ToArray(); user.Companies = updatedProjects; await repository.ReplaceOneAsync(user); return user; } /// /// Removes a project from the user's list of projects. /// /// The identifier of the user from whom the project will be removed. /// The identifier of the project to remove. /// A representing the asynchronous operation, with the updated user object. public async ValueTask RemoveProjectFromUser(string userId, string projectId, CancellationToken cancellationToken) { var user = await repository.FindOneAsync( u => u.Id == userId && u.Status == Core.Blueprint.Mongo.StatusEnum.Active); var updatedProjects = user.Projects ?.Where(c => c != projectId) .ToArray(); user.Companies = updatedProjects; await repository.ReplaceOneAsync(user); return user; } /// /// Gets the token adapter for a user. /// /// The user's email. /// A representing the asynchronous execution of the service. public async ValueTask GetToken(string email, CancellationToken cancellationToken) { try { var pipeline = new[] { new BsonDocument("$match", new BsonDocument { { "email", new BsonDocument { { "$regex", $"^{Regex.Escape(email)}$" }, { "$options", "i" } } }, { "status", Core.Blueprint.Mongo.StatusEnum.Active.ToString() } }), new BsonDocument("$lookup", new BsonDocument { { "from", "Roles" }, { "localField", "roleId" }, { "foreignField", "_id" }, { "as", "role" } }), new BsonDocument("$unwind", "$role"), new BsonDocument("$match", new BsonDocument("role.status", Core.Blueprint.Mongo.StatusEnum.Active.ToString())), new BsonDocument("$addFields", new BsonDocument { { "role.permissions", new BsonDocument("$map", new BsonDocument { { "input", "$role.permissions" }, { "as", "perm" }, { "in", new BsonDocument("$toObjectId", "$$perm") } }) }, { "role.modules", new BsonDocument("$map", new BsonDocument { { "input", "$role.modules" }, { "as", "mod" }, { "in", new BsonDocument("$toObjectId", "$$mod") } }) } }), new BsonDocument("$lookup", new BsonDocument { { "from", "Permissions" }, { "localField", "role.permissions" }, { "foreignField", "_id" }, { "as", "permissions" } }), new BsonDocument("$lookup", new BsonDocument { { "from", "Modules" }, { "localField", "role.modules" }, { "foreignField", "_id" }, { "as", "modules" } }), new BsonDocument("$project", new BsonDocument { { "_id", 1 }, { "guid", 1 }, { "email", 1 }, { "name", 1 }, { "middleName", 1 }, { "lastName", 1 }, { "displayName", 1 }, { "roleId", 1 }, { "companies", 1 }, { "projects", 1 }, { "lastLogIn", 1 }, { "lastLogOut", 1 }, { "createdBy", 1 }, { "updatedBy", 1 }, { "status", 1 }, { "createdAt", 1 }, { "updatedAt", 1 }, { "role._id", 1 }, { "role.name", 1 }, { "role.description", 1 }, { "role.applications", 1 }, { "role.permissions", 1 }, { "role.modules", 1 }, { "role.status", 1 }, { "role.createdAt", 1 }, { "role.updatedAt", 1 }, { "role.createdBy", 1 }, { "role.updatedBy", 1 }, { "permissions", 1 }, { "modules", 1 } }) }; var result = await repository.FindOnePipelineAsync(pipeline); if (result is null) return null; var tokenAdapter = new TokenAdapter { User = new UserAdapter { Id = result["_id"]?.ToString() ?? "", Guid = result["guid"].AsString, Email = result["email"].AsString, Name = result["name"].AsString, MiddleName = result["middleName"].AsString, LastName = result["lastName"].AsString, DisplayName = result["displayName"].AsString, RoleId = result["roleId"]?.ToString() ?? "", Companies = result["companies"].AsBsonArray .Select(c => c.AsString) .ToArray(), Projects = result["projects"].AsBsonArray .Select(c => c.AsString) .ToArray(), LastLogIn = result["lastLogIn"].ToUniversalTime(), LastLogOut = result["lastLogOut"].ToUniversalTime(), CreatedAt = result["createdAt"].ToUniversalTime(), CreatedBy = result["createdBy"].AsString, UpdatedAt = result["updatedAt"].ToUniversalTime(), UpdatedBy = result["updatedBy"].AsString, Status = (Core.Blueprint.Mongo.StatusEnum)Enum.Parse(typeof(Core.Blueprint.Mongo.StatusEnum), result["status"].AsString), }, Role = new RoleAdapter { Id = result["role"]["_id"]?.ToString() ?? "", Name = result["role"]["name"].AsString, Description = result["role"]["description"].AsString, Applications = result["role"]["applications"].AsBsonArray .Select(c => (ApplicationsEnum)c.AsInt32) .ToArray(), Modules = result["role"]["modules"].AsBsonArray .Select(c => c.ToString() ?? "") .ToArray(), Permissions = result["role"]["permissions"].AsBsonArray .Select(c => c.ToString() ?? "") .ToArray(), Status = (Core.Blueprint.Mongo.StatusEnum)Enum.Parse(typeof(Core.Blueprint.Mongo.StatusEnum), result["role"]["status"].AsString), CreatedAt = result["role"]["createdAt"].ToUniversalTime(), UpdatedAt = result["role"]["updatedAt"].ToUniversalTime(), CreatedBy = result["role"]["createdBy"].AsString, UpdatedBy = result["role"]["updatedBy"].AsString }, Permissions = result["permissions"].AsBsonArray .Select(permission => BsonSerializer.Deserialize(permission.AsBsonDocument)) .Where(permission => permission.Status == Core.Blueprint.Mongo.StatusEnum.Active) .ToList() }; return tokenAdapter; } catch (Exception ex) { throw new Exception(ex.Message, ex); } } /// /// Deletes an User by id. /// /// The User identifier. /// A representing /// the asynchronous execution of the service. public async ValueTask DeleteUser(string _id, CancellationToken cancellationToken) { var entity = await repository.DeleteOneAsync(doc => doc.Id == _id); return entity; } } }