// *********************************************************************** // // AgileWebs // // *********************************************************************** using Core.Blueprint.Mongo; using Core.Blueprint.Redis; using Core.Blueprint.Redis.Helpers; using Core.Thalos.BuildingBlocks; using Core.Thalos.Provider.Contracts; using Mapster; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; using System.Text.RegularExpressions; namespace Core.Thalos.Provider.Providers.Onboarding { /// /// Handles all services and business rules related to . /// public class UserProvider : IUserProvider { private readonly CollectionRepository repository; private readonly ICacheSettings cacheSettings; private readonly IRedisCacheProvider cacheProvider; public UserProvider(CollectionRepository repository, IRedisCacheProvider cacheProvider, ICacheSettings cacheSettings ) { this.repository = repository; this.repository.CollectionInitialization(); this.cacheSettings = cacheSettings; 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 mongo 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, TimeSpan.FromMinutes(cacheSettings.DefaultCacheDurationInMinutes)); 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, TimeSpan.FromMinutes(cacheSettings.DefaultCacheDurationInMinutes)); 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); UserExistenceAdapter userExistance = new UserExistenceAdapter(); userExistance.Existence = (user != null) ? true : false; await cacheProvider.SetAsync(cacheKey, userExistance); return userExistance; } /// /// Changes the status of the user. /// /// The user mongo 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); if (entity is not null) { entity.Status = newStatus; return repository.ReplaceOneAsync(entity).Result; } else return null; } /// /// Updates a User by _id. /// /// The User to be updated. /// The User mongo identifier. /// A representing /// the asynchronous execution of the service. public async ValueTask UpdateUser(UserAdapter entity, CancellationToken cancellationToken) { var updatedEntity = await repository.ReplaceOneAsync(entity); return updatedEntity; } /// /// Logs in the user. /// /// The User mongo 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; } /// /// 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.Contains("guid") && !result["guid"].IsBsonNull ? result["guid"].AsString : string.Empty, Email = result.Contains("email") && !result["email"].IsBsonNull ? result["email"].AsString : string.Empty, Name = result.Contains("name") && !result["name"].IsBsonNull ? result["name"].AsString : string.Empty, MiddleName = result.Contains("middleName") && !result["middleName"].IsBsonNull ? result["middleName"].AsString : string.Empty, LastName = result.Contains("lastName") && !result["lastName"].IsBsonNull ? result["lastName"].AsString : string.Empty, DisplayName = result.Contains("displayName") && !result["displayName"].IsBsonNull ? result["displayName"].AsString : string.Empty, RoleId = result.Contains("roleId") && !result["roleId"].IsBsonNull ? result["roleId"].ToString() : string.Empty, LastLogIn = result.Contains("lastLogIn") && !result["lastLogIn"].IsBsonNull ? result["lastLogIn"].ToUniversalTime() : DateTime.MinValue, LastLogOut = result.Contains("lastLogOut") && !result["lastLogOut"].IsBsonNull ? result["lastLogOut"].ToUniversalTime() : DateTime.MinValue, CreatedAt = result.Contains("createdAt") && !result["createdAt"].IsBsonNull ? result["createdAt"].ToUniversalTime() : DateTime.MinValue, CreatedBy = result.Contains("createdBy") && !result["createdBy"].IsBsonNull ? result["createdBy"].AsString : string.Empty, UpdatedAt = result.Contains("updatedAt") && !result["updatedAt"].IsBsonNull ? result["updatedAt"].ToUniversalTime() : DateTime.MinValue, UpdatedBy = result.Contains("updatedBy") && !result["updatedBy"].IsBsonNull ? result["updatedBy"].AsString : string.Empty, Status = result.Contains("status") && !result["status"].IsBsonNull ? (Core.Blueprint.Mongo.StatusEnum)Enum.Parse(typeof(Core.Blueprint.Mongo.StatusEnum), result["status"].AsString) : Core.Blueprint.Mongo.StatusEnum.Inactive }, Role = new RoleAdapter { Id = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("_id") ? result["role"]["_id"]?.ToString() ?? "" : string.Empty, Name = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("name") ? result["role"]["name"]?.AsString ?? "" : string.Empty, Description = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("description") ? result["role"]["description"]?.AsString ?? "" : string.Empty, Applications = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("applications") && result["role"]["applications"].IsBsonArray ? result["role"]["applications"].AsBsonArray .Where(app => app != null && app.IsInt32) .Select(app => (ApplicationsEnum)app.AsInt32) .ToArray() : Array.Empty(), Modules = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("modules") && result["role"]["modules"].IsBsonArray ? result["role"]["modules"].AsBsonArray .Where(m => m != null) .Select(m => m.ToString() ?? "") .ToArray() : Array.Empty(), Permissions = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("permissions") && result["role"]["permissions"].IsBsonArray ? result["role"]["permissions"].AsBsonArray .Where(p => p != null) .Select(p => p.ToString() ?? "") .ToArray() : Array.Empty(), Status = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("status") && !result["role"]["status"].IsBsonNull ? (Core.Blueprint.Mongo.StatusEnum)Enum.Parse(typeof(Core.Blueprint.Mongo.StatusEnum), result["role"]["status"].AsString) : Core.Blueprint.Mongo.StatusEnum.Inactive, CreatedAt = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("createdAt") && !result["role"]["createdAt"].IsBsonNull ? result["role"]["createdAt"].ToUniversalTime() : DateTime.MinValue, UpdatedAt = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("updatedAt") && !result["role"]["updatedAt"].IsBsonNull ? result["role"]["updatedAt"].ToUniversalTime() : DateTime.MinValue, CreatedBy = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("createdBy") && !result["role"]["createdBy"].IsBsonNull ? result["role"]["createdBy"].AsString : string.Empty, UpdatedBy = result.Contains("role") && result["role"].IsBsonDocument && result["role"].AsBsonDocument.Contains("updatedBy") && !result["role"]["updatedBy"].IsBsonNull ? result["role"]["updatedBy"].AsString : string.Empty }, Permissions = result.Contains("permissions") && result["permissions"].IsBsonArray ? result["permissions"].AsBsonArray .Where(p => p != null && p.IsBsonDocument) .Select(p => BsonSerializer.Deserialize(p.AsBsonDocument)) .Where(p => p.Status == Core.Blueprint.Mongo.StatusEnum.Active) .ToList() : new List() }; return tokenAdapter; } catch (Exception ex) { throw new Exception(ex.Message, ex); } } /// /// Deletes an User by _id. /// /// The User mongo 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; } } }