diff --git a/.github/workflows/develop_dev-mixcore.yml b/.github/workflows/develop_dev-mixcore.yml deleted file mode 100644 index ed3737fdb..000000000 --- a/.github/workflows/develop_dev-mixcore.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy -# More GitHub Actions for Azure: https://github.com/Azure/actions - -name: Build and deploy ASP.Net Core app to Azure Web App - dev-mixcore - -on: - push: - branches: - - develop - workflow_dispatch: - -jobs: - build: - runs-on: windows-latest - - steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Set up .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '7.x' - include-prerelease: true - - - name: Build with dotnet - run: dotnet build src/applications/Mixcore/mixcore.csproj --configuration Release - - - name: dotnet publish - run: dotnet publish src/applications/Mixcore/mixcore.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp - - - name: Upload artifact for deployment job - uses: actions/upload-artifact@v2 - with: - name: .net-app - path: ${{env.DOTNET_ROOT}}/myapp - - deploy: - runs-on: windows-latest - needs: build - environment: - name: 'Production' - url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} - - steps: - - name: Download artifact from build job - uses: actions/download-artifact@v2 - with: - name: .net-app - - - name: Deploy to Azure Web App - id: deploy-to-webapp - uses: azure/webapps-deploy@v2 - with: - app-name: 'dev-mixcore' - slot-name: 'Production' - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_401AAB0F55D04A1ABCF859E4A8B1463E }} - package: . diff --git a/src/applications/Mixcore/Domain/Services/MixSEORouteTransformer.cs b/src/applications/Mixcore/Domain/Services/MixSEORouteTransformer.cs index 021b77c95..5c6766a86 100644 --- a/src/applications/Mixcore/Domain/Services/MixSEORouteTransformer.cs +++ b/src/applications/Mixcore/Domain/Services/MixSEORouteTransformer.cs @@ -26,7 +26,7 @@ public override ValueTask TransformAsync( var language = (string)values[keys[0]]; string seoName = string.Empty; - if (_tenantService.AllCultures.Any(m => m.Specificulture == language)) + if (_tenantService.AllCultures != null && _tenantService.AllCultures.Any(m => m.Specificulture == language)) { seoName = string.Join('/', values.Values.Skip(1)); } diff --git a/src/applications/Mixcore/wwwroot/mix-app/js/app-portal.min.js b/src/applications/Mixcore/wwwroot/mix-app/js/app-portal.min.js index 402910c9c..6766c0386 100644 --- a/src/applications/Mixcore/wwwroot/mix-app/js/app-portal.min.js +++ b/src/applications/Mixcore/wwwroot/mix-app/js/app-portal.min.js @@ -1,4 +1,4 @@ -/* Wed Oct 18 2023 20:25:46 GMT+0700 (Indochina Time) */"use strict"; +/* Sun Oct 29 2023 13:00:18 GMT+0700 (Indochina Time) */"use strict"; var app = angular.module("MixPortal", [ "angularCroppie", "ui.bootstrap", @@ -419,9 +419,8 @@ app.controller("MixApplicationController", [ $scope.installStatus = "Downloading"; var resp = await service.install($scope.viewmodel); if (resp && resp.success) { - $scope.data = resp.data; $rootScope.isBusy = false; - $location.url("/admin/mix-application/list"); + $("html, body").animate({ scrollTop: "0px" }, 500); $scope.$apply(); } else { if (resp) { @@ -434,6 +433,7 @@ app.controller("MixApplicationController", [ $scope.restore = async function () { $rootScope.isBusy = true; $scope.installStatus = "Restoring"; + $("html, body").animate({ scrollTop: "0px" }, 500); var resp = await service.restore({ appId: $scope.viewmodel.id, packageFilePath: $scope.viewmodel.appSettings.activePackage, @@ -466,7 +466,11 @@ app.controller("MixApplicationController", [ $scope.$apply(); } break; - + case "Finished": + $scope.installStatus = "Finished"; + $location.url("/admin/mix-application/list"); + $scope.$apply(); + break; default: setTimeout(() => { $scope.status = msg.message; @@ -514,8 +518,8 @@ app.controller("MixApplicationController", [ $scope.viewMode = "list"; }; $scope.validate = function () { - if ($scope.viewmodel.baseHref.indexOf("/app/") != 0) { - $rootScope.showErrors(['baseHref must start with "/app/"']); + if ($scope.viewmodel.baseHref.indexOf("/mixapp/") != 0) { + $rootScope.showErrors(['baseHref must start with "/mixapp/"']); return false; } return true; @@ -666,6 +670,89 @@ app.factory("ConfigurationService", [ }, ]); +"use strict"; +app.controller("CultureController", [ + "$scope", + "$rootScope", + "ngAppSettings", + "$routeParams", + "CultureService", + "CommonService", + "ApiService", + function ( + $scope, + $rootScope, + ngAppSettings, + $routeParams, + service, + commonService, + apiService + ) { + $scope.selected = null; + BaseCtrl.call( + this, + $scope, + $rootScope, + $routeParams, + ngAppSettings, + service + ); + $scope.loadCultures = async function () { + var getCultures = await commonService.loadJsonData("cultures"); + $scope.cultures = getCultures.data.items; + $scope.$apply(); + }; + $scope.saveSuccessCallback = function () { + apiService + .initAllSettings() + .then(() => (window.location.href = "/admin/language/list")); + }; + $scope.removeCallback = function () { + apiService + .initAllSettings() + .then(() => (window.location.href = "/admin/language/list")); + }; + $scope.changeData = function (selected) { + if (selected) { + $scope.viewmodel.specificulture = selected.specificulture; + $scope.viewmodel.displayName = selected.fullName; + $scope.viewmodel.icon = selected.icon; + } + }; + }, +]); + +"use strict"; +app.factory("CultureService", [ + "BaseRestService", + function (baseService) { + var serviceFactory = Object.create(baseService); + serviceFactory.init("culture"); + var _updateInfos = async function (pages) { + var req = { + method: "POST", + url: this.prefixUrl + "/update-infos", + data: JSON.stringify(pages), + }; + return await apiService.sendRequest(req); + }; + + var _syncTemplates = async function (id) { + var apiUrl = "/culture/"; + var url = apiUrl + "sync/" + id; + var req = { + method: "GET", + url: url, + }; + return await apiService.sendRequest(req); + }; + + serviceFactory.syncTemplates = _syncTemplates; + serviceFactory.updateInfos = _updateInfos; + return serviceFactory; + }, +]); + "use strict"; app.controller("AuditLogController", [ "$scope", @@ -802,89 +889,6 @@ app.factory("AuditLogRestService", [ }, ]); -"use strict"; -app.controller("CultureController", [ - "$scope", - "$rootScope", - "ngAppSettings", - "$routeParams", - "CultureService", - "CommonService", - "ApiService", - function ( - $scope, - $rootScope, - ngAppSettings, - $routeParams, - service, - commonService, - apiService - ) { - $scope.selected = null; - BaseCtrl.call( - this, - $scope, - $rootScope, - $routeParams, - ngAppSettings, - service - ); - $scope.loadCultures = async function () { - var getCultures = await commonService.loadJsonData("cultures"); - $scope.cultures = getCultures.data.items; - $scope.$apply(); - }; - $scope.saveSuccessCallback = function () { - apiService - .initAllSettings() - .then(() => (window.location.href = "/admin/language/list")); - }; - $scope.removeCallback = function () { - apiService - .initAllSettings() - .then(() => (window.location.href = "/admin/language/list")); - }; - $scope.changeData = function (selected) { - if (selected) { - $scope.viewmodel.specificulture = selected.specificulture; - $scope.viewmodel.displayName = selected.fullName; - $scope.viewmodel.icon = selected.icon; - } - }; - }, -]); - -"use strict"; -app.factory("CultureService", [ - "BaseRestService", - function (baseService) { - var serviceFactory = Object.create(baseService); - serviceFactory.init("culture"); - var _updateInfos = async function (pages) { - var req = { - method: "POST", - url: this.prefixUrl + "/update-infos", - data: JSON.stringify(pages), - }; - return await apiService.sendRequest(req); - }; - - var _syncTemplates = async function (id) { - var apiUrl = "/culture/"; - var url = apiUrl + "sync/" + id; - var req = { - method: "GET", - url: url, - }; - return await apiService.sendRequest(req); - }; - - serviceFactory.syncTemplates = _syncTemplates; - serviceFactory.updateInfos = _updateInfos; - return serviceFactory; - }, -]); - "use strict"; app.controller("CustomerController", [ "$scope", @@ -1949,20 +1953,26 @@ app.controller("loginController", [ ]); "use strict"; -app.controller("MixDatabaseDataController", [ +app.controller("MixDatabaseController", [ "$scope", "$rootScope", + "$location", "ngAppSettings", "$routeParams", - "$location", - "MixDbService", + "RestMixDatabaseDataPortalService", + "RestMixDatabaseColumnPortalService", + "RestMixDatabasePortalService", + "RestMixDatabaseContextService", function ( $scope, $rootScope, + $location, ngAppSettings, $routeParams, - $location, - mixDbService + databaseDataService, + databaseColumnService, + databaseService, + dbContextService ) { BaseRestCtrl.call( this, @@ -1971,50 +1981,189 @@ app.controller("MixDatabaseDataController", [ $location, $routeParams, ngAppSettings, - mixDbService + databaseService ); - $scope.queries = {}; - $scope.data = null; - $scope.exportAll = true; - $scope.mixConfigurations = $rootScope.globalSettings; - $scope.filterType = "contain"; - $scope.defaultId = "default"; - $scope.importFile = { - file: null, - fullPath: "", - folder: "import", - title: "", - description: "", + $scope.defaultAttr = null; + $scope.actions = ["Delete"]; + $scope.viewmodelType = "mix-database"; + // $scope.request.selects = 'id,title,name,createdDateTime'; + $scope.orders = [ + { title: "Id", value: "Id" }, + { title: "Name", value: "Name" }, + { title: "Created Date", value: "CreatedDateTime" }, + ]; + $scope.request.orderBy = "CreatedDateTime"; + $scope.request.columns = "id,displayName,systemName,type,createdDatetime"; + $scope.request.searchColumns = "displayName,systemName"; + $scope.saveDatabase = function () { + $scope.save($scope.viewmodel); }; - $scope.initRouteParams = () => { - $scope.requestKey = `request${$rootScope.generateKeyword( - $location.$$path, - "_" - )}_${$routeParams.mixDatabaseId}`; - $scope.request = $rootScope.getRequest($scope.requestKey); - if ($routeParams.mixDatabaseId) { - $scope.request.mixDatabaseId = $routeParams.mixDatabaseId; + + $scope.getSingleSuccessCallback = async function () { + $scope.viewmodel.mixDatabaseContextId = $routeParams.mixDatabaseContextId; + if ($scope.viewmodel.mixDatabaseContextId) { + var resp = await dbContextService.getSingle([ + $scope.viewmodel.mixDatabaseContextId, + ]); + if (resp.success) { + $scope.dbContext = resp.data; + } } - if ($routeParams.queryFields) { - if (Array.isArray($routeParams.queryFields)) { - angular.forEach($routeParams.queryFields, (e) => { - let val = e.split(":"); - $scope.queries[val[0]] = val[1]; - }); - } else { - let val = $routeParams.queryFields.split(":"); - $scope.queries[val[0]] = val[1]; + if (!$scope.defaultAttr) { + var getDefaultAttr = await databaseColumnService.getDefault(); + if (getDefaultAttr.success) { + $scope.defaultAttr = getDefaultAttr.data; + $scope.defaultAttr.options = []; } - $scope.request.mixDatabaseId = $routeParams.mixDatabaseId; + $scope.$apply(); } - $scope.request.mixDatabaseName = $routeParams.mixDatabaseName; - $scope.request.filterType = $routeParams.filterType || "contain"; - $scope.request.compareType = $routeParams.compareType || "or"; - - $scope.mixDatabaseId = $routeParams.mixDatabaseId; - $scope.mixDatabaseName = $routeParams.mixDatabaseName; - $scope.mixDatabaseTitle = $routeParams.mixDatabaseTitle; - $scope.guidParentId = $routeParams.guidParentId; + }; + $scope.migrate = async function () { + if ($scope.viewmodel.id) { + $rootScope.isBusy = true; + var result = await databaseService.migrate($scope.viewmodel); + if (result.success) { + $rootScope.showMessage( + "Please restart pool to apply new db schema", + "warning" + ); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(["Cannot migrate database"]); + $rootScope.isBusy = false; + $scope.$apply(); + } + } + }; + $scope.backup = async function () { + if ($scope.viewmodel.id) { + $rootScope.isBusy = true; + var result = await databaseService.backup($scope.viewmodel); + if (result.success) { + $rootScope.showMessage( + `Backup ${$scope.viewmodel.systemName} is queued`, + "success" + ); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(["Cannot backup database"]); + $rootScope.isBusy = false; + $scope.$apply(); + } + } + }; + $scope.restore = async function () { + if ($scope.viewmodel.id) { + $rootScope.isBusy = true; + var result = await databaseService.restore($scope.viewmodel); + if (result.success) { + $rootScope.showMessage( + `Restore ${$scope.viewmodel.systemName} is queued`, + "success" + ); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(["Cannot restore database"]); + $rootScope.isBusy = false; + $scope.$apply(); + } + } + }; + $scope.updateSchema = async function () { + if ($scope.viewmodel.id) { + $rootScope.isBusy = true; + var result = await databaseService.updateSchema($scope.viewmodel); + if (result.success) { + $rootScope.showMessage( + "Please restart pool to apply new db schema", + "warning" + ); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(["Cannot update database"]); + $rootScope.isBusy = false; + $scope.$apply(); + } + } + }; + + $scope.back = function () { + window.history.back(); + }; + }, +]); + +"use strict"; +app.controller("MixDatabaseDataController", [ + "$scope", + "$rootScope", + "ngAppSettings", + "$routeParams", + "$location", + "MixDbService", + function ( + $scope, + $rootScope, + ngAppSettings, + $routeParams, + $location, + mixDbService + ) { + BaseRestCtrl.call( + this, + $scope, + $rootScope, + $location, + $routeParams, + ngAppSettings, + mixDbService + ); + $scope.queries = {}; + $scope.data = null; + $scope.exportAll = true; + $scope.mixConfigurations = $rootScope.globalSettings; + $scope.filterType = "contain"; + $scope.defaultId = "default"; + $scope.importFile = { + file: null, + fullPath: "", + folder: "import", + title: "", + description: "", + }; + $scope.initRouteParams = () => { + $scope.requestKey = `request${$rootScope.generateKeyword( + $location.$$path, + "_" + )}_${$routeParams.mixDatabaseId}`; + $scope.request = $rootScope.getRequest($scope.requestKey); + if ($routeParams.mixDatabaseId) { + $scope.request.mixDatabaseId = $routeParams.mixDatabaseId; + } + if ($routeParams.queryFields) { + if (Array.isArray($routeParams.queryFields)) { + angular.forEach($routeParams.queryFields, (e) => { + let val = e.split(":"); + $scope.queries[val[0]] = val[1]; + }); + } else { + let val = $routeParams.queryFields.split(":"); + $scope.queries[val[0]] = val[1]; + } + $scope.request.mixDatabaseId = $routeParams.mixDatabaseId; + } + $scope.request.mixDatabaseName = $routeParams.mixDatabaseName; + $scope.request.filterType = $routeParams.filterType || "contain"; + $scope.request.compareType = $routeParams.compareType || "or"; + + $scope.mixDatabaseId = $routeParams.mixDatabaseId; + $scope.mixDatabaseName = $routeParams.mixDatabaseName; + $scope.mixDatabaseTitle = $routeParams.mixDatabaseTitle; + $scope.guidParentId = $routeParams.guidParentId; $scope.parentType = $routeParams.parentType; $scope.request.mixDatabaseName = $routeParams.mixDatabaseName; $scope.request.isGroup = $routeParams.isGroup || false; @@ -2300,15 +2449,12 @@ app.controller("MixDatabaseDataController", [ ]); "use strict"; -app.controller("MixDatabaseController", [ +app.controller("MixDatabaseContextController", [ "$scope", "$rootScope", "$location", "ngAppSettings", "$routeParams", - "RestMixDatabaseDataPortalService", - "RestMixDatabaseColumnPortalService", - "RestMixDatabasePortalService", "RestMixDatabaseContextService", function ( $scope, @@ -2316,10 +2462,7 @@ app.controller("MixDatabaseController", [ $location, ngAppSettings, $routeParams, - databaseDataService, - databaseColumnService, - databaseService, - dbContextService + mixdbContextService ) { BaseRestCtrl.call( this, @@ -2328,15 +2471,15 @@ app.controller("MixDatabaseController", [ $location, $routeParams, ngAppSettings, - databaseService + mixdbContextService ); $scope.defaultAttr = null; + $scope.databaseProvider = ["MySQL", "PostgreSQL", "SQLITE", "SQLSERVER"]; $scope.actions = ["Delete"]; - $scope.viewmodelType = "mix-database"; // $scope.request.selects = 'id,title,name,createdDateTime'; $scope.orders = [ { title: "Id", value: "Id" }, - { title: "Name", value: "Name" }, + { title: "Name", value: "DisplayName" }, { title: "Created Date", value: "CreatedDateTime" }, ]; $scope.request.orderBy = "CreatedDateTime"; @@ -2345,221 +2488,82 @@ app.controller("MixDatabaseController", [ $scope.saveDatabase = function () { $scope.save($scope.viewmodel); }; + $scope.generateName = function () { + $scope.viewmodel.systemName = $rootScope.generateKeyword( + $scope.viewmodel.displayName, + "_", + true, + true + ); + }; + $scope.getSingleSuccessCallback = async function () {}; + }, +]); - $scope.getSingleSuccessCallback = async function () { - $scope.viewmodel.mixDatabaseContextId = $routeParams.mixDatabaseContextId; - if ($scope.viewmodel.mixDatabaseContextId) { - var resp = await dbContextService.getSingle([ - $scope.viewmodel.mixDatabaseContextId, - ]); - if (resp.success) { - $scope.dbContext = resp.data; - } - } - if (!$scope.defaultAttr) { - var getDefaultAttr = await databaseColumnService.getDefault(); - if (getDefaultAttr.success) { - $scope.defaultAttr = getDefaultAttr.data; - $scope.defaultAttr.options = []; - } - $scope.$apply(); - } - }; - $scope.migrate = async function () { - if ($scope.viewmodel.id) { - $rootScope.isBusy = true; - var result = await databaseService.migrate($scope.viewmodel); - if (result.success) { - $rootScope.showMessage( - "Please restart pool to apply new db schema", - "warning" - ); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(["Cannot migrate database"]); - $rootScope.isBusy = false; - $scope.$apply(); - } - } - }; - $scope.backup = async function () { - if ($scope.viewmodel.id) { - $rootScope.isBusy = true; - var result = await databaseService.backup($scope.viewmodel); - if (result.success) { - $rootScope.showMessage( - `Backup ${$scope.viewmodel.systemName} is queued`, - "success" - ); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(["Cannot backup database"]); - $rootScope.isBusy = false; - $scope.$apply(); - } - } - }; - $scope.restore = async function () { - if ($scope.viewmodel.id) { - $rootScope.isBusy = true; - var result = await databaseService.restore($scope.viewmodel); - if (result.success) { - $rootScope.showMessage( - `Restore ${$scope.viewmodel.systemName} is queued`, - "success" - ); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(["Cannot restore database"]); - $rootScope.isBusy = false; - $scope.$apply(); - } - } - }; - $scope.updateSchema = async function () { - if ($scope.viewmodel.id) { - $rootScope.isBusy = true; - var result = await databaseService.updateSchema($scope.viewmodel); - if (result.success) { - $rootScope.showMessage( - "Please restart pool to apply new db schema", - "warning" - ); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(["Cannot update database"]); - $rootScope.isBusy = false; - $scope.$apply(); - } - } - }; - - $scope.back = function () { - window.history.back(); - }; - }, -]); - -"use strict"; -app.controller("MixDatabaseContextController", [ - "$scope", - "$rootScope", - "$location", - "ngAppSettings", - "$routeParams", - "RestMixDatabaseContextService", - function ( - $scope, - $rootScope, - $location, - ngAppSettings, - $routeParams, - mixdbContextService - ) { - BaseRestCtrl.call( - this, - $scope, - $rootScope, - $location, - $routeParams, - ngAppSettings, - mixdbContextService - ); - $scope.defaultAttr = null; - $scope.databaseProvider = ["MySQL", "PostgreSQL", "SQLITE", "SQLSERVER"]; - $scope.actions = ["Delete"]; - // $scope.request.selects = 'id,title,name,createdDateTime'; - $scope.orders = [ - { title: "Id", value: "Id" }, - { title: "Name", value: "DisplayName" }, - { title: "Created Date", value: "CreatedDateTime" }, - ]; - $scope.request.orderBy = "CreatedDateTime"; - $scope.request.columns = "id,displayName,systemName,type,createdDatetime"; - $scope.request.searchColumns = "displayName,systemName"; - $scope.saveDatabase = function () { - $scope.save($scope.viewmodel); - }; - $scope.generateName = function () { - $scope.viewmodel.systemName = $rootScope.generateKeyword( - $scope.viewmodel.displayName, - "_", - true, - true - ); - }; - $scope.getSingleSuccessCallback = async function () {}; - }, -]); - -"use strict"; -app.factory("RestMixDatabaseContextService", [ - "BaseRestService", - function (baseService) { - var serviceFactory = Object.create(baseService); - serviceFactory.init("mixdb-context"); - - var _getByName = async function (name) { - var url = `${this.prefixUrl}/get-by-name/${name}`; - var req = { - method: "GET", - url: url, - }; - return await this.getRestApiResult(req); - }; - serviceFactory.getByName = _getByName; - return serviceFactory; - }, -]); - -"use strict"; -app.controller("ModuleController", [ - "$scope", - "$rootScope", - "ngAppSettings", - "$location", - "$routeParams", - "ModuleRestService", - "SharedModuleDataService", - "RestMixDatabaseDataPortalService", - "RestMixDatabaseColumnPortalService", - function ( - $scope, - $rootScope, - ngAppSettings, - $location, - $routeParams, - moduleServices, - moduleDataService, - dataService, - columnService - ) { - BaseRestCtrl.call( - this, - $scope, - $rootScope, - $location, - $routeParams, - ngAppSettings, - moduleServices, - "product" - ); - $scope.request.culture = $rootScope.globalSettings.defaultCulture; - $scope.viewmodelType = "module"; - $scope.contentUrl = ""; - $scope.getSingleSuccessCallback = function () { - $scope.loadAdditionalData(); - - if ($scope.viewmodel.id > 0) { - // module => list post or list product - if ($scope.viewmodel.type.localeCompare("ListPost") == 0) { - $scope.contentUrl = "/admin/module-post/list/" + $scope.viewmodel.id; - } else if ($scope.viewmodel.type.localeCompare("Data") == 0) { - $scope.contentUrl = "/admin/module-data/list/" + $scope.viewmodel.id; +"use strict"; +app.factory("RestMixDatabaseContextService", [ + "BaseRestService", + function (baseService) { + var serviceFactory = Object.create(baseService); + serviceFactory.init("mixdb-context"); + + var _getByName = async function (name) { + var url = `${this.prefixUrl}/get-by-name/${name}`; + var req = { + method: "GET", + url: url, + }; + return await this.getRestApiResult(req); + }; + serviceFactory.getByName = _getByName; + return serviceFactory; + }, +]); + +"use strict"; +app.controller("ModuleController", [ + "$scope", + "$rootScope", + "ngAppSettings", + "$location", + "$routeParams", + "ModuleRestService", + "SharedModuleDataService", + "RestMixDatabaseDataPortalService", + "RestMixDatabaseColumnPortalService", + function ( + $scope, + $rootScope, + ngAppSettings, + $location, + $routeParams, + moduleServices, + moduleDataService, + dataService, + columnService + ) { + BaseRestCtrl.call( + this, + $scope, + $rootScope, + $location, + $routeParams, + ngAppSettings, + moduleServices, + "product" + ); + $scope.request.culture = $rootScope.globalSettings.defaultCulture; + $scope.viewmodelType = "module"; + $scope.contentUrl = ""; + $scope.getSingleSuccessCallback = function () { + $scope.loadAdditionalData(); + + if ($scope.viewmodel.id > 0) { + // module => list post or list product + if ($scope.viewmodel.type.localeCompare("ListPost") == 0) { + $scope.contentUrl = "/admin/module-post/list/" + $scope.viewmodel.id; + } else if ($scope.viewmodel.type.localeCompare("Data") == 0) { + $scope.contentUrl = "/admin/module-data/list/" + $scope.viewmodel.id; } } if ($scope.viewmodel.sysCategories) { @@ -4249,34 +4253,22 @@ app.factory("RestPortalPageNavigationService", [ ]); "use strict"; -app.controller("PostController", [ +app.controller("QueueLogController", [ "$scope", "$rootScope", - "$location", - "$filter", "ngAppSettings", + "$location", "$routeParams", - "PostRestService", - "UrlAliasService", - "RestMixDatabaseDataPortalService", - "RestMixDatabaseColumnPortalService", - "RestRelatedAttributeDataPortalService", - "RestMixDatabasePortalService", - "MixDbService", + "AuthService", + "QueueLogRestService", function ( $scope, $rootScope, - $location, - $filter, ngAppSettings, + $location, $routeParams, - service, - urlAliasService, - dataService, - columnService, - navService, - databaseService, - mixDbService + authService, + service ) { BaseRestCtrl.call( this, @@ -4287,19 +4279,134 @@ app.controller("PostController", [ ngAppSettings, service ); - if (!$scope.referrerUrl) { - $scope.referrerUrl = "/admin/post/list"; - } - $scope.request.searchColumns = "title"; - $scope.request.culture = $rootScope.globalSettings.defaultCulture; - $scope.request.queries = []; - $scope.request.metadataQueries = []; - $scope.defaultQuery = { - fieldName: "", - compareOperator: "Equal", - value: "", + authService.fillAuthData(); + $scope.request.status = null; + $scope.messages = []; + $scope.canDrag = + $scope.request.orderBy !== "Priority" || $scope.request.direction !== "0"; + $scope.getListSuccessCallback = function () { + angular.forEach($scope.data.items, function (e) { + switch (e.state) { + case "ACK": + e.objClass = "text-success"; + break; + case "NACK": + e.objClass = "text-warning"; + break; + case "FAILED": + e.objClass = "text-danger"; + break; + default: + e.objClass = "text-info"; + break; + } + }); }; - $scope.viewmodelType = "post"; + $scope.view = function (item) { + switch (item.state) { + case "ACK": + item.objClass = "text-success"; + break; + case "NACK": + item.objClass = "text-warning"; + break; + case "FAILED": + item.objClass = "text-danger"; + break; + default: + item.objClass = "text-info"; + break; + } + $rootScope.preview("object", item, null, "modal-lg"); + }; + }, +]); + +"use strict"; +app.factory("QueueLogRestService", [ + "BaseRestService", + function (baseService) { + var serviceFactory = angular.copy(baseService); + serviceFactory.initService("/rest", "mix-log/queue-log", true); + var _search = async function (objData, queries = null) { + var data = serviceFactory.parseQuery(objData); + + var url = `${this.prefixUrl}/search`; + + if (data) { + url += "?"; + url = url.concat(data); + if (queries) { + url += "&"; + var extraQueries = serviceFactory.parseQuery(queries); + url = url.concat(extraQueries); + } + } + var req = { + serviceBase: this.serviceBase, + apiVersion: this.apiVersion, + method: "GET", + url: url, + }; + return await this.getRestApiResult(req); + }; + serviceFactory.getList = _search; + return serviceFactory; + }, +]); + +"use strict"; +app.controller("PostController", [ + "$scope", + "$rootScope", + "$location", + "$filter", + "ngAppSettings", + "$routeParams", + "PostRestService", + "UrlAliasService", + "RestMixDatabaseDataPortalService", + "RestMixDatabaseColumnPortalService", + "RestRelatedAttributeDataPortalService", + "RestMixDatabasePortalService", + "MixDbService", + function ( + $scope, + $rootScope, + $location, + $filter, + ngAppSettings, + $routeParams, + service, + urlAliasService, + dataService, + columnService, + navService, + databaseService, + mixDbService + ) { + BaseRestCtrl.call( + this, + $scope, + $rootScope, + $location, + $routeParams, + ngAppSettings, + service + ); + if (!$scope.referrerUrl) { + $scope.referrerUrl = "/admin/post/list"; + } + $scope.request.searchColumns = "title"; + $scope.request.culture = $rootScope.globalSettings.defaultCulture; + $scope.request.queries = []; + $scope.request.metadataQueries = []; + $scope.defaultQuery = { + fieldName: "", + compareOperator: "Equal", + value: "", + }; + $scope.viewmodelType = "post"; $scope.additionalData = {}; $scope.createUrl = "/admin/post/create?"; $scope.postTypeRequest = angular.copy(ngAppSettings.request); @@ -4742,109 +4849,6 @@ app.factory("PostRestService", [ }, ]); -"use strict"; -app.controller("QueueLogController", [ - "$scope", - "$rootScope", - "ngAppSettings", - "$location", - "$routeParams", - "AuthService", - "QueueLogRestService", - function ( - $scope, - $rootScope, - ngAppSettings, - $location, - $routeParams, - authService, - service - ) { - BaseRestCtrl.call( - this, - $scope, - $rootScope, - $location, - $routeParams, - ngAppSettings, - service - ); - authService.fillAuthData(); - $scope.request.status = null; - $scope.messages = []; - $scope.canDrag = - $scope.request.orderBy !== "Priority" || $scope.request.direction !== "0"; - $scope.getListSuccessCallback = function () { - angular.forEach($scope.data.items, function (e) { - switch (e.state) { - case "ACK": - e.objClass = "text-success"; - break; - case "NACK": - e.objClass = "text-warning"; - break; - case "FAILED": - e.objClass = "text-danger"; - break; - default: - e.objClass = "text-info"; - break; - } - }); - }; - $scope.view = function (item) { - switch (item.state) { - case "ACK": - item.objClass = "text-success"; - break; - case "NACK": - item.objClass = "text-warning"; - break; - case "FAILED": - item.objClass = "text-danger"; - break; - default: - item.objClass = "text-info"; - break; - } - $rootScope.preview("object", item, null, "modal-lg"); - }; - }, -]); - -"use strict"; -app.factory("QueueLogRestService", [ - "BaseRestService", - function (baseService) { - var serviceFactory = angular.copy(baseService); - serviceFactory.initService("/rest", "mix-log/queue-log", true); - var _search = async function (objData, queries = null) { - var data = serviceFactory.parseQuery(objData); - - var url = `${this.prefixUrl}/search`; - - if (data) { - url += "?"; - url = url.concat(data); - if (queries) { - url += "&"; - var extraQueries = serviceFactory.parseQuery(queries); - url = url.concat(extraQueries); - } - } - var req = { - serviceBase: this.serviceBase, - apiVersion: this.apiVersion, - method: "GET", - url: url, - }; - return await this.getRestApiResult(req); - }; - serviceFactory.getList = _search; - return serviceFactory; - }, -]); - "use strict"; app.controller("RoleController", [ "$scope", @@ -5981,54 +5985,6 @@ app.controller("TemplateController", [ }, ]); -"use strict"; -app.controller("TenantController", [ - "$scope", - "$rootScope", - "ngAppSettings", - "$location", - "$routeParams", - "TenantRestService", - function ( - $scope, - $rootScope, - ngAppSettings, - $location, - $routeParams, - service - ) { - BaseRestCtrl.call( - this, - $scope, - $rootScope, - $location, - $routeParams, - ngAppSettings, - service - ); - $scope.request.columns = [ - "id", - "displayName", - "systemName", - "primaryDomain", - "createdDateTime", - "createdBy", - ]; - $scope.canDrag = - $scope.request.orderBy !== "Priority" || $scope.request.direction !== "0"; - }, -]); - -"use strict"; -app.factory("TenantRestService", [ - "BaseRestService", - function (baseService) { - var serviceFactory = Object.create(baseService); - serviceFactory.init("mix-tenant"); - return serviceFactory; - }, -]); - "use strict"; app.controller("ThemeController", [ "$scope", @@ -6177,87 +6133,50 @@ app.controller("ThemeController", [ ]); "use strict"; -app.controller("ThemeImportController", [ +app.controller("TenantController", [ "$scope", "$rootScope", "ngAppSettings", - "$routeParams", "$location", - "ApiService", - "TenancyService", + "$routeParams", + "TenantRestService", function ( $scope, $rootScope, ngAppSettings, - $routeParams, $location, - apiService, - tenancyService + $routeParams, + service ) { - $scope.importData = null; - $scope.init = function () {}; - $scope.getSingleSuccessCallback = function () { - $scope.assets = null; - $scope.theme = null; - }; - $scope.submit = async function () { - $scope.form = document.getElementById("form-portal"); - let theme = $scope.form["theme"].files[0]; - if (theme) { - await $scope.extract(theme); - document.getElementById("form-portal")["theme"].value = ""; - } else { - $scope.import(); - } - }; - $scope.extract = async function (theme) { - $rootScope.isBusy = true; - var frm = new FormData(); - var url = "/rest/mix-tenancy/setup/extract-theme"; - $rootScope.isBusy = true; - // Looping over all files and add it to FormData object - frm.append("theme", theme); - // Adding one more key to FormData object - frm.append("model", angular.toJson($scope.data)); - var response = await apiService.ajaxSubmitForm(frm, url); - $rootScope.isBusy = false; - if (response.success) { - var getData = await $scope.loadTheme(); - if (getData.success) { - $scope.importThemeDto = getData.data; - $rootScope.isBusy = false; - $scope.$apply(); - } - } else { - $rootScope.showErrors(response.errors); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - - $scope.loadTheme = async function () { - var req = { - method: "GET", - url: "/rest/mix-tenancy/setup/load-theme", - }; - return await apiService.sendRequest(req); - }; - - $scope.import = async function () { - $scope.importThemeDto.themeId = $routeParams.id; - $rootScope.isBusy = true; - var response = await tenancyService.import($scope.importThemeDto); + BaseRestCtrl.call( + this, + $scope, + $rootScope, + $location, + $routeParams, + ngAppSettings, + service + ); + $scope.request.columns = [ + "id", + "displayName", + "systemName", + "primaryDomain", + "createdDateTime", + "createdBy", + ]; + $scope.canDrag = + $scope.request.orderBy !== "Priority" || $scope.request.direction !== "0"; + }, +]); - if (response.success) { - $rootScope.isBusy = false; - window.open("/", "_blank"); - $scope.$apply(); - } else { - $rootScope.showErrors(response.errors); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; +"use strict"; +app.factory("TenantRestService", [ + "BaseRestService", + function (baseService) { + var serviceFactory = Object.create(baseService); + serviceFactory.init("mix-tenant"); + return serviceFactory; }, ]); @@ -6390,6 +6309,91 @@ app.factory("UrlAliasService", [ }, ]); +"use strict"; +app.controller("ThemeImportController", [ + "$scope", + "$rootScope", + "ngAppSettings", + "$routeParams", + "$location", + "ApiService", + "TenancyService", + function ( + $scope, + $rootScope, + ngAppSettings, + $routeParams, + $location, + apiService, + tenancyService + ) { + $scope.importData = null; + $scope.init = function () {}; + $scope.getSingleSuccessCallback = function () { + $scope.assets = null; + $scope.theme = null; + }; + $scope.submit = async function () { + $scope.form = document.getElementById("form-portal"); + let theme = $scope.form["theme"].files[0]; + if (theme) { + await $scope.extract(theme); + document.getElementById("form-portal")["theme"].value = ""; + } else { + $scope.import(); + } + }; + $scope.extract = async function (theme) { + $rootScope.isBusy = true; + var frm = new FormData(); + var url = "/rest/mix-tenancy/setup/extract-theme"; + $rootScope.isBusy = true; + // Looping over all files and add it to FormData object + frm.append("theme", theme); + // Adding one more key to FormData object + frm.append("model", angular.toJson($scope.data)); + var response = await apiService.ajaxSubmitForm(frm, url); + $rootScope.isBusy = false; + if (response.success) { + var getData = await $scope.loadTheme(); + if (getData.success) { + $scope.importThemeDto = getData.data; + $rootScope.isBusy = false; + $scope.$apply(); + } + } else { + $rootScope.showErrors(response.errors); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + + $scope.loadTheme = async function () { + var req = { + method: "GET", + url: "/rest/mix-tenancy/setup/load-theme", + }; + return await apiService.sendRequest(req); + }; + + $scope.import = async function () { + $scope.importThemeDto.themeId = $routeParams.id; + $rootScope.isBusy = true; + var response = await tenancyService.import($scope.importThemeDto); + + if (response.success) { + $rootScope.isBusy = false; + window.open("/", "_blank"); + $scope.$apply(); + } else { + $rootScope.showErrors(response.errors); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + }, +]); + "use strict"; app.controller("UserController", [ "$scope", @@ -7171,20 +7175,6 @@ app.component("appSettingsGeneral", { }, }); -app.component("appSettingsSmtp", { - templateUrl: - "/mix-app/views/app-portal/pages/app-settings/components/smtp/view.html", - controller: [ - "ngAppSettings", - function (ngAppSettings) { - var ctrl = this; - }, - ], - bindings: { - appSettings: "=", - }, -}); - modules.component("portalMenus", { templateUrl: "/mix-app/views/app-portal/pages/app-settings/components/portal-menus/view.html", @@ -7217,48 +7207,23 @@ modules.component("portalMenus", { ], }); -app.component("customerMain", { +app.component("appSettingsSmtp", { templateUrl: - "/mix-app/views/app-portal/pages/customer/components/main/customer-main.html", + "/mix-app/views/app-portal/pages/app-settings/components/smtp/view.html", + controller: [ + "ngAppSettings", + function (ngAppSettings) { + var ctrl = this; + }, + ], bindings: { - customer: "=", - onDelete: "&", - onUpdate: "&", + appSettings: "=", }, }); -app.component("customerOrders", { +app.component("customerMain", { templateUrl: - "/mix-app/views/app-portal/pages/customer/components/orders/customer-orders.html", - controller: [ - "$rootScope", - "OrderServices", - function ($rootScope, orderServices) { - var ctrl = this; - ctrl.removeOrder = function (id) { - $rootScope.showConfirm( - ctrl, - "removeOrderConfirmed", - [id], - null, - "Remove Order", - "Deleted data will not able to recover, are you sure you want to delete this item?" - ); - }; - - ctrl.removeOrderConfirmed = async function (id) { - var result = await orderServices.removeOrder(id); - if (result.success) { - $rootScope.showMessage("success", "success"); - window.top.location = window.top.location.href; - } else { - $rootScope.showMessage("failed"); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - }, - ], + "/mix-app/views/app-portal/pages/customer/components/main/customer-main.html", bindings: { customer: "=", onDelete: "&", @@ -7319,12 +7284,51 @@ app.component("mixDatabaseMain", { }, }); -app.component("mixdbContextDatabases", { - bindings: { - model: "=", - }, +app.component("customerOrders", { templateUrl: - "/mix-app/views/app-portal/pages/mixdb-context/components/mix-databases/view.html", + "/mix-app/views/app-portal/pages/customer/components/orders/customer-orders.html", + controller: [ + "$rootScope", + "OrderServices", + function ($rootScope, orderServices) { + var ctrl = this; + ctrl.removeOrder = function (id) { + $rootScope.showConfirm( + ctrl, + "removeOrderConfirmed", + [id], + null, + "Remove Order", + "Deleted data will not able to recover, are you sure you want to delete this item?" + ); + }; + + ctrl.removeOrderConfirmed = async function (id) { + var result = await orderServices.removeOrder(id); + if (result.success) { + $rootScope.showMessage("success", "success"); + window.top.location = window.top.location.href; + } else { + $rootScope.showMessage("failed"); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + }, + ], + bindings: { + customer: "=", + onDelete: "&", + onUpdate: "&", + }, +}); + +app.component("mixdbContextDatabases", { + bindings: { + model: "=", + }, + templateUrl: + "/mix-app/views/app-portal/pages/mixdb-context/components/mix-databases/view.html", controller: [ "$rootScope", "$scope", @@ -7351,25 +7355,6 @@ app.component("mixdbContextDatabases", { ], }); -app.component("moduleAdvanced", { - templateUrl: - "/mix-app/views/app-portal/pages/module/components/module-advanced/view.html", - bindings: { - model: "=", - additionalData: "=", - }, - controller: [ - "$rootScope", - function ($rootScope) { - var ctrl = this; - ctrl.mixConfigurations = $rootScope.globalSettings; - ctrl.$onInit = function () { - ctrl.isAdmin = $rootScope.isAdmin; - }; - }, - ], -}); - app.component("moduleMain", { templateUrl: "/mix-app/views/app-portal/pages/module/components/main/main.html", @@ -7400,6 +7385,25 @@ app.component("moduleMain", { }, }); +app.component("moduleAdvanced", { + templateUrl: + "/mix-app/views/app-portal/pages/module/components/module-advanced/view.html", + bindings: { + model: "=", + additionalData: "=", + }, + controller: [ + "$rootScope", + function ($rootScope) { + var ctrl = this; + ctrl.mixConfigurations = $rootScope.globalSettings; + ctrl.$onInit = function () { + ctrl.isAdmin = $rootScope.isAdmin; + }; + }, + ], +}); + app.component("moduleContent", { templateUrl: "/mix-app/views/app-portal/pages/module/components/module-content/view.html", @@ -7584,27 +7588,6 @@ app.component("pageMain", { }, }); -app.component("pageAdvanced", { - templateUrl: - "/mix-app/views/app-portal/pages/page/components/page-advanced/view.html", - bindings: { - model: "=", - additionalData: "=", - }, - controller: [ - "$rootScope", - "$scope", - function ($rootScope, $scope) { - var ctrl = this; - - ctrl.translate = $rootScope.translate; - ctrl.$onInit = function () { - ctrl.isAdmin = $rootScope.isAdmin; - }; - }, - ], -}); - app.component("pageModules", { templateUrl: "/mix-app/views/app-portal/pages/page/components/modules/modules.html", @@ -7650,6 +7633,27 @@ app.component("pageModules", { ], }); +app.component("pageAdvanced", { + templateUrl: + "/mix-app/views/app-portal/pages/page/components/page-advanced/view.html", + bindings: { + model: "=", + additionalData: "=", + }, + controller: [ + "$rootScope", + "$scope", + function ($rootScope, $scope) { + var ctrl = this; + + ctrl.translate = $rootScope.translate; + ctrl.$onInit = function () { + ctrl.isAdmin = $rootScope.isAdmin; + }; + }, + ], +}); + app.component("pageContent", { templateUrl: "/mix-app/views/app-portal/pages/page/components/page-content/view.html", @@ -8127,16 +8131,6 @@ app.component("postMedias", { }, }); -app.component("postParents", { - templateUrl: - "/mix-app/views/app-portal/pages/post/components/parents/view.html", - bindings: { - post: "=", - onDelete: "&", - onUpdate: "&", - }, -}); - app.component("postModules", { templateUrl: "/mix-app/views/app-portal/pages/post/components/modules/view.html", @@ -8230,6 +8224,16 @@ app.component("postModules", { }, }); +app.component("postParents", { + templateUrl: + "/mix-app/views/app-portal/pages/post/components/parents/view.html", + bindings: { + post: "=", + onDelete: "&", + onUpdate: "&", + }, +}); + app.component("postAdvanced", { templateUrl: "/mix-app/views/app-portal/pages/post/components/post-advanced/view.html", @@ -8257,6 +8261,100 @@ app.component("postAdvanced", { ], }); +app.component("postContent", { + templateUrl: + "/mix-app/views/app-portal/pages/post/components/post-content/view.html", + bindings: { + model: "=", + additionalData: "=", + loadingData: "=", + }, + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + "PostRestService", + function ($rootScope, $scope, ngAppSettings, service) { + var ctrl = this; + ctrl.request = angular.copy(ngAppSettings.request); + ctrl.translate = $rootScope.translate; + ctrl.relatedData = {}; + ctrl.$onInit = function () { + ctrl.backUrl = `/admin/post/details`; + }; + ctrl.generateSeo = function () { + if (ctrl.model) { + if (ctrl.model.seoName === null || ctrl.model.seoName === "") { + ctrl.model.seoName = $rootScope.generateKeyword( + ctrl.model.title, + "-" + ); + } + if (ctrl.model.seoTitle === null || ctrl.model.seoTitle === "") { + ctrl.model.seoTitle = ctrl.model.title; + } + if ( + ctrl.model.seoDescription === null || + ctrl.model.seoDescription === "" + ) { + ctrl.model.seoDescription = ctrl.model.excerpt; + } + if ( + ctrl.model.seoKeywords === null || + ctrl.model.seoKeywords === "" + ) { + ctrl.model.seoKeywords = ctrl.model.title; + } + } + }; + ctrl.getListRelated = async function (pageIndex) { + if (pageIndex !== undefined) { + ctrl.request.pageIndex = pageIndex; + } + if (ctrl.request.fromDate !== null) { + var d = new Date(ctrl.request.fromDate); + ctrl.request.fromDate = d.toISOString(); + } + if (ctrl.request.toDate !== null) { + var d = new Date(ctrl.request.toDate); + ctrl.request.toDate = d.toISOString(); + } + var resp = await service.getList(ctrl.request); + if (resp && resp.success) { + ctrl.relatedData = angular.copy(resp.data); + ctrl.relatedData.items = []; + angular.forEach(resp.data.items, (element) => { + var existed = $rootScope.findObjectByKey( + ctrl.model.postNavs, + ["sourceId", "destinationId"], + [ctrl.model.id, element.id] + ); + + var obj = { + description: element.title, + destinationId: element.id, + image: element.image, + isActived: existed !== null, + sourceId: ctrl.model.id, + specificulture: ctrl.model.specificulture, + status: "Published", + }; + + ctrl.relatedData.items.push(obj); + }); + console.log(ctrl.relatedData); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(getData.errors); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + }, + ], +}); + modules.component("relatedPosts", { templateUrl: "/mix-app/views/app-portal/pages/post/components/related-navigations/view.html", @@ -8398,116 +8496,22 @@ modules.component("relatedPosts", { ], }); -app.component("postContent", { +app.component("postSeo", { + templateUrl: "/mix-app/views/app-portal/pages/post/components/seo/view.html", + bindings: { + post: "=", + onDelete: "&", + onUpdate: "&", + }, +}); + +modules.component("rolePageNav", { templateUrl: - "/mix-app/views/app-portal/pages/post/components/post-content/view.html", + "/mix-app/views/app-portal/pages/role/components/role-page-navigation/role-page-navigations.html", bindings: { - model: "=", - additionalData: "=", - loadingData: "=", - }, - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - "PostRestService", - function ($rootScope, $scope, ngAppSettings, service) { - var ctrl = this; - ctrl.request = angular.copy(ngAppSettings.request); - ctrl.translate = $rootScope.translate; - ctrl.relatedData = {}; - ctrl.$onInit = function () { - ctrl.backUrl = `/admin/post/details`; - }; - ctrl.generateSeo = function () { - if (ctrl.model) { - if (ctrl.model.seoName === null || ctrl.model.seoName === "") { - ctrl.model.seoName = $rootScope.generateKeyword( - ctrl.model.title, - "-" - ); - } - if (ctrl.model.seoTitle === null || ctrl.model.seoTitle === "") { - ctrl.model.seoTitle = ctrl.model.title; - } - if ( - ctrl.model.seoDescription === null || - ctrl.model.seoDescription === "" - ) { - ctrl.model.seoDescription = ctrl.model.excerpt; - } - if ( - ctrl.model.seoKeywords === null || - ctrl.model.seoKeywords === "" - ) { - ctrl.model.seoKeywords = ctrl.model.title; - } - } - }; - ctrl.getListRelated = async function (pageIndex) { - if (pageIndex !== undefined) { - ctrl.request.pageIndex = pageIndex; - } - if (ctrl.request.fromDate !== null) { - var d = new Date(ctrl.request.fromDate); - ctrl.request.fromDate = d.toISOString(); - } - if (ctrl.request.toDate !== null) { - var d = new Date(ctrl.request.toDate); - ctrl.request.toDate = d.toISOString(); - } - var resp = await service.getList(ctrl.request); - if (resp && resp.success) { - ctrl.relatedData = angular.copy(resp.data); - ctrl.relatedData.items = []; - angular.forEach(resp.data.items, (element) => { - var existed = $rootScope.findObjectByKey( - ctrl.model.postNavs, - ["sourceId", "destinationId"], - [ctrl.model.id, element.id] - ); - - var obj = { - description: element.title, - destinationId: element.id, - image: element.image, - isActived: existed !== null, - sourceId: ctrl.model.id, - specificulture: ctrl.model.specificulture, - status: "Published", - }; - - ctrl.relatedData.items.push(obj); - }); - console.log(ctrl.relatedData); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(getData.errors); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - }, - ], -}); - -app.component("postSeo", { - templateUrl: "/mix-app/views/app-portal/pages/post/components/seo/view.html", - bindings: { - post: "=", - onDelete: "&", - onUpdate: "&", - }, -}); - -modules.component("rolePageNav", { - templateUrl: - "/mix-app/views/app-portal/pages/role/components/role-page-navigation/role-page-navigations.html", - bindings: { - prefix: "=", - page: "=", - callback: "&", + prefix: "=", + page: "=", + callback: "&", }, controller: [ "$rootScope", @@ -8566,6 +8570,76 @@ app.component("serviceMain", { }, }); +app.component("themeExportCultures", { + templateUrl: + "/mix-app/views/app-portal/pages/theme/components/theme-export-cultures/view.html", + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + function ($rootScope, $scope, ngAppSettings) { + var ctrl = this; + var service = $rootScope.getRestService("culture"); + ctrl.selectAllContent = false; + ctrl.request = angular.copy(ngAppSettings.request); + ctrl.$onInit = async () => { + ctrl.getList(); + }; + ctrl.getList = async (cultureIndex) => { + if (cultureIndex !== undefined) { + ctrl.request.cultureIndex = cultureIndex; + } + if (ctrl.request.fromDate !== null) { + var d = new Date(ctrl.request.fromDate); + ctrl.request.fromDate = d.toISOString(); + } + if (ctrl.request.toDate !== null) { + var d = new Date(ctrl.request.toDate); + ctrl.request.toDate = d.toISOString(); + } + let getData = await service.getList(ctrl.request); + if (getData.success) { + ctrl.data = getData.data; + } + }; + ctrl.selectContent = (culture, selected) => { + ctrl.selectAllContent = ctrl.selectAllContent && selected; + ctrl.selectAllData = ctrl.selectAllData && selected; + culture.isExportData = selected && culture.isExportData; + ctrl.updateContent([culture.id], selected); + }; + ctrl.updateContent = function (arr, selected) { + if (selected) { + ctrl.exportThemeDto.cultureIds = ctrl.unionArray( + ctrl.exportThemeDto.cultureIds, + arr + ); + } else { + ctrl.exportThemeDto.cultureIds = + ctrl.exportThemeDto.cultureIds.filter((m) => arr.indexOf(m) < 0); + ctrl.updateData(arr, false); + } + }; + ctrl.selectAll = function (arr) { + // ctrl.selectedList.data = []; + var ids = arr.map(function (obj) { + return obj.id; + }); + ctrl.updateContent(ids, ctrl.selectAllContent); + angular.forEach(arr, function (e) { + e.isActived = ctrl.selectAllContent; + }); + }; + ctrl.unionArray = (a, b) => { + return [...new Set([...a, ...b])]; + }; + }, + ], + bindings: { + exportThemeDto: "=", + }, +}); + app.component("themeExportMixDatabases", { templateUrl: "/mix-app/views/app-portal/pages/theme/components/theme-export-mix-databases/view.html", @@ -8647,76 +8721,6 @@ app.component("themeExportMixDatabases", { }, }); -app.component("themeExportCultures", { - templateUrl: - "/mix-app/views/app-portal/pages/theme/components/theme-export-cultures/view.html", - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - function ($rootScope, $scope, ngAppSettings) { - var ctrl = this; - var service = $rootScope.getRestService("culture"); - ctrl.selectAllContent = false; - ctrl.request = angular.copy(ngAppSettings.request); - ctrl.$onInit = async () => { - ctrl.getList(); - }; - ctrl.getList = async (cultureIndex) => { - if (cultureIndex !== undefined) { - ctrl.request.cultureIndex = cultureIndex; - } - if (ctrl.request.fromDate !== null) { - var d = new Date(ctrl.request.fromDate); - ctrl.request.fromDate = d.toISOString(); - } - if (ctrl.request.toDate !== null) { - var d = new Date(ctrl.request.toDate); - ctrl.request.toDate = d.toISOString(); - } - let getData = await service.getList(ctrl.request); - if (getData.success) { - ctrl.data = getData.data; - } - }; - ctrl.selectContent = (culture, selected) => { - ctrl.selectAllContent = ctrl.selectAllContent && selected; - ctrl.selectAllData = ctrl.selectAllData && selected; - culture.isExportData = selected && culture.isExportData; - ctrl.updateContent([culture.id], selected); - }; - ctrl.updateContent = function (arr, selected) { - if (selected) { - ctrl.exportThemeDto.cultureIds = ctrl.unionArray( - ctrl.exportThemeDto.cultureIds, - arr - ); - } else { - ctrl.exportThemeDto.cultureIds = - ctrl.exportThemeDto.cultureIds.filter((m) => arr.indexOf(m) < 0); - ctrl.updateData(arr, false); - } - }; - ctrl.selectAll = function (arr) { - // ctrl.selectedList.data = []; - var ids = arr.map(function (obj) { - return obj.id; - }); - ctrl.updateContent(ids, ctrl.selectAllContent); - angular.forEach(arr, function (e) { - e.isActived = ctrl.selectAllContent; - }); - }; - ctrl.unionArray = (a, b) => { - return [...new Set([...a, ...b])]; - }; - }, - ], - bindings: { - exportThemeDto: "=", - }, -}); - app.component("themeExportModules", { templateUrl: "/mix-app/views/app-portal/pages/theme/components/theme-export-modules/view.html", @@ -8911,24 +8915,28 @@ app.component("themeExportPages", { }, }); -app.component("themeImportCultures", { +app.component("themeExportPosts", { templateUrl: - "/mix-app/views/app-portal/pages/theme-import/components/theme-import-cultures/view.html", + "/mix-app/views/app-portal/pages/theme/components/theme-export-posts/view.html", controller: [ "$rootScope", "$scope", "ngAppSettings", - function ($rootScope, $scope, ngAppSettings) { + "BaseRestService", + function ($rootScope, $scope, ngAppSettings, baseRestService) { var ctrl = this; - var service = $rootScope.getRestService("culture"); + var service = angular.copy(baseRestService); + service.initService("/rest/mix-portal", "mix-post"); ctrl.selectAllContent = false; + ctrl.selectAllData = false; ctrl.request = angular.copy(ngAppSettings.request); ctrl.$onInit = async () => { + ctrl.request.pageSize = 1000; ctrl.getList(); }; - ctrl.getList = async (cultureIndex) => { - if (cultureIndex !== undefined) { - ctrl.request.cultureIndex = cultureIndex; + ctrl.getList = async (postIndex) => { + if (postIndex !== undefined) { + ctrl.request.postIndex = postIndex; } if (ctrl.request.fromDate !== null) { var d = new Date(ctrl.request.fromDate); @@ -8943,32 +8951,57 @@ app.component("themeImportCultures", { ctrl.data = getData.data; } }; - ctrl.selectContent = (culture, selected) => { + ctrl.selectContent = (post, selected) => { ctrl.selectAllContent = ctrl.selectAllContent && selected; ctrl.selectAllData = ctrl.selectAllData && selected; - culture.isImportData = selected && culture.isImportData; - ctrl.updateContent([culture.id], selected); + post.isExportData = selected && post.isExportData; + let contentIds = post.contents.map(function (obj) { + return obj.id; + }); + ctrl.exportThemeDto.content.postIds = ctrl.updateArray( + ctrl.exportThemeDto.content.postIds, + [post.id], + selected + ); + ctrl.exportThemeDto.content.postContentIds = ctrl.updateArray( + ctrl.exportThemeDto.content.postContentIds, + contentIds, + selected + ); + if (!selected) { + ctrl.selectData(post, false); + } }; - ctrl.updateContent = function (arr, selected) { + ctrl.selectData = (post, selected) => { + ctrl.selectAllData = ctrl.selectAllData && selected; + let contentIds = post.contents.map(function (obj) { + return obj.id; + }); + ctrl.exportThemeDto.associations.postIds = ctrl.updateArray( + ctrl.exportThemeDto.associations.postIds, + [post.id], + selected + ); + ctrl.exportThemeDto.associations.postContentIds = ctrl.updateArray( + ctrl.exportThemeDto.associations.postContentIds, + contentIds, + selected + ); + }; + ctrl.updateArray = function (src, arr, selected) { if (selected) { - ctrl.importThemeDto.cultureIds = ctrl.unionArray( - ctrl.importThemeDto.cultureIds, - arr - ); + src = ctrl.unionArray(src, arr); } else { - ctrl.importThemeDto.cultureIds = - ctrl.importThemeDto.cultureIds.filter((m) => arr.indexOf(m) < 0); - ctrl.updateData(arr, false); + src = src.filter((m) => arr.indexOf(m) < 0); } + return src; }; ctrl.selectAll = function (arr) { - // ctrl.selectedList.data = []; - var ids = arr.map(function (obj) { - return obj.id; - }); - ctrl.updateContent(ids, ctrl.selectAllContent); angular.forEach(arr, function (e) { + ctrl.selectContent(e, ctrl.selectAllContent); + ctrl.selectData(e, ctrl.selectAllData); e.isActived = ctrl.selectAllContent; + e.isExportData = ctrl.selectAllData; }); }; ctrl.unionArray = (a, b) => { @@ -8977,32 +9010,28 @@ app.component("themeImportCultures", { }, ], bindings: { - importThemeDto: "=", + exportThemeDto: "=", }, }); -app.component("themeExportPosts", { +app.component("themeImportCultures", { templateUrl: - "/mix-app/views/app-portal/pages/theme/components/theme-export-posts/view.html", + "/mix-app/views/app-portal/pages/theme-import/components/theme-import-cultures/view.html", controller: [ "$rootScope", "$scope", "ngAppSettings", - "BaseRestService", - function ($rootScope, $scope, ngAppSettings, baseRestService) { + function ($rootScope, $scope, ngAppSettings) { var ctrl = this; - var service = angular.copy(baseRestService); - service.initService("/rest/mix-portal", "mix-post"); + var service = $rootScope.getRestService("culture"); ctrl.selectAllContent = false; - ctrl.selectAllData = false; ctrl.request = angular.copy(ngAppSettings.request); ctrl.$onInit = async () => { - ctrl.request.pageSize = 1000; ctrl.getList(); }; - ctrl.getList = async (postIndex) => { - if (postIndex !== undefined) { - ctrl.request.postIndex = postIndex; + ctrl.getList = async (cultureIndex) => { + if (cultureIndex !== undefined) { + ctrl.request.cultureIndex = cultureIndex; } if (ctrl.request.fromDate !== null) { var d = new Date(ctrl.request.fromDate); @@ -9017,57 +9046,32 @@ app.component("themeExportPosts", { ctrl.data = getData.data; } }; - ctrl.selectContent = (post, selected) => { + ctrl.selectContent = (culture, selected) => { ctrl.selectAllContent = ctrl.selectAllContent && selected; ctrl.selectAllData = ctrl.selectAllData && selected; - post.isExportData = selected && post.isExportData; - let contentIds = post.contents.map(function (obj) { - return obj.id; - }); - ctrl.exportThemeDto.content.postIds = ctrl.updateArray( - ctrl.exportThemeDto.content.postIds, - [post.id], - selected - ); - ctrl.exportThemeDto.content.postContentIds = ctrl.updateArray( - ctrl.exportThemeDto.content.postContentIds, - contentIds, - selected - ); - if (!selected) { - ctrl.selectData(post, false); - } - }; - ctrl.selectData = (post, selected) => { - ctrl.selectAllData = ctrl.selectAllData && selected; - let contentIds = post.contents.map(function (obj) { - return obj.id; - }); - ctrl.exportThemeDto.associations.postIds = ctrl.updateArray( - ctrl.exportThemeDto.associations.postIds, - [post.id], - selected - ); - ctrl.exportThemeDto.associations.postContentIds = ctrl.updateArray( - ctrl.exportThemeDto.associations.postContentIds, - contentIds, - selected - ); + culture.isImportData = selected && culture.isImportData; + ctrl.updateContent([culture.id], selected); }; - ctrl.updateArray = function (src, arr, selected) { + ctrl.updateContent = function (arr, selected) { if (selected) { - src = ctrl.unionArray(src, arr); + ctrl.importThemeDto.cultureIds = ctrl.unionArray( + ctrl.importThemeDto.cultureIds, + arr + ); } else { - src = src.filter((m) => arr.indexOf(m) < 0); + ctrl.importThemeDto.cultureIds = + ctrl.importThemeDto.cultureIds.filter((m) => arr.indexOf(m) < 0); + ctrl.updateData(arr, false); } - return src; }; ctrl.selectAll = function (arr) { + // ctrl.selectedList.data = []; + var ids = arr.map(function (obj) { + return obj.id; + }); + ctrl.updateContent(ids, ctrl.selectAllContent); angular.forEach(arr, function (e) { - ctrl.selectContent(e, ctrl.selectAllContent); - ctrl.selectData(e, ctrl.selectAllData); e.isActived = ctrl.selectAllContent; - e.isExportData = ctrl.selectAllData; }); }; ctrl.unionArray = (a, b) => { @@ -9076,7 +9080,7 @@ app.component("themeExportPosts", { }, ], bindings: { - exportThemeDto: "=", + importThemeDto: "=", }, }); @@ -9715,49 +9719,6 @@ modules.component("layoutPortalSidebar", { bindings: {}, }); -modules.component("actions", { - templateUrl: "/mix-app/views/app-portal/components/actions/actions.html", - bindings: { - primaryUrl: "=", - primaryTitle: "=", - primaryIcon: "=", - previewUrl: "=", - backUrl: "=", - contentUrl: "=", - onClearCache: "&?", - onSubmit: "&?", - }, - controller: [ - "$rootScope", - "$scope", - "$location", - function ($rootScope, $scope, $location) { - var ctrl = this; - ctrl.visible = $rootScope.visible; - ctrl.back = function () { - if (ctrl.backUrl) { - $location.url(ctrl.backUrl); - } else { - window.history.back(); - } - }; - ctrl.$onInit = function () { - ctrl.isAdmin = $rootScope.isAdmin; - }; - ctrl.submit = function ($event) { - if (ctrl.onSubmit) { - $event.preventDefault(); - ctrl.onSubmit(); - return; - } - }; - ctrl.clearCache = function () { - ctrl.onClearCache(); - }; - }, - ], -}); - modules.component("aceEditor", { templateUrl: "/mix-app/views/app-portal/components/ace-editor/ace-editor.html", @@ -9865,6 +9826,49 @@ modules.component("aceEditor", { }, }); +modules.component("actions", { + templateUrl: "/mix-app/views/app-portal/components/actions/actions.html", + bindings: { + primaryUrl: "=", + primaryTitle: "=", + primaryIcon: "=", + previewUrl: "=", + backUrl: "=", + contentUrl: "=", + onClearCache: "&?", + onSubmit: "&?", + }, + controller: [ + "$rootScope", + "$scope", + "$location", + function ($rootScope, $scope, $location) { + var ctrl = this; + ctrl.visible = $rootScope.visible; + ctrl.back = function () { + if (ctrl.backUrl) { + $location.url(ctrl.backUrl); + } else { + window.history.back(); + } + }; + ctrl.$onInit = function () { + ctrl.isAdmin = $rootScope.isAdmin; + }; + ctrl.submit = function ($event) { + if (ctrl.onSubmit) { + $event.preventDefault(); + ctrl.onSubmit(); + return; + } + }; + ctrl.clearCache = function () { + ctrl.onClearCache(); + }; + }, + ], +}); + modules.component("additionalColumn", { templateUrl: "/mix-app/views/app-portal/components/additional-column/view.html", @@ -10909,36 +10913,157 @@ app.controller("HighFrequencyMessagesController", [ }, ]); -modules.component("jsonBuilder", { - templateUrl: "/mix-app/views/app-portal/components/json-builder/view.html", - bindings: { - data: "=?", // json obj (ex: { column1: 'some val' }) - strData: "=?", // json obj (ex: { column1: 'some val' }) - folder: "=?", // filepath (ex: 'data/jsonfile.json') - filename: "=?", // filepath (ex: 'data/jsonfile.json') - allowedTypes: "=?", // string array ( ex: [ 'type1', 'type2' ] ) - backUrl: "=?", // string array ( ex: [ 'type1', 'type2' ] ) - showPreview: "=?", - type: "=?", // array / obj - editMode: "=?", // array / obj - save: "&", - onUpdate: "&", - }, - controller: [ - "$rootScope", - "$scope", - "$location", - "FileServices", - "ngAppSettings", - function ($rootScope, $scope, $location, fileService, ngAppSettings) { - var ctrl = this; - - ctrl.file = null; - ctrl.translate = $rootScope.translate; - ctrl.mixConfigurations = $rootScope.globalSettings; - ctrl.timestamp = Math.random(); - ctrl.templates = [ - { +modules.component("hubMessages", { + templateUrl: + "/mix-app/views/app-portal/components/hub-messages/hub-messages.html", + controller: "HubMessagesController", + bindings: {}, +}); +app.controller("HubMessagesController", [ + "$scope", + "$rootScope", + "AuthService", + function ($scope, $rootScope, authService) { + BaseHub.call(this, $scope); + authService.fillAuthData(); + $scope.newMsgCount = 0; + $scope.messages = []; + $scope.onConnected = () => { + // $scope.joinRoom("portal"); + }; + $scope.init = function () { + $scope.startConnection( + "portalHub", + authService.authentication.accessToken, + (err) => { + if ( + authService.authentication.refreshToken && + err.message.indexOf("401") >= 0 + ) { + authService.refreshToken().then(async () => { + $scope.startConnection( + "portalHub", + authService.authentication.accessToken + ); + }); + } + } + ); + }; + $scope.readMessages = function () { + $scope.newMsgCount = 0; + $("#modal-hub-messages").modal("show"); + }; + $scope.receiveMessage = function (msg) { + switch (msg.action) { + case "MyConnection": + $scope.hubRequest.from = msg.data; + $scope.$apply(); + break; + case "MemberList": + // filter unique member by username + $scope.members = msg.data.filter( + (value, index, array) => + array.indexOf(array.find((u) => u.username == value.username)) === + index + ); + $scope.$apply(); + break; + case "NewMember": + $scope.newMember(msg.data); + break; + case "MemberOffline": + $scope.removeMember(msg.data); + case "NewMessage": + $scope.newMessage(msg); + break; + } + }; + $scope.newMessage = function (msg) { + msg.style = $scope.getMessageType(msg.type); + if ( + msg.data && + !angular.isObject(msg.data) && + msg.data.indexOf("{") == 0 + ) { + msg.data = JSON.parse(msg.data); + } + $scope.messages.push(msg); + if ( + !msg.from || + msg.from.connectionId != $scope.hubRequest.from.connectionId + ) { + $scope.newMsgCount += 1; + $rootScope.showMessage(msg.title, msg.style); + } + $scope.$apply(); + }; + $scope.removeMember = function (member) { + var index = $scope.members.findIndex( + (x) => x.username === member.username + ); + if (index >= 0) { + $scope.members.splice(index, 1); + } + $scope.$apply(); + }; + + $scope.newMember = function (member) { + var index = $scope.members.findIndex( + (x) => x.username === member.username + ); + if (index < 0) { + $scope.members.splice(0, 0, member); + } + $scope.$apply(); + }; + $scope.getMessageType = function (type) { + switch (type) { + case "Success": + return "success"; + case "Error": + return "danger"; + case "Warning": + return "warning"; + case "Info": + return "info"; + default: + return "default"; + } + }; + }, +]); + +modules.component("jsonBuilder", { + templateUrl: "/mix-app/views/app-portal/components/json-builder/view.html", + bindings: { + data: "=?", // json obj (ex: { column1: 'some val' }) + strData: "=?", // json obj (ex: { column1: 'some val' }) + folder: "=?", // filepath (ex: 'data/jsonfile.json') + filename: "=?", // filepath (ex: 'data/jsonfile.json') + allowedTypes: "=?", // string array ( ex: [ 'type1', 'type2' ] ) + backUrl: "=?", // string array ( ex: [ 'type1', 'type2' ] ) + showPreview: "=?", + type: "=?", // array / obj + editMode: "=?", // array / obj + save: "&", + onUpdate: "&", + }, + controller: [ + "$rootScope", + "$scope", + "$location", + "FileServices", + "ngAppSettings", + function ($rootScope, $scope, $location, fileService, ngAppSettings) { + var ctrl = this; + + ctrl.file = null; + ctrl.translate = $rootScope.translate; + ctrl.mixConfigurations = $rootScope.globalSettings; + ctrl.timestamp = Math.random(); + ctrl.templates = [ + { type: "item", name: "", dataType: "Text", @@ -11200,169 +11325,72 @@ modules.component("jsonBuilder", { ], }); -modules.component("hubMessages", { +modules.component("jumbotrons", { templateUrl: - "/mix-app/views/app-portal/components/hub-messages/hub-messages.html", - controller: "HubMessagesController", - bindings: {}, + "/mix-app/views/app-portal/components/jumbotrons/jumbotrons.html", + controller: [ + "$rootScope", + "$scope", + "$location", + function ($rootScope, $scope, $location) { + var ctrl = this; + ctrl.translate = function (keyword) { + return $rootScope.translate(keyword); + }; + // ctrl.back = function () { + // ctrl.backUrl = ctrl.backUrl || '/admin'; + // $location.path(ctrl.backUrl); + // }; + }, + ], + bindings: { + tagName: "=", + tagType: "=", + }, }); -app.controller("HubMessagesController", [ - "$scope", - "$rootScope", - "AuthService", - function ($scope, $rootScope, authService) { - BaseHub.call(this, $scope); - authService.fillAuthData(); - $scope.newMsgCount = 0; - $scope.messages = []; - $scope.onConnected = () => { - // $scope.joinRoom("portal"); - }; - $scope.init = function () { - $scope.startConnection( - "portalHub", - authService.authentication.accessToken, - (err) => { - if ( - authService.authentication.refreshToken && - err.message.indexOf("401") >= 0 - ) { - authService.refreshToken().then(async () => { - $scope.startConnection( - "portalHub", - authService.authentication.accessToken - ); - }); - } - } - ); - }; - $scope.readMessages = function () { - $scope.newMsgCount = 0; - $("#modal-hub-messages").modal("show"); - }; - $scope.receiveMessage = function (msg) { - switch (msg.action) { - case "MyConnection": - $scope.hubRequest.from = msg.data; - $scope.$apply(); - break; - case "MemberList": - // filter unique member by username - $scope.members = msg.data.filter( - (value, index, array) => - array.indexOf(array.find((u) => u.username == value.username)) === - index - ); - $scope.$apply(); - break; - case "NewMember": - $scope.newMember(msg.data); - break; - case "MemberOffline": - $scope.removeMember(msg.data); - case "NewMessage": - $scope.newMessage(msg); - break; - } - }; - $scope.newMessage = function (msg) { - msg.style = $scope.getMessageType(msg.type); - if ( - msg.data && - !angular.isObject(msg.data) && - msg.data.indexOf("{") == 0 - ) { - msg.data = JSON.parse(msg.data); - } - $scope.messages.push(msg); - if ( - !msg.from || - msg.from.connectionId != $scope.hubRequest.from.connectionId - ) { - $scope.newMsgCount += 1; - $rootScope.showMessage(msg.title, msg.style); - } - $scope.$apply(); - }; - $scope.removeMember = function (member) { - var index = $scope.members.findIndex( - (x) => x.username === member.username - ); - if (index >= 0) { - $scope.members.splice(index, 1); - } - $scope.$apply(); - }; - - $scope.newMember = function (member) { - var index = $scope.members.findIndex( - (x) => x.username === member.username - ); - if (index < 0) { - $scope.members.splice(0, 0, member); - } - $scope.$apply(); - }; - $scope.getMessageType = function (type) { - switch (type) { - case "Success": - return "success"; - case "Error": - return "danger"; - case "Warning": - return "warning"; - case "Info": - return "info"; - default: - return "default"; - } - }; - }, -]); - -// const { data } = require("jquery"); - -modules.component("listMixColumn", { - templateUrl: "/mix-app/views/app-portal/components/list-mix-column/view.html", - bindings: { - header: "=", - columns: "=", - relationships: "=", - removeAttributes: "=", - }, - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - "RestMixRelationshipPortalService", - "RestMixDatabasePortalService", - "RestMixDatabaseColumnPortalService", - function ( - $rootScope, - $scope, - ngAppSettings, - relationshipService, - databaseService, - service - ) { - var ctrl = this; - ctrl.request = angular.copy(ngAppSettings.request); - ctrl.selectedCol = null; - ctrl.relationshipTypes = ["OneToMany"]; - ctrl.defaultRelationship = { - parentId: null, - type: "OneToMany", - childId: null, - displayName: null, - }; - ctrl.$onInit = async function () { - ctrl.dataTypes = $rootScope.globalSettings.dataTypes; - ctrl.databases = await databaseService.getList(ctrl.request); - var getDefaultAttr = await service.getDefault(); - if (getDefaultAttr.success) { - ctrl.defaultAttr = getDefaultAttr.data; - ctrl.defaultAttr.options = []; + +// const { data } = require("jquery"); + +modules.component("listMixColumn", { + templateUrl: "/mix-app/views/app-portal/components/list-mix-column/view.html", + bindings: { + header: "=", + columns: "=", + relationships: "=", + removeAttributes: "=", + }, + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + "RestMixRelationshipPortalService", + "RestMixDatabasePortalService", + "RestMixDatabaseColumnPortalService", + function ( + $rootScope, + $scope, + ngAppSettings, + relationshipService, + databaseService, + service + ) { + var ctrl = this; + ctrl.request = angular.copy(ngAppSettings.request); + ctrl.selectedCol = null; + ctrl.relationshipTypes = ["OneToMany"]; + ctrl.defaultRelationship = { + parentId: null, + type: "OneToMany", + childId: null, + displayName: null, + }; + ctrl.$onInit = async function () { + ctrl.dataTypes = $rootScope.globalSettings.dataTypes; + ctrl.databases = await databaseService.getList(ctrl.request); + var getDefaultAttr = await service.getDefault(); + if (getDefaultAttr.success) { + ctrl.defaultAttr = getDefaultAttr.data; + ctrl.defaultAttr.options = []; } angular.forEach(ctrl.relationships, (e, i) => { e.database = ctrl.databases.data.items.find((m) => m.id == e.childId); @@ -11532,65 +11560,6 @@ modules.component("listMixColumn", { ], }); -modules.component("jumbotrons", { - templateUrl: - "/mix-app/views/app-portal/components/jumbotrons/jumbotrons.html", - controller: [ - "$rootScope", - "$scope", - "$location", - function ($rootScope, $scope, $location) { - var ctrl = this; - ctrl.translate = function (keyword) { - return $rootScope.translate(keyword); - }; - // ctrl.back = function () { - // ctrl.backUrl = ctrl.backUrl || '/admin'; - // $location.path(ctrl.backUrl); - // }; - }, - ], - bindings: { - tagName: "=", - tagType: "=", - }, -}); - -modules.component("mainSideBar", { - templateUrl: - "/mix-app/views/app-portal/components/main-side-bar/main-side-bar.html", - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - "TranslatorService", - "ApiService", - "CommonService", - function ( - $rootScope, - $scope, - ngAppSettings, - translatorService, - apiService, - commonService - ) { - var ctrl = this; - ctrl.items = []; - ctrl.init = async function () { - var resp = await apiService.getPortalMenus(); - if (resp.success && resp.data && resp.data.length) { - ctrl.items = resp.data; - } else { - ctrl.items = JSON.parse($("#portal-menus").val()).items; - } - }; - }, - ], - bindings: { - items: "=?", - }, -}); - modules.component("logStream", { templateUrl: "/mix-app/views/app-portal/components/log-stream/view.html", controller: "LogStreamController", @@ -11683,6 +11652,41 @@ app.controller("LogStreamController", [ }, ]); +modules.component("mainSideBar", { + templateUrl: + "/mix-app/views/app-portal/components/main-side-bar/main-side-bar.html", + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + "TranslatorService", + "ApiService", + "CommonService", + function ( + $rootScope, + $scope, + ngAppSettings, + translatorService, + apiService, + commonService + ) { + var ctrl = this; + ctrl.items = []; + ctrl.init = async function () { + var resp = await apiService.getPortalMenus(); + if (resp.success && resp.data && resp.data.length) { + ctrl.items = resp.data; + } else { + ctrl.items = JSON.parse($("#portal-menus").val()).items; + } + }; + }, + ], + bindings: { + items: "=?", + }, +}); + modules.component("mainSideBarDynamic", { templateUrl: "/mix-app/views/app-portal/components/main-side-bar-dynamic/main-side-bar-dynamic.html", @@ -13558,129 +13562,39 @@ modules.component("mixDatabaseNavValues", { ], }); -modules.component("mixFileExtract", { +modules.component("mixDatabaseNavs", { templateUrl: - "/mix-app/views/app-portal/components/mix-file-extract/view.html", + "/mix-app/views/app-portal/components/mix-database-navs/view.html", bindings: { - folder: "=?", - accept: "=?", - onFail: "&?", - onSuccess: "&?", + parentId: "=", + parentType: "=", + mixDatabaseNavs: "=?", + onUpdate: "&?", + onDelete: "&?", }, controller: [ "$rootScope", "$scope", "ngAppSettings", - "FileServices", - function ($rootScope, $scope, ngAppSettings, fileService) { + "RestRelatedMixDatabasePortalService", + "RestMixDatabasePortalService", + function ($rootScope, $scope, ngAppSettings, navService, setService) { var ctrl = this; - ctrl.mediaFile = {}; - ctrl.isAdmin = $rootScope.isAdmin; - ctrl.mediaNavs = []; + ctrl.mixDatabaseNavs = ctrl.mixDatabaseNavs || []; + ctrl.selected = {}; + ctrl.defaultData = null; + ctrl.navRequest = angular.copy(ngAppSettings.request); + ctrl.setRequest = angular.copy(ngAppSettings.request); + + ctrl.mixConfigurations = $rootScope.globalSettings; ctrl.$onInit = function () { - ctrl.id = Math.floor(Math.random() * 100); - }; - ctrl.selectFile = function (files) { - if (files !== undefined && files !== null && files.length > 0) { - const file = files[0]; - ctrl.file = file; - ctrl.mediaFile.folder = ctrl.folder ? ctrl.folder : "Media"; - ctrl.mediaFile.title = ctrl.title ? ctrl.title : ""; - ctrl.mediaFile.description = ctrl.description ? ctrl.description : ""; - ctrl.mediaFile.file = file; - if (ctrl.auto == "true") { - ctrl.uploadFile(file); - } else { - ctrl.getBase64(file); - } - } - }; - - ctrl.getBase64 = function (file) { - if (file !== null) { - $rootScope.isBusy = true; - var reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = function () { - if (ctrl.mediaFile) { - ctrl.mediaFile.fileName = file.name.substring( - 0, - file.name.lastIndexOf(".") - ); - ctrl.mediaFile.extension = file.name.substring( - file.name.lastIndexOf(".") - ); - ctrl.mediaFile.fileStream = reader.result; - } - $rootScope.isBusy = false; - $scope.$apply(); - }; - reader.onerror = function (error) { - $rootScope.isBusy = false; - $rootScope.showErrors([error]); - }; - } else { - return null; - } - }; - - ctrl.uploadFile = async function () { - if (ctrl.file) { - $rootScope.isBusy = true; - var response = await fileService.extractFile(ctrl.file, ctrl.folder); - if (response) { - if (ctrl.onSuccess) { - ctrl.onSuccess(); - } - $rootScope.showMessage("success", "success"); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(["Cannot upload file"]); - $rootScope.isBusy = false; - $scope.$apply(); - } - } else { - $rootScope.showErrors(["Please choose file"]); - } - }; - }, - ], -}); - -modules.component("mixDatabaseNavs", { - templateUrl: - "/mix-app/views/app-portal/components/mix-database-navs/view.html", - bindings: { - parentId: "=", - parentType: "=", - mixDatabaseNavs: "=?", - onUpdate: "&?", - onDelete: "&?", - }, - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - "RestRelatedMixDatabasePortalService", - "RestMixDatabasePortalService", - function ($rootScope, $scope, ngAppSettings, navService, setService) { - var ctrl = this; - ctrl.mixDatabaseNavs = ctrl.mixDatabaseNavs || []; - ctrl.selected = {}; - ctrl.defaultData = null; - ctrl.navRequest = angular.copy(ngAppSettings.request); - ctrl.setRequest = angular.copy(ngAppSettings.request); - - ctrl.mixConfigurations = $rootScope.globalSettings; - ctrl.$onInit = function () { - // ctrl.setRequest.type = ctrl.parentType; - navService.getDefault().then((resp) => { - resp.parentId = ctrl.parentId; - resp.parentType = ctrl.parentType; - ctrl.defaultData = resp; - ctrl.loadData(); - }); + // ctrl.setRequest.type = ctrl.parentType; + navService.getDefault().then((resp) => { + resp.parentId = ctrl.parentId; + resp.parentType = ctrl.parentType; + ctrl.defaultData = resp; + ctrl.loadData(); + }); }; ctrl.goToPath = $rootScope.goToPath; ctrl.selectPane = function (pane) {}; @@ -13819,6 +13733,96 @@ modules.component("mixDatabaseNavs", { ], }); +modules.component("mixFileExtract", { + templateUrl: + "/mix-app/views/app-portal/components/mix-file-extract/view.html", + bindings: { + folder: "=?", + accept: "=?", + onFail: "&?", + onSuccess: "&?", + }, + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + "FileServices", + function ($rootScope, $scope, ngAppSettings, fileService) { + var ctrl = this; + ctrl.mediaFile = {}; + ctrl.isAdmin = $rootScope.isAdmin; + ctrl.mediaNavs = []; + ctrl.$onInit = function () { + ctrl.id = Math.floor(Math.random() * 100); + }; + ctrl.selectFile = function (files) { + if (files !== undefined && files !== null && files.length > 0) { + const file = files[0]; + ctrl.file = file; + ctrl.mediaFile.folder = ctrl.folder ? ctrl.folder : "Media"; + ctrl.mediaFile.title = ctrl.title ? ctrl.title : ""; + ctrl.mediaFile.description = ctrl.description ? ctrl.description : ""; + ctrl.mediaFile.file = file; + if (ctrl.auto == "true") { + ctrl.uploadFile(file); + } else { + ctrl.getBase64(file); + } + } + }; + + ctrl.getBase64 = function (file) { + if (file !== null) { + $rootScope.isBusy = true; + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + if (ctrl.mediaFile) { + ctrl.mediaFile.fileName = file.name.substring( + 0, + file.name.lastIndexOf(".") + ); + ctrl.mediaFile.extension = file.name.substring( + file.name.lastIndexOf(".") + ); + ctrl.mediaFile.fileStream = reader.result; + } + $rootScope.isBusy = false; + $scope.$apply(); + }; + reader.onerror = function (error) { + $rootScope.isBusy = false; + $rootScope.showErrors([error]); + }; + } else { + return null; + } + }; + + ctrl.uploadFile = async function () { + if (ctrl.file) { + $rootScope.isBusy = true; + var response = await fileService.extractFile(ctrl.file, ctrl.folder); + if (response) { + if (ctrl.onSuccess) { + ctrl.onSuccess(); + } + $rootScope.showMessage("success", "success"); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(["Cannot upload file"]); + $rootScope.isBusy = false; + $scope.$apply(); + } + } else { + $rootScope.showErrors(["Please choose file"]); + } + }; + }, + ], +}); + modules.component("mixFileUpload", { templateUrl: "/mix-app/views/app-portal/components/mix-file-upload/view.html", bindings: { @@ -14802,164 +14806,6 @@ modules.component("modalNavDatas", { ], }); -modules.component("modalNavPosts", { - templateUrl: - "/mix-app/views/app-portal/components/modal-nav-posts/modal-nav-posts.html", - bindings: { - srcColumn: "=", - srcId: "=", - query: "=", - selected: "=", - save: "&", - }, - controller: [ - "$rootScope", - "$scope", - "$routeParams", - "ngAppSettings", - "PostRestService", - function ($rootScope, $scope, $routeParams, ngAppSettings, postService) { - var ctrl = this; - ctrl.request = angular.copy(ngAppSettings.request); - ctrl.navs = []; - ctrl.associations = []; - ctrl.data = { items: [] }; - ctrl.loadPosts = async function (pageIndex) { - // ctrl.request.query = ctrl.query + ctrl.srcId; - if (pageIndex !== undefined) { - ctrl.request.pageIndex = pageIndex; - } - if (ctrl.request.fromDate !== null) { - var d = new Date(ctrl.request.fromDate); - ctrl.request.fromDate = d.toISOString(); - } - if (ctrl.request.toDate !== null) { - var d = new Date(ctrl.request.toDate); - ctrl.request.toDate = d.toISOString(); - } - if ($routeParams.type) { - ctrl.request.postType = $routeParams.type; - } else { - ctrl.request.postType = ""; - } - var response = await postService.getList(ctrl.request); - if (response.success) { - ctrl.data = response.data; - // ctrl.navs = []; - // angular.forEach(response.data.items, function (e) { - // var item = { - // priority: e.priority, - // description: e.title, - // postId: e.id, - // image: e.thumbnailUrl, - // specificulture: e.specificulture, - // post: e, - // status: "Published", - // isActived: false, - // }; - // item[ctrl.srcColumn] = ctrl.srcId; - // ctrl.navs.push(item); - // }); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(response.errors); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - ctrl.select = async (associations) => { - ctrl.associations = associations; - }; - ctrl.saveSelected = function () { - ctrl.selected = $rootScope.filterArray( - ctrl.navs, - ["isActived"], - [true] - ); - setTimeout(() => { - ctrl.save().then(() => { - ctrl.loadPosts(); - }); - }, 500); - }; - }, - ], -}); - -modules.component("modalNavPages", { - templateUrl: "/mix-app/views/app-portal/components/modal-nav-pages/view.html", - bindings: { - srcField: "=", - srcId: "=", - query: "=", - selected: "=", - save: "&", - }, - controller: [ - "$rootScope", - "$scope", - "ngAppSettings", - "PageRestService", - function ($rootScope, $scope, ngAppSettings, pageService) { - var ctrl = this; - ctrl.request = angular.copy(ngAppSettings.request); - ctrl.navs = []; - ctrl.data = { items: [] }; - ctrl.loadData = async function (pageIndex) { - ctrl.request.query = ctrl.query + ctrl.srcId; - if (pageIndex !== undefined) { - ctrl.request.pageIndex = pageIndex; - } - if (ctrl.request.fromDate !== null) { - var d = new Date(ctrl.request.fromDate); - ctrl.request.fromDate = d.toISOString(); - } - if (ctrl.request.toDate !== null) { - var d = new Date(ctrl.request.toDate); - ctrl.request.toDate = d.toISOString(); - } - var response = await pageService.getList(ctrl.request); - if (response.success) { - ctrl.data = response.data; - ctrl.navs = []; - angular.forEach(response.data.items, function (e) { - var item = { - priority: e.priority, - description: e.title, - pageId: e.id, - image: e.thumbnailUrl, - specificulture: e.specificulture, - status: "Published", - isActived: false, - }; - item[ctrl.srcField] = ctrl.srcId; - ctrl.navs.push(item); - }); - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(response.errors); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - ctrl.saveSelected = function () { - ctrl.selected = $rootScope.filterArray( - ctrl.navs, - ["isActived"], - [true] - ); - setTimeout(() => { - ctrl.save().then(() => { - ctrl.loadPages(); - }); - }, 500); - }; - }, - ], -}); - modules.component("modalNavMetas", { templateUrl: "/mix-app/views/app-portal/components/modal-nav-metas/view.html", bindings: { @@ -15189,66 +15035,224 @@ modules.component("modalNavMetas", { $scope.$apply(); } } - - if (!isSelected) { - await ctrl.removeNav(idx); - if (ctrl.selectCallback) { - ctrl.selectCallback({ data: nav }); - } - return; + + if (!isSelected) { + await ctrl.removeNav(idx); + if (ctrl.selectCallback) { + ctrl.selectCallback({ data: nav }); + } + return; + } + }; + ctrl.removeNav = async function (idx) { + var nav = ctrl.selectedList.items[idx]; + ctrl.selectedValues.splice(idx, 1); + ctrl.selectedList.items.splice(idx, 1); + ctrl.filterData(); + if (nav && nav.id) { + await navService.delete([nav.id]); + $rootScope.showMessage("success", "success"); + $scope.$apply(); + } + }; + ctrl.disableNavitem = function (nav, isDisable) { + nav.disabled = isDisable; + }; + ctrl.createData = function () { + if (ctrl.newTitle) { + var tmp = $rootScope.findObjectByKey( + ctrl.data.items, + "title", + ctrl.newTitle + ); + if (!tmp) { + ctrl.isBusy = true; + ctrl.mixDatabaseData.intParentId = 0; + ctrl.mixDatabaseData.parentType = "Set"; + ctrl.mixDatabaseData.data.title = ctrl.newTitle; + ctrl.mixDatabaseData.data.slug = $rootScope.generateKeyword( + ctrl.newTitle, + "-" + ); + ctrl.mixDatabaseData.data.type = ctrl.type; + dataService.save(ctrl.mixDatabaseData).then((resp) => { + if (resp.success) { + ctrl.mixDatabaseData.id = resp.data; + ctrl.data.items.push(ctrl.mixDatabaseData); + ctrl.reload(); + ctrl.select(resp.data.id, true); + ctrl.filterData(); + ctrl.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(resp.errors); + ctrl.isBusy = false; + $scope.$apply(); + } + }); + } else { + tmp.isActived = true; + ctrl.select(tmp); + } + } + }; + }, + ], +}); + +modules.component("modalNavPages", { + templateUrl: "/mix-app/views/app-portal/components/modal-nav-pages/view.html", + bindings: { + srcField: "=", + srcId: "=", + query: "=", + selected: "=", + save: "&", + }, + controller: [ + "$rootScope", + "$scope", + "ngAppSettings", + "PageRestService", + function ($rootScope, $scope, ngAppSettings, pageService) { + var ctrl = this; + ctrl.request = angular.copy(ngAppSettings.request); + ctrl.navs = []; + ctrl.data = { items: [] }; + ctrl.loadData = async function (pageIndex) { + ctrl.request.query = ctrl.query + ctrl.srcId; + if (pageIndex !== undefined) { + ctrl.request.pageIndex = pageIndex; + } + if (ctrl.request.fromDate !== null) { + var d = new Date(ctrl.request.fromDate); + ctrl.request.fromDate = d.toISOString(); + } + if (ctrl.request.toDate !== null) { + var d = new Date(ctrl.request.toDate); + ctrl.request.toDate = d.toISOString(); + } + var response = await pageService.getList(ctrl.request); + if (response.success) { + ctrl.data = response.data; + ctrl.navs = []; + angular.forEach(response.data.items, function (e) { + var item = { + priority: e.priority, + description: e.title, + pageId: e.id, + image: e.thumbnailUrl, + specificulture: e.specificulture, + status: "Published", + isActived: false, + }; + item[ctrl.srcField] = ctrl.srcId; + ctrl.navs.push(item); + }); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(response.errors); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + ctrl.saveSelected = function () { + ctrl.selected = $rootScope.filterArray( + ctrl.navs, + ["isActived"], + [true] + ); + setTimeout(() => { + ctrl.save().then(() => { + ctrl.loadPages(); + }); + }, 500); + }; + }, + ], +}); + +modules.component("modalNavPosts", { + templateUrl: + "/mix-app/views/app-portal/components/modal-nav-posts/modal-nav-posts.html", + bindings: { + srcColumn: "=", + srcId: "=", + query: "=", + selected: "=", + save: "&", + }, + controller: [ + "$rootScope", + "$scope", + "$routeParams", + "ngAppSettings", + "PostRestService", + function ($rootScope, $scope, $routeParams, ngAppSettings, postService) { + var ctrl = this; + ctrl.request = angular.copy(ngAppSettings.request); + ctrl.navs = []; + ctrl.associations = []; + ctrl.data = { items: [] }; + ctrl.loadPosts = async function (pageIndex) { + // ctrl.request.query = ctrl.query + ctrl.srcId; + if (pageIndex !== undefined) { + ctrl.request.pageIndex = pageIndex; + } + if (ctrl.request.fromDate !== null) { + var d = new Date(ctrl.request.fromDate); + ctrl.request.fromDate = d.toISOString(); + } + if (ctrl.request.toDate !== null) { + var d = new Date(ctrl.request.toDate); + ctrl.request.toDate = d.toISOString(); } - }; - ctrl.removeNav = async function (idx) { - var nav = ctrl.selectedList.items[idx]; - ctrl.selectedValues.splice(idx, 1); - ctrl.selectedList.items.splice(idx, 1); - ctrl.filterData(); - if (nav && nav.id) { - await navService.delete([nav.id]); - $rootScope.showMessage("success", "success"); + if ($routeParams.type) { + ctrl.request.postType = $routeParams.type; + } else { + ctrl.request.postType = ""; + } + var response = await postService.getList(ctrl.request); + if (response.success) { + ctrl.data = response.data; + // ctrl.navs = []; + // angular.forEach(response.data.items, function (e) { + // var item = { + // priority: e.priority, + // description: e.title, + // postId: e.id, + // image: e.thumbnailUrl, + // specificulture: e.specificulture, + // post: e, + // status: "Published", + // isActived: false, + // }; + // item[ctrl.srcColumn] = ctrl.srcId; + // ctrl.navs.push(item); + // }); + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showErrors(response.errors); + $rootScope.isBusy = false; $scope.$apply(); } }; - ctrl.disableNavitem = function (nav, isDisable) { - nav.disabled = isDisable; + ctrl.select = async (associations) => { + ctrl.associations = associations; }; - ctrl.createData = function () { - if (ctrl.newTitle) { - var tmp = $rootScope.findObjectByKey( - ctrl.data.items, - "title", - ctrl.newTitle - ); - if (!tmp) { - ctrl.isBusy = true; - ctrl.mixDatabaseData.intParentId = 0; - ctrl.mixDatabaseData.parentType = "Set"; - ctrl.mixDatabaseData.data.title = ctrl.newTitle; - ctrl.mixDatabaseData.data.slug = $rootScope.generateKeyword( - ctrl.newTitle, - "-" - ); - ctrl.mixDatabaseData.data.type = ctrl.type; - dataService.save(ctrl.mixDatabaseData).then((resp) => { - if (resp.success) { - ctrl.mixDatabaseData.id = resp.data; - ctrl.data.items.push(ctrl.mixDatabaseData); - ctrl.reload(); - ctrl.select(resp.data.id, true); - ctrl.filterData(); - ctrl.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showErrors(resp.errors); - ctrl.isBusy = false; - $scope.$apply(); - } - }); - } else { - tmp.isActived = true; - ctrl.select(tmp); - } - } + ctrl.saveSelected = function () { + ctrl.selected = $rootScope.filterArray( + ctrl.navs, + ["isActived"], + [true] + ); + setTimeout(() => { + ctrl.save().then(() => { + ctrl.loadPosts(); + }); + }, 500); }; }, ], @@ -16330,6 +16334,83 @@ modules.component("templateEditor", { ], }); +modules.component("toastHelper", { + templateUrl: + "/mix-app/views/app-portal/components/toast-helper/toast-helper.html", + bindings: { + url: "=?", + title: "=?", + }, + controller: [ + "$rootScope", + function ($rootScope) { + var ctrl = this; + ctrl.visible = $rootScope.visible; + }, + ], +}); + +modules.component("urlAlias", { + templateUrl: "/mix-app/views/app-portal/components/url-alias/url-alias.html", + controller: [ + "$rootScope", + "$scope", + "UrlAliasService", + function ($rootScope, $scope, service) { + var ctrl = this; + ctrl.$onInit = function () { + ctrl.updateUrl(); + }; + ctrl.updateUrl = function () { + ctrl.url = + $rootScope.globalSettings.domain + + "/" + + $rootScope.mixConfigurations.lang + + "/" + + ctrl.urlAlias.alias; + }; + ctrl.remove = function () { + if (ctrl.urlAlias.id > 0) { + $rootScope.showConfirm( + ctrl, + "removeConfirmed", + [ctrl.urlAlias.id], + null, + "Remove", + "Deleted data will not able to recover, are you sure you want to delete this item?" + ); + } else { + if (ctrl.removeCallback) { + ctrl.removeCallback({ index: ctrl.index }); + } + } + }; + + ctrl.removeConfirmed = async function (id) { + $rootScope.isBusy = true; + var result = await service.delete(id); + if (result.success) { + if (ctrl.removeCallback) { + ctrl.removeCallback({ index: ctrl.index }); + } + $rootScope.isBusy = false; + $scope.$apply(); + } else { + $rootScope.showMessage("failed"); + $rootScope.isBusy = false; + $scope.$apply(); + } + }; + }, + ], + bindings: { + urlAlias: "=", + index: "=", + callback: "&", + removeCallback: "&", + }, +}); + app.factory("ConnectionManager", [ function () { var serviceFactory = {}; @@ -17182,83 +17263,6 @@ app.factory("ViewModel", [ }, ]); -modules.component("urlAlias", { - templateUrl: "/mix-app/views/app-portal/components/url-alias/url-alias.html", - controller: [ - "$rootScope", - "$scope", - "UrlAliasService", - function ($rootScope, $scope, service) { - var ctrl = this; - ctrl.$onInit = function () { - ctrl.updateUrl(); - }; - ctrl.updateUrl = function () { - ctrl.url = - $rootScope.globalSettings.domain + - "/" + - $rootScope.mixConfigurations.lang + - "/" + - ctrl.urlAlias.alias; - }; - ctrl.remove = function () { - if (ctrl.urlAlias.id > 0) { - $rootScope.showConfirm( - ctrl, - "removeConfirmed", - [ctrl.urlAlias.id], - null, - "Remove", - "Deleted data will not able to recover, are you sure you want to delete this item?" - ); - } else { - if (ctrl.removeCallback) { - ctrl.removeCallback({ index: ctrl.index }); - } - } - }; - - ctrl.removeConfirmed = async function (id) { - $rootScope.isBusy = true; - var result = await service.delete(id); - if (result.success) { - if (ctrl.removeCallback) { - ctrl.removeCallback({ index: ctrl.index }); - } - $rootScope.isBusy = false; - $scope.$apply(); - } else { - $rootScope.showMessage("failed"); - $rootScope.isBusy = false; - $scope.$apply(); - } - }; - }, - ], - bindings: { - urlAlias: "=", - index: "=", - callback: "&", - removeCallback: "&", - }, -}); - -modules.component("toastHelper", { - templateUrl: - "/mix-app/views/app-portal/components/toast-helper/toast-helper.html", - bindings: { - url: "=?", - title: "=?", - }, - controller: [ - "$rootScope", - function ($rootScope) { - var ctrl = this; - ctrl.visible = $rootScope.visible; - }, - ], -}); - !(function (t) { var e = {}; function i(n) { diff --git a/src/applications/Mixcore/wwwroot/mix-app/views/app-portal/pages/application/details.html b/src/applications/Mixcore/wwwroot/mix-app/views/app-portal/pages/application/details.html index 297c3a6c0..3fdd7ef15 100644 --- a/src/applications/Mixcore/wwwroot/mix-app/views/app-portal/pages/application/details.html +++ b/src/applications/Mixcore/wwwroot/mix-app/views/app-portal/pages/application/details.html @@ -1 +1 @@ -
(Must start with "/app/", ex: '/app/my-app')
{{post.title}}
by {{post.properties.authorName}} in {{post.additionalData.category}}

\ No newline at end of file +

(Must start with "/app/", ex: '/app/my-app')
{{post.title}}
by {{post.properties.authorName}} in {{post.additionalData.category}}
\ No newline at end of file diff --git a/src/modules/mix.portal/Controllers/MixApplicationController.cs b/src/modules/mix.portal/Controllers/MixApplicationController.cs index 206e86bc7..3450e69de 100644 --- a/src/modules/mix.portal/Controllers/MixApplicationController.cs +++ b/src/modules/mix.portal/Controllers/MixApplicationController.cs @@ -1,7 +1,8 @@ -using Microsoft.AspNetCore.Mvc; +using FirebaseAdmin.Auth.Multitenancy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.CodeAnalysis.Elfie.Diagnostics; using Mix.Database.Entities.AuditLog; using Mix.Lib.Interfaces; -using Mix.Portal.Domain.Interfaces; using Mix.SignalR.Interfaces; namespace Mix.Portal.Controllers @@ -36,15 +37,14 @@ public MixApplicationController( [HttpPost] [Route("install")] - public async Task> Install([FromBody] MixApplicationViewModel app, CancellationToken cancellationToken = default) + public ActionResult Install([FromBody] MixApplicationViewModel app, CancellationToken cancellationToken = default) { if (_cmsContext.MixApplication.Any(m => m.MixTenantId == CurrentTenant.Id && m.BaseHref == app.BaseHref && m.Id != app.Id)) { return BadRequest($"BaseHref: \"{app.BaseHref}\" existed"); } - - await _applicationService.Install(app, cancellationToken); - return base.Ok(app); + QueueService.PushQueue(CurrentTenant.Id, MixQueueTopics.MixBackgroundTasks, MixQueueActions.InstallMixApplication, app); + return NoContent(); } [HttpPost] 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/modules/mix.portal/Domain/Services/MixApplicationService.cs b/src/modules/mix.portal/Domain/Services/MixApplicationService.cs index 66ee382f8..08bc15728 100644 --- a/src/modules/mix.portal/Domain/Services/MixApplicationService.cs +++ b/src/modules/mix.portal/Domain/Services/MixApplicationService.cs @@ -5,9 +5,11 @@ using Mix.Lib.Interfaces; using Mix.Portal.Domain.Interfaces; using Mix.Shared.Helpers; +using Mix.Shared.Models.Configurations; using Mix.Shared.Services; using Mix.SignalR.Constants; using Mix.SignalR.Hubs; +using System.Configuration; using System.IO.Packaging; using System.Text.RegularExpressions; using static NuGet.Packaging.PackagingConstants; @@ -17,9 +19,10 @@ namespace Mix.Portal.Domain.Services public sealed class MixApplicationService : TenantServiceBase, IMixApplicationService { static string[] excludeFileNames = { "jquery", "index" }; - static string allowExtensionsPattern = "js|css|png|jpg|jpeg|gif|svg|webm|mp3|mp4|wmv"; + static string allowExtensionsPattern = "json|js|css|webmanifest|ico|png|jpg|jpeg|gif|svg|webm|mp3|mp4|wmv"; private readonly IQueueService _queueService; private readonly IThemeService _themeService; + private readonly IMixThemeImportService _importService; private readonly MixIdentityService _mixIdentityService; private readonly IHubContext _hubContext; private readonly HttpService _httpService; @@ -33,7 +36,8 @@ public MixApplicationService( IThemeService themeService, IQueueService queueService, MixCacheService cacheService, - IMixTenantService mixTenantService) + IMixTenantService mixTenantService, + IMixThemeImportService importService) : base(httpContextAccessor, cacheService, mixTenantService) { _cmsUow = cmsUow; @@ -42,6 +46,7 @@ public MixApplicationService( _mixIdentityService = mixIdentityService; _themeService = themeService; _queueService = queueService; + _importService = importService; } public async Task Install(MixApplicationViewModel app, CancellationToken cancellationToken = default) { @@ -51,6 +56,8 @@ public async Task Install(MixApplicationViewModel app, _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {filePath} Successfully"); MixFileHelper.UnZipFile(filePath, deployUrl); _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {filePath} Successfully"); + + await ImportSchema($"{deployUrl}/schema", cancellationToken); app.TemplateId = await SaveTemplate(app.TemplateId, name, deployUrl, app.BaseHref); app.SetUowInfo(_cmsUow, CacheService); app.DeployUrl = deployUrl; @@ -62,8 +69,93 @@ public async Task Install(MixApplicationViewModel app, filePath }; await app.SaveAsync(); + _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Finished", 200, string.Empty); return app; } + public async Task UpdatePackage(MixApplicationViewModel app, string packageFileUrl, CancellationToken cancellationToken = default) + { + try + { + if (app == null) + { + throw new MixException(MixErrorStatus.NotFound, "App not found"); + } + string name = SeoHelper.GetSEOString(app.DisplayName); + var packages = app.AppSettings.Value("packages") ?? new(); + + string deployUrl = $"{MixFolders.StaticFiles}/{MixFolders.MixApplications}/{name}"; + string package = await DownloadPackage(name, app.PackageFilePath, deployUrl); + MixFileHelper.UnZipFile(package, deployUrl); + + await ImportSchema($"{deployUrl}/schema", cancellationToken); + await SaveTemplate(app.TemplateId, name, deployUrl, app.BaseHref); + + packages.Add(package); + app.AppSettings["activePackage"] = package; + app.AppSettings["packages"] = packages; + return app; + } + catch (MixException) + { + throw; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); + } + } + + public async Task RestorePackage(RestoreMixApplicationPackageDto dto, CancellationToken cancellationToken) + { + try + { + _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {dto.PackageFilePath}"); + var app = await MixApplicationViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.Id == dto.AppId); + if (app == null) + { + throw new MixException(MixErrorStatus.NotFound, "App Not Found"); + } + if (!File.Exists(dto.PackageFilePath)) + { + throw new MixException(MixErrorStatus.NotFound, $"Package {dto.PackageFilePath} Not Found"); + } + string name = SeoHelper.GetSEOString(app.DisplayName); + string deployUrl = $"{MixFolders.StaticFiles}/{MixFolders.MixApplications}/{name}"; + MixFileHelper.UnZipFile(dto.PackageFilePath, deployUrl); + + _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {dto.PackageFilePath} Successfully"); + + await ImportSchema($"{deployUrl}/schema", cancellationToken); + await SaveTemplate(app.TemplateId, name, deployUrl, app.BaseHref); + + app.AppSettings["activePackage"] = dto.PackageFilePath; + + await app.SaveAsync(cancellationToken); + + return app; + } + catch (MixException) + { + throw; + } + catch (Exception ex) + { + throw new MixException(MixErrorStatus.Badrequest, ex); + } + } + + private async Task ImportSchema(string schemaFolder, CancellationToken cancellationToken) + { + if (Directory.Exists(schemaFolder)) + { + var schema = await _importService.LoadSchema(schemaFolder); + schema.ThemeId = CurrentTenant.Themes.FirstOrDefault().Id; + if (schema != null && schema.IsValid) + { + await _importService.ImportSelectedItemsAsync(schema); + } + } + } private async Task SaveTemplate(int? templateId, string name, string deployUrl, string baseHref) { @@ -120,15 +212,12 @@ private async Task ModifyFilesAndFolders(string deployUrl, string topFolder, str } - Regex regex = new($"((\\\"|\\'|\\(\\/|\\`)(\\.)?(\\/)?(([0-9a-zA-Z\\/\\._-])+)\\.({allowExtensionsPattern})(\"|\\'|\\)|\\`))"); - Regex baseHrefRegex = new("(base href=\"(.+?)\")"); - indexFile.Content = indexFile.Content.Replace("[basePath]/", string.Empty); + Regex regex = new($"((\\\"|\\'|\\(\\/|\\`)(\\.)?(\\/)?(([0-9a-zA-Z\\/\\.\\$\\{{\\}}_-])+)\\.({allowExtensionsPattern})(\\\"|\\'|\\)|\\`))"); + Regex baseHrefRegex = new("(base href=\"(.{0,})\")"); + Regex basePathRegex = new("(\\[\\[?basePath\\]\\]?\\/?)"); indexFile.Content = regex.Replace(indexFile.Content, $"$2/{deployUrl}/$5.$7$2"); - indexFile.Content = baseHrefRegex.Replace(indexFile.Content, $"base href=\"{baseHref}\"") - .Replace("[baseRoute]", deployUrl) - - .Replace("options['baseRoute']", $"'{deployUrl}'") - .Replace("options['baseHref']", $"'/{baseHref}'"); + indexFile.Content = baseHrefRegex.Replace(indexFile.Content, $"base href=\"{baseHref}\""); + indexFile.Content = basePathRegex.Replace(indexFile.Content, $"/{deployUrl}/"); var activeTheme = await _themeService.GetActiveTheme(); MixTemplateViewModel template = await MixTemplateViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.Id == templateId); @@ -142,7 +231,6 @@ private async Task ModifyFilesAndFolders(string deployUrl, string topFolder, str MixTenantId = CurrentTenant.Id, Scripts = string.Empty, Styles = string.Empty, - CreatedBy = _mixIdentityService.GetClaim(HttpContextAccessor.HttpContext.User, MixClaims.Username) }; template.Content = indexFile.Content.Replace("@", "@@") .Replace("", "
@Model.AppSettings.ToString()
"); @@ -154,7 +242,6 @@ private async Task ModifyFilesAndFolders(string deployUrl, string topFolder, str } catch (Exception) { - throw; } } @@ -166,7 +253,9 @@ private Task ReplaceContent(FileModel file, string folders, string deployUrl) try { _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Modifying {file.Filename}{file.Extension}"); - Regex rg = new($"((\\\"|\\'|\\(\\/|\\`)(\\.)?(\\/)?(([0-9a-zA-Z\\/\\._-])+)\\.({allowExtensionsPattern})(\"|\\'|\\)|\\`))"); + Regex rg = new($"((\\\"|\\'|\\(\\/|\\`)(\\.)?(\\/)?(([0-9a-zA-Z\\/\\.\\$\\{{\\}}_-])+)\\.({allowExtensionsPattern})(\\\"|\\'|\\)|\\`))"); + Regex basePathRegex = new("(\\[\\[?basePath\\]\\]?\\/?)"); + Regex apiEndpointRegex = new("(\\[\\[?apiEndpoint\\]\\]?\\/?)"); if (rg.IsMatch(file.Content)) { file.Content = rg.Replace(file.Content, $"$2/{deployUrl}/$5.$7$2"); @@ -180,7 +269,8 @@ private Task ReplaceContent(FileModel file, string folders, string deployUrl) } } - file.Content = file.Content.Replace("[basePath]", $"/{deployUrl}"); + file.Content = basePathRegex.Replace(file.Content, $"/{deployUrl}/"); + file.Content = apiEndpointRegex.Replace(file.Content, $"{CurrentTenant.Configurations.Domain.TrimEnd('/')}"); MixFileHelper.SaveFile(file); } @@ -221,71 +311,7 @@ private async Task DownloadPackage(string name, string packageUrl, strin } } - public async Task UpdatePackage(MixApplicationViewModel app, string packageFileUrl, CancellationToken cancellationToken = default) - { - try - { - if (app == null) - { - throw new MixException(MixErrorStatus.NotFound, "App not found"); - } - string name = SeoHelper.GetSEOString(app.DisplayName); - var packages = app.AppSettings.Value("packages") ?? new(); - - string deployUrl = $"{MixFolders.StaticFiles}/{MixFolders.MixApplications}/{name}"; - string package = await DownloadPackage(name, app.PackageFilePath, deployUrl); - MixFileHelper.UnZipFile(package, deployUrl); - await SaveTemplate(app.TemplateId, name, deployUrl, app.BaseHref); - packages.Add(package); - app.AppSettings["activePackage"] = package; - app.AppSettings["packages"] = packages; - return app; - } - catch (MixException) - { - throw; - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.Badrequest, ex); - } - } - - public async Task RestorePackage(RestoreMixApplicationPackageDto dto, CancellationToken cancellationToken) - { - try - { - _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {dto.PackageFilePath}"); - var app = await MixApplicationViewModel.GetRepository(_cmsUow, CacheService).GetSingleAsync(m => m.Id == dto.AppId); - if (app == null) - { - throw new MixException(MixErrorStatus.NotFound, "App Not Found"); - } - if (!File.Exists(dto.PackageFilePath)) - { - throw new MixException(MixErrorStatus.NotFound, $"Package {dto.PackageFilePath} Not Found"); - } - string name = SeoHelper.GetSEOString(app.DisplayName); - string deployUrl = $"{MixFolders.StaticFiles}/{MixFolders.MixApplications}/{name}"; - MixFileHelper.UnZipFile(dto.PackageFilePath, deployUrl); - - _ = AlertAsync(_hubContext.Clients.Group("Theme"), "Status", 200, $"Extract Package {dto.PackageFilePath} Successfully"); - await SaveTemplate(app.TemplateId, name, deployUrl, app.BaseHref); - app.AppSettings["activePackage"] = dto.PackageFilePath; - - await app.SaveAsync(cancellationToken); - - return app; - } - catch (MixException) - { - throw; - } - catch (Exception ex) - { - throw new MixException(MixErrorStatus.Badrequest, ex); - } - } + #region Helpers public async Task AlertAsync(IClientProxy clients, string action, int status, T message) @@ -298,11 +324,11 @@ public async Task AlertAsync(IClientProxy clients, string action, int status, var logMsg = new JObject() { new JProperty("created_at", DateTime.UtcNow), - new JProperty("id", HttpContextAccessor.HttpContext?.Request.HttpContext.Connection.Id.ToString()), + //new JProperty("id", HttpContextAccessor.HttpContext?.Request.HttpContext.Connection.Id.ToString()), new JProperty("address", address), - new JProperty("ip_address", HttpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString()), - new JProperty("user", _mixIdentityService.GetClaim(HttpContextAccessor.HttpContext.User, MixClaims.Username)), - new JProperty("request_url", HttpContextAccessor.HttpContext.Request.Path.Value), + //new JProperty("ip_address", HttpContextAccessor.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.ToString()), + //new JProperty("user", _mixIdentityService.GetClaim(HttpContextAccessor.HttpContext.User, MixClaims.Username)), + //new JProperty("request_url", HttpContextAccessor.HttpContext.Request.Path.Value), new JProperty("action", action), new JProperty("status", status), new JProperty("message", message) diff --git a/src/platform/mix.constant/Constants/MixQueueActions.cs b/src/platform/mix.constant/Constants/MixQueueActions.cs index b5c5068ec..81b461d11 100644 --- a/src/platform/mix.constant/Constants/MixQueueActions.cs +++ b/src/platform/mix.constant/Constants/MixQueueActions.cs @@ -2,6 +2,7 @@ { public class MixQueueActions { + public const string InstallMixApplication = "InstallMixApplication"; public const string AuditLog = "AuditLog"; public const string EnqueueLog = "QueueLog"; public const string AckLog = "AckLog"; diff --git a/src/modules/mix.portal/Domain/Dtos/RestoreMixApplicationPackageDto.cs b/src/platform/mix.library/Dtos/RestoreMixApplicationPackageDto.cs similarity index 81% rename from src/modules/mix.portal/Domain/Dtos/RestoreMixApplicationPackageDto.cs rename to src/platform/mix.library/Dtos/RestoreMixApplicationPackageDto.cs index b66cff7dc..0719554c3 100644 --- a/src/modules/mix.portal/Domain/Dtos/RestoreMixApplicationPackageDto.cs +++ b/src/platform/mix.library/Dtos/RestoreMixApplicationPackageDto.cs @@ -1,4 +1,4 @@ -namespace Mix.Portal.Domain.Dtos +namespace Mix.Lib.Dtos { public sealed class RestoreMixApplicationPackageDto { diff --git a/src/modules/mix.portal/Domain/Interfaces/IMixApplicationService.cs b/src/platform/mix.library/Interfaces/IMixApplicationService.cs similarity index 92% rename from src/modules/mix.portal/Domain/Interfaces/IMixApplicationService.cs rename to src/platform/mix.library/Interfaces/IMixApplicationService.cs index 5eedbdbf8..99050cd8a 100644 --- a/src/modules/mix.portal/Domain/Interfaces/IMixApplicationService.cs +++ b/src/platform/mix.library/Interfaces/IMixApplicationService.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.SignalR; +using Mix.Lib.Dtos; -namespace Mix.Portal.Domain.Interfaces +namespace Mix.Lib.Interfaces { public interface IMixApplicationService { diff --git a/src/platform/mix.library/Interfaces/IMixThemeImportService.cs b/src/platform/mix.library/Interfaces/IMixThemeImportService.cs index 4e30673bb..d0c43a77f 100644 --- a/src/platform/mix.library/Interfaces/IMixThemeImportService.cs +++ b/src/platform/mix.library/Interfaces/IMixThemeImportService.cs @@ -8,5 +8,6 @@ public interface IMixThemeImportService public Task LoadSchema(); public void ExtractTheme(IFormFile themeFile); public Task ImportSelectedItemsAsync(SiteDataViewModel siteData); + Task LoadSchema(string folder); } } diff --git a/src/platform/mix.library/Services/MixTenantService.cs b/src/platform/mix.library/Services/MixTenantService.cs index f28e46eed..3b9bf3b9b 100644 --- a/src/platform/mix.library/Services/MixTenantService.cs +++ b/src/platform/mix.library/Services/MixTenantService.cs @@ -11,6 +11,7 @@ public sealed class MixTenantService : IMixTenantService public List AllTenants { get; set; } public List AllCultures { get; set; } + public List AllThemes { get; set; } public MixTenantService(DatabaseService databaseService) { @@ -29,6 +30,7 @@ public async Task Reload(CancellationToken cancellationToken = default) var domains = await dbContext.MixDomain.Where(p => tenantIds.Contains(p.MixTenantId)).ToListAsync(cancellationToken); AllCultures = await dbContext.MixCulture.ToListAsync(cancellationToken); + AllThemes = await dbContext.MixTheme.ToListAsync(cancellationToken); var tenants = mixTenants .Select(p => new MixTenantSystemModel @@ -41,6 +43,7 @@ public async Task Reload(CancellationToken cancellationToken = default) Configurations = new TenantConfigService(p.SystemName).AppSettings, Domains = domains.Where(d => d.MixTenantId == p.Id).ToList(), Cultures = AllCultures.Where(c => c.MixTenantId == p.Id).ToList(), + Themes = AllThemes.Where(c => c.MixTenantId == p.Id).ToList(), }) .ToList(); diff --git a/src/platform/mix.library/Services/MixThemeImportService.cs b/src/platform/mix.library/Services/MixThemeImportService.cs index b2f739ff1..4bc859640 100644 --- a/src/platform/mix.library/Services/MixThemeImportService.cs +++ b/src/platform/mix.library/Services/MixThemeImportService.cs @@ -30,7 +30,10 @@ public MixTenantSystemModel CurrentTenant { if (_currentTenant == null) { - _currentTenant = _session.Get(MixRequestQueryKeywords.Tenant); + _currentTenant = _session?.Get(MixRequestQueryKeywords.Tenant) ?? new() + { + Id = 1 + }; } return _currentTenant; } @@ -91,13 +94,19 @@ await httpService.DownloadAsync( } - public async Task LoadSchema() + public Task LoadSchema() + { + return LoadSchema($"{MixFolders.ThemePackage}/{MixThemePackageConstants.SchemaFolder}"); + } + + + public async Task LoadSchema(string folder) { using (var serviceScope = _serviceProvider.CreateScope()) { _uow = serviceScope.ServiceProvider.GetRequiredService>(); _context = _uow.DbContext; - var strSchema = MixFileHelper.GetFile(MixThemePackageConstants.SchemaFilename, MixFileExtensions.Json, $"{MixFolders.ThemePackage}/{MixThemePackageConstants.SchemaFolder}"); + var strSchema = MixFileHelper.GetFile(MixThemePackageConstants.SchemaFilename, MixFileExtensions.Json, folder); var siteStructures = JObject.Parse(strSchema.Content).ToObject(); await ValidateSiteData(siteStructures); return siteStructures; @@ -157,7 +166,7 @@ private async Task ImportSiteData() _currentCulture = _context.MixCulture.First(m => m.MixTenantId == CurrentTenant.Id - && (!string.IsNullOrEmpty(_siteData.Specificulture) || m.Specificulture == _siteData.Specificulture)); + && (string.IsNullOrEmpty(_siteData.Specificulture) || m.Specificulture == _siteData.Specificulture)); if (_siteData.ThemeId == 0) { @@ -278,7 +287,7 @@ private async Task MigrateMixDatabaseAsync(IMixDbService mixDbService) } } } - + private async Task MigrateSystemMixDatabaseAsync(IMixDbService mixDbService, CancellationToken cancellationToken = default) { await mixDbService.MigrateSystemDatabases(cancellationToken); @@ -545,9 +554,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 +768,7 @@ private async Task ImportEntitiesAsync(MixCmsContext dbContext, List data, private async Task ImportContentDataAsync(List data, Dictionary dic, Dictionary parentDic) where T : MultilingualContentBase { - if (data.Count > 0) + if (data != null && data.Count > 0) { foreach (var item in data) { @@ -857,6 +866,7 @@ private async Task ValidateSiteData(SiteDataViewModel siteData) siteData.InvalidDatabaseNames.AddRange(existedDbNameErrors); siteData.IsValid = !siteData.Errors.Any(); } + #endregion Import } } diff --git a/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs b/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs index afe14deec..e93e28f52 100644 --- a/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs +++ b/src/platform/mix.library/Subscribers/MixBackgroundTaskSubscriber.cs @@ -3,6 +3,7 @@ using Mix.Communicator.Models; using Mix.Communicator.Services; using Mix.Database.Entities.Account; +using Mix.Lib.Interfaces; using Mix.Mixdb.Event.Services; using Mix.Queue.Engines; using Mix.Queue.Engines.MixQueue; @@ -23,7 +24,8 @@ public class MixBackgroundTaskSubscriber : SubscriberBase private static string[] allowActions = { MixQueueActions.SendMail, - MixQueueActions.MixDbEvent + MixQueueActions.MixDbEvent, + MixQueueActions.InstallMixApplication }; public MixBackgroundTaskSubscriber( IServiceProvider serviceProvider, @@ -59,6 +61,10 @@ public override async Task Handler(MessageQueueModel model) switch (model.Action) { + case MixQueueActions.InstallMixApplication: + await InstallMixApplication(model); + break; + case MixQueueActions.SendMail: await SendMail(model); break; @@ -73,6 +79,15 @@ public override async Task Handler(MessageQueueModel model) } } + private async Task InstallMixApplication(MessageQueueModel model) + { + var cmsUow = GetRequiredService>(); + IMixApplicationService _applicationService = GetRequiredService(); + var app = model.ParseData(); + await _applicationService.Install(app); + await cmsUow.CompleteAsync(); + } + public override Task HandleException(MessageQueueModel model, Exception ex) { return MixLogService.LogExceptionAsync(ex); diff --git a/src/modules/mix.portal/Domain/ViewModels/MixApplicationViewModel.cs b/src/platform/mix.library/ViewModels/MixApplicationViewModel.cs similarity index 97% rename from src/modules/mix.portal/Domain/ViewModels/MixApplicationViewModel.cs rename to src/platform/mix.library/ViewModels/MixApplicationViewModel.cs index afa81d350..848255652 100644 --- a/src/modules/mix.portal/Domain/ViewModels/MixApplicationViewModel.cs +++ b/src/platform/mix.library/ViewModels/MixApplicationViewModel.cs @@ -1,4 +1,4 @@ -namespace Mix.Portal.Domain.ViewModels +namespace Mix.Lib.ViewModels { public sealed class MixApplicationViewModel : TenantDataViewModelBase 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) { } diff --git a/src/platform/mix.service/Models/MixTenantSystemModel.cs b/src/platform/mix.service/Models/MixTenantSystemModel.cs index a7e77713a..a50b41763 100644 --- a/src/platform/mix.service/Models/MixTenantSystemModel.cs +++ b/src/platform/mix.service/Models/MixTenantSystemModel.cs @@ -17,6 +17,7 @@ public class MixTenantSystemModel public List Domains { get; set; } public List Cultures { get; set; } = new(); + public List Themes { get; set; } = new(); public TenantConfigurationModel Configurations { get; set; } }