diff --git a/src/modules/mix.portal/Controllers/MixDbController.cs b/src/modules/mix.portal/Controllers/MixDbController.cs index b9ac9939a..bcff23e7e 100644 --- a/src/modules/mix.portal/Controllers/MixDbController.cs +++ b/src/modules/mix.portal/Controllers/MixDbController.cs @@ -8,8 +8,10 @@ using Mix.Heart.Model; using Mix.Lib.Interfaces; using Mix.Lib.ViewModels.ReadOnly; +using Mix.RepoDb.Helpers; using Mix.RepoDb.Interfaces; using Mix.RepoDb.Repositories; +using Mix.RepoDb.ViewModels; using Mix.Service.Commands; using Mix.Service.Interfaces; using Mix.Service.Models; @@ -53,7 +55,7 @@ public class MixDbController : MixTenantApiControllerBase private readonly IMixDbService _mixDbService; private const string AssociationTableName = nameof(MixDatabaseAssociation); private IMixDbCommandHubClientService _mixDbCommandHubClientService; - private MixDatabaseViewModel _mixDb; + private RepoDbMixDatabaseViewModel _mixDb; public MixDbController( IHttpContextAccessor httpContextAccessor, IConfiguration configuration, @@ -167,7 +169,7 @@ public async Task Import([FromForm] IFormFile file) List lstDto = new(); foreach (var item in data) { - lstDto.Add(await ParseDtoToEntityAsync(item)); + lstDto.Add(await MixDbHelper.ParseImportDtoToEntityAsync(item, _mixDb.Columns, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username))); } var result = await _repository.InsertManyAsync(lstDto); @@ -349,7 +351,7 @@ public ActionResult CreateHub(object dto) [HttpPost] public async Task> Create(JObject dto) { - JObject obj = await ParseDtoToEntityAsync(dto); + JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username)); string username = _idService.GetClaim(User, MixClaims.Username); var id = await _repository.InsertAsync(obj); var resp = await _repository.GetSingleAsync(id); @@ -363,7 +365,7 @@ public async Task> Create(JObject dto) [HttpPut("{id}")] public async Task> Update(int id, [FromBody] JObject dto) { - JObject obj = await ParseDtoToEntityAsync(dto); + JObject obj = await MixDbHelper.ParseDtoToEntityAsync(dto, _mixDb.Columns, CurrentTenant.Id, _idService.GetClaim(User, MixClaims.Username)); string username = _idService.GetClaim(User, MixClaims.Username); var data = await _repository.UpdateAsync(obj); if (data != null) @@ -485,100 +487,7 @@ private async Task PatchHandler(JObject objDto, CancellationToken cancellationTo throw new MixException(MixErrorStatus.Badrequest, ex); } } - private Task ParseDtoToEntityAsync(JObject dto) - { - try - { - string username = _idService.GetClaim(User, MixClaims.Username); - JObject result = new(); - var encryptedColumnNames = _mixDb.Columns - .Where(m => m.ColumnConfigurations.IsEncrypt) - .Select(c => c.SystemName) - .ToList(); - foreach (var pr in dto.Properties()) - { - var col = _mixDb.Columns.FirstOrDefault(c => c.SystemName.Equals(pr.Name, StringComparison.InvariantCultureIgnoreCase)); - - if (encryptedColumnNames.Contains(pr.Name)) - { - result.Add( - new JProperty( - pr.Name.ToTitleCase(), AesEncryptionHelper.EncryptString(pr.Value.ToString(), - GlobalConfigService.Instance.AppSettings.ApiEncryptKey))); - } - else - { - if (col != null) - { - if (col.DataType == MixDataType.Json || col.DataType == MixDataType.ArrayRadio) - { - result.Add(new JProperty(pr.Name.ToTitleCase(), JObject.FromObject(pr.Value).ToString(Formatting.None))); - } - else if (col.DataType == MixDataType.Array || col.DataType == MixDataType.ArrayMedia) - { - - result.Add(new JProperty(pr.Name.ToTitleCase(), JArray.FromObject(pr.Value).ToString(Formatting.None))); - } - else - { - result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); - } - } - else - { - result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); - } - } - } - - if (!result.ContainsKey(IdFieldName)) - { - result.Add(new JProperty(IdFieldName, null)); - if (!result.ContainsKey(CreatedByFieldName)) - { - result.Add(new JProperty(CreatedByFieldName, username)); - } - if (!result.ContainsKey(CreatedDateFieldName)) - { - result.Add(new JProperty(CreatedDateFieldName, DateTime.UtcNow)); - } - if (!result.ContainsKey(CreatedByFieldName)) - { - result.Add(new JProperty(CreatedByFieldName, username)); - } - } - else - { - result[ModifiedByFieldName] = username; - result[LastModifiedFieldName] = DateTime.UtcNow; - } - - if (!result.ContainsKey(PriorityFieldName)) - { - result.Add(new JProperty(PriorityFieldName, 0)); - } - if (!result.ContainsKey(TenantIdFieldName)) - { - result.Add(new JProperty(TenantIdFieldName, CurrentTenant.Id)); - } - - if (!result.ContainsKey(StatusFieldName)) - { - result.Add(new JProperty(StatusFieldName, MixContentStatus.Published.ToString())); - } - - if (!result.ContainsKey(IsDeletedFieldName)) - { - result.Add(new JProperty(IsDeletedFieldName, false)); - } - return Task.FromResult(result); - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.Badrequest, ex); - } - } - + private async Task> SearchHandler(SearchMixDbRequestDto request) { try @@ -801,15 +710,15 @@ private List GetAssociationQueries(string parentDatabaseName = null, return queries; } - private async Task GetMixDatabase() + private async Task GetMixDatabase() { - string name = $"{typeof(MixDatabaseViewModel).FullName}_{_tableName}"; + string name = $"{typeof(RepoDbMixDatabaseViewModel).FullName}_{_tableName}"; return await _memoryCache.TryGetValueAsync( name, cache => { cache.SlidingExpiration = TimeSpan.FromSeconds(20); - return MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == _tableName); + return RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == _tableName); } ); } diff --git a/src/platform/mix.library/Services/MixThemeImportService.cs b/src/platform/mix.library/Services/MixThemeImportService.cs index 36f6c41c4..bb0e507eb 100644 --- a/src/platform/mix.library/Services/MixThemeImportService.cs +++ b/src/platform/mix.library/Services/MixThemeImportService.cs @@ -278,7 +278,7 @@ private async Task MigrateMixDatabaseAsync(IMixDbService mixDbService) } } } - + private async Task MigrateSystemMixDatabaseAsync(IMixDbService mixDbService, CancellationToken cancellationToken = default) { await mixDbService.MigrateSystemDatabases(cancellationToken); @@ -545,9 +545,9 @@ private async Task ImportDatabaseRelationshipsAsync(MixCmsContext dbContext) item.ChildId = _dicMixDatabaseIds[item.ChildId]; item.CreatedBy = _siteData.CreatedBy; item.CreatedDateTime = DateTime.UtcNow; - + if (!dbContext.MixDatabaseRelationship.Any( - m => m.ParentId == item.ParentId + m => m.ParentId == item.ParentId && m.ChildId == item.ChildId && m.DisplayName == item.DisplayName)) { @@ -759,7 +759,7 @@ private async Task ImportEntitiesAsync(MixCmsContext dbContext, List data, private async Task ImportContentDataAsync(List data, Dictionary dic, Dictionary parentDic) where T : MultilingualContentBase { - if (data!= null && data.Count > 0) + if (data != null && data.Count > 0) { foreach (var item in data) { diff --git a/src/platform/mix.repodb/Helpers/MixDbHelper.cs b/src/platform/mix.repodb/Helpers/MixDbHelper.cs new file mode 100644 index 000000000..d8b03f91b --- /dev/null +++ b/src/platform/mix.repodb/Helpers/MixDbHelper.cs @@ -0,0 +1,233 @@ +using Mix.Constant.Enums; +using Mix.Heart.Enums; +using Mix.Heart.Exceptions; +using Mix.Heart.Extensions; +using Mix.Heart.Helpers; +using Mix.Identity.Constants; +using Mix.RepoDb.ViewModels; +using Mix.Shared.Services; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mix.RepoDb.Helpers +{ + public class MixDbHelper + { + public const string CreatedByFieldName = "CreatedBy"; + public const string ModifiedByFieldName = "ModifiedBy"; + public const string LastModifiedFieldName = "LastModified"; + public const string CreatedDateFieldName = "CreatedDateTime"; + public const string PriorityFieldName = "Priority"; + public const string IdFieldName = "Id"; + public const string ParentIdFieldName = "ParentId"; + public const string ChildIdFieldName = "ChildId"; + public const string TenantIdFieldName = "MixTenantId"; + public const string StatusFieldName = "Status"; + public const string IsDeletedFieldName = "IsDeleted"; + + public static Task ParseDtoToEntityAsync(JObject dto, List columns, int? tenantId = null, string? username = null) + { + try + { + JObject result = new(); + var encryptedColumnNames = columns + .Where(m => m.ColumnConfigurations.IsEncrypt) + .Select(c => c.SystemName) + .ToList(); + foreach (var pr in dto.Properties()) + { + var col = columns.FirstOrDefault(c => c.SystemName.Equals(pr.Name, StringComparison.InvariantCultureIgnoreCase)); + + if (encryptedColumnNames.Contains(pr.Name)) + { + result.Add( + new JProperty( + pr.Name.ToTitleCase(), AesEncryptionHelper.EncryptString(pr.Value.ToString(), + GlobalConfigService.Instance.AppSettings.ApiEncryptKey))); + } + else + { + if (col != null) + { + if (col.DataType == MixDataType.Json || col.DataType == MixDataType.ArrayRadio) + { + result.Add(new JProperty(pr.Name.ToTitleCase(), JObject.FromObject(pr.Value).ToString(Formatting.None))); + } + else if (col.DataType == MixDataType.Array || col.DataType == MixDataType.ArrayMedia) + { + + result.Add(new JProperty(pr.Name.ToTitleCase(), JArray.FromObject(pr.Value).ToString(Formatting.None))); + } + else if (col.DataType == MixDataType.Boolean) + { + result.Add(new JProperty(pr.Name.ToTitleCase(), bool.Parse(pr.Value.ToString()))); + } + else + { + result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); + } + } + else + { + result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); + } + } + } + + if (!result.ContainsKey(IdFieldName)) + { + result.Add(new JProperty(IdFieldName, null)); + if (!result.ContainsKey(CreatedByFieldName)) + { + result.Add(new JProperty(CreatedByFieldName, username)); + } + if (!result.ContainsKey(CreatedDateFieldName)) + { + result.Add(new JProperty(CreatedDateFieldName, DateTime.UtcNow)); + } + if (!result.ContainsKey(CreatedByFieldName)) + { + result.Add(new JProperty(CreatedByFieldName, username)); + } + } + else + { + result[ModifiedByFieldName] = username; + result[LastModifiedFieldName] = DateTime.UtcNow; + } + + if (!result.ContainsKey(PriorityFieldName)) + { + result.Add(new JProperty(PriorityFieldName, 0)); + } + if (!result.ContainsKey(TenantIdFieldName)) + { + result.Add(new JProperty(TenantIdFieldName, tenantId)); + } + + if (!result.ContainsKey(StatusFieldName)) + { + result.Add(new JProperty(StatusFieldName, MixContentStatus.Published.ToString())); + } + + if (!result.ContainsKey(IsDeletedFieldName)) + { + result.Add(new JProperty(IsDeletedFieldName, false)); + } + return Task.FromResult(result); + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); + } + } + + public static Task ParseImportDtoToEntityAsync(JObject dto, List columns, int? tenantId = null, string? username = null) + { + try + { + JObject result = new(); + var encryptedColumnNames = columns + .Where(m => m.ColumnConfigurations.IsEncrypt) + .Select(c => c.SystemName) + .ToList(); + foreach (var pr in dto.Properties()) + { + var col = columns.FirstOrDefault(c => c.SystemName.Equals(pr.Name, StringComparison.InvariantCultureIgnoreCase)); + + if (encryptedColumnNames.Contains(pr.Name)) + { + result.Add( + new JProperty( + pr.Name.ToTitleCase(), AesEncryptionHelper.EncryptString(pr.Value.ToString(), + GlobalConfigService.Instance.AppSettings.ApiEncryptKey))); + } + else + { + if (col != null) + { + if (col.DataType == MixDataType.Json || col.DataType == MixDataType.ArrayRadio) + { + result.Add(new JProperty(pr.Name.ToTitleCase(), JObject.FromObject(pr.Value).ToString(Formatting.None))); + } + else if (col.DataType == MixDataType.Array || col.DataType == MixDataType.ArrayMedia) + { + + result.Add(new JProperty(pr.Name.ToTitleCase(), JArray.FromObject(pr.Value).ToString(Formatting.None))); + } + else if (col.DataType == MixDataType.Date || col.DataType == MixDataType.DateTime) + { + result.Add(new JProperty(pr.Name.ToTitleCase(), DateTime.Parse(pr.Value.ToString()))); + } + else if (col.DataType == MixDataType.Boolean) + { + result.Add(new JProperty(pr.Name.ToTitleCase(), bool.Parse(pr.Value.ToString()))); + } + else + { + result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); + } + } + else + { + result.Add(new JProperty(pr.Name.ToTitleCase(), pr.Value)); + } + } + } + + if (!result.ContainsKey(IdFieldName)) + { + result.Add(new JProperty(IdFieldName, null)); + if (!result.ContainsKey(CreatedByFieldName)) + { + result.Add(new JProperty(CreatedByFieldName, username)); + } + if (!result.ContainsKey(CreatedDateFieldName)) + { + result.Add(new JProperty(CreatedDateFieldName, DateTime.UtcNow)); + } + if (!result.ContainsKey(CreatedByFieldName)) + { + result.Add(new JProperty(CreatedByFieldName, username)); + } + } + else + { + result[CreatedDateFieldName] = DateTime.Parse(result[CreatedDateFieldName]!.ToString()); + result[ModifiedByFieldName] = username; + result[LastModifiedFieldName] = DateTime.UtcNow; + result[IsDeletedFieldName] = bool.Parse(result[IsDeletedFieldName]!.ToString()); + } + + if (!result.ContainsKey(PriorityFieldName)) + { + result.Add(new JProperty(PriorityFieldName, 0)); + } + if (!result.ContainsKey(TenantIdFieldName)) + { + result.Add(new JProperty(TenantIdFieldName, tenantId)); + } + + if (!result.ContainsKey(StatusFieldName)) + { + result.Add(new JProperty(StatusFieldName, MixContentStatus.Published.ToString())); + } + + if (!result.ContainsKey(IsDeletedFieldName)) + { + result.Add(new JProperty(IsDeletedFieldName, false)); + } + return Task.FromResult(result); + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); + } + } + } +} diff --git a/src/platform/mix.repodb/Services/MixDbDataService.cs b/src/platform/mix.repodb/Services/MixDbDataService.cs index 5c4827548..52b46f4bc 100644 --- a/src/platform/mix.repodb/Services/MixDbDataService.cs +++ b/src/platform/mix.repodb/Services/MixDbDataService.cs @@ -36,7 +36,7 @@ public class MixDbDataService : TenantServiceBase, IMixDbDataService private readonly MixRepoDbRepository _repository; private readonly MixRepoDbRepository _associationRepository; private readonly IMixMemoryCacheService _memoryCache; - private MixDatabaseViewModel? _mixDb; + private RepoDbMixDatabaseViewModel? _mixDb; #region Properties private readonly UnitOfWorkInfo _cmsUow; @@ -339,14 +339,14 @@ private List GetAssociationQueries(string? parentDatabaseName = null return queries; } - private async Task GetMixDatabase(string tableName) + private async Task GetMixDatabase(string tableName) { return await _memoryCache.TryGetValueAsync( tableName, cache => { cache.SlidingExpiration = TimeSpan.FromSeconds(20); - return MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == tableName); + return RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == tableName); } ); } diff --git a/src/platform/mix.repodb/Services/MixDbService.cs b/src/platform/mix.repodb/Services/MixDbService.cs index 4df526765..a5b437a76 100644 --- a/src/platform/mix.repodb/Services/MixDbService.cs +++ b/src/platform/mix.repodb/Services/MixDbService.cs @@ -356,14 +356,14 @@ private List GetAssociationQueries(string? parentDatabaseName = null return queries; } - private async Task GetMixDatabase(string tableName) + private async Task GetMixDatabase(string tableName) { return await _memoryCache.TryGetValueAsync( tableName, cache => { cache.SlidingExpiration = TimeSpan.FromSeconds(20); - return MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == tableName); + return RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == tableName); } ); } @@ -486,7 +486,7 @@ private Operation ParseSearchOperation(MixCompareOperator? searchMethod) // TODO: check why need to restart application to load new database schema for Repo Db Context !important public async Task MigrateDatabase(string name) { - MixDatabaseViewModel database = await MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); + RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); if (database.MixDatabaseContextId.HasValue) { @@ -543,7 +543,7 @@ public async Task MigrateSystemDatabases(CancellationToken cancellationTok if (!_cmsUow.DbContext.MixDatabase.Any(m => m.SystemName == database.SystemName)) { - MixDatabaseViewModel currentDb = new(database, _cmsUow); + RepoDbMixDatabaseViewModel currentDb = new(database, _cmsUow); currentDb.Id = 0; currentDb.MixTenantId = CurrentTenant?.Id ?? 1; currentDb.CreatedDateTime = DateTime.UtcNow; @@ -578,7 +578,7 @@ public async Task RestoreFromLocal(string name) { try { - MixDatabaseViewModel database = await MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); + RepoDbMixDatabaseViewModel database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == name); if (database is { Columns.Count: > 0 }) { return await RestoreFromLocal(database); @@ -597,7 +597,7 @@ public async Task RestoreFromLocal(string name) public async Task BackupDatabase(string databaseName, CancellationToken cancellationToken = default) { - var database = await MixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == databaseName, cancellationToken); + var database = await RepoDbMixDatabaseViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.SystemName == databaseName, cancellationToken); if (database != null) { return await BackupToLocal(database, cancellationToken); @@ -609,7 +609,7 @@ public async Task BackupDatabase(string databaseName, CancellationToken ca #region Private - private async Task BackupToLocal(MixDatabaseViewModel database, CancellationToken cancellationToken = default) + private async Task BackupToLocal(RepoDbMixDatabaseViewModel database, CancellationToken cancellationToken = default) { var data = await GetCurrentData(database.SystemName, cancellationToken); if (data is { Count: > 0 }) @@ -636,7 +636,7 @@ private void InitBackupRepository(string databaseName) } - private async Task RestoreFromLocal(MixDatabaseViewModel database) + private async Task RestoreFromLocal(RepoDbMixDatabaseViewModel database) { InitBackupRepository(database.SystemName); var data = await _backupRepository.GetAllAsync(); @@ -702,7 +702,7 @@ private string GetInsertQuery(ExpandoObject obj, List selectMembers) return await _repository.GetAllAsync(cancellationToken); } - private async Task Migrate(MixDatabaseViewModel database, + private async Task Migrate(RepoDbMixDatabaseViewModel database, MixDatabaseProvider databaseProvider, MixRepoDbRepository repo) { diff --git a/src/platform/mix.repodb/ViewModels/MixDatabaseViewModel.cs b/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs similarity index 94% rename from src/platform/mix.repodb/ViewModels/MixDatabaseViewModel.cs rename to src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs index 6b5502501..51d533c39 100644 --- a/src/platform/mix.repodb/ViewModels/MixDatabaseViewModel.cs +++ b/src/platform/mix.repodb/ViewModels/RepoDbMixDatabaseViewModel.cs @@ -6,8 +6,8 @@ namespace Mix.RepoDb.ViewModels { - public sealed class MixDatabaseViewModel - : TenantDataViewModelBase + public sealed class RepoDbMixDatabaseViewModel + : TenantDataViewModelBase { #region Properties public int? MixDatabaseContextId { get; set; } @@ -28,16 +28,16 @@ public sealed class MixDatabaseViewModel #region Constructors - public MixDatabaseViewModel() + public RepoDbMixDatabaseViewModel() { } - public MixDatabaseViewModel(UnitOfWorkInfo unitOfWorkInfo) : base(unitOfWorkInfo) + public RepoDbMixDatabaseViewModel(UnitOfWorkInfo unitOfWorkInfo) : base(unitOfWorkInfo) { } - public MixDatabaseViewModel(MixDatabase entity, UnitOfWorkInfo? uowInfo = null) + public RepoDbMixDatabaseViewModel(MixDatabase entity, UnitOfWorkInfo? uowInfo = null) : base(entity, uowInfo) { }