diff --git a/docs/en/Modules/Cms-Kit/Blogging.md b/docs/en/Modules/Cms-Kit/Blogging.md index 91c14d79e8..d45598be52 100644 --- a/docs/en/Modules/Cms-Kit/Blogging.md +++ b/docs/en/Modules/Cms-Kit/Blogging.md @@ -118,4 +118,8 @@ This module follows the [Domain Services Best Practices & Conventions](https://d - CmsBlogs - CmsBlogPosts -- CmsBlogFeatures \ No newline at end of file +- CmsBlogFeatures + +## Entity Extensions + +Check the ["Entity Extensions" section of the CMS Kit Module documentation](Index.md#entity-extensions) to see how to extend entities of the Blogging Feature of the CMS Kit module. \ No newline at end of file diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index e40f78922e..952fa87aba 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -80,3 +80,66 @@ All tables/collections use the `Cms` prefix by default. Set static properties on This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string. See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details. + +## Entity Extensions + +[Module entity extension](https://docs.abp.io/en/abp/latest/Module-Entity-Extensions) system is a **high-level** extension system that allows you to **define new properties** for existing entities of the dependent modules. It automatically **adds properties to the entity**, **database**, **HTTP API and user interface** in a single point. + +To extend entities of the CMS Kit Pro module, open your `YourProjectNameModuleExtensionConfigurator` class inside of your `DomainShared` project and change the `ConfigureExtraProperties` method like shown below. + +```csharp +public static void ConfigureExtraProperties() +{ + OneTimeRunner.Run(() => + { + ObjectExtensionManager.Instance.Modules() + .ConfigureCmsKit(cmsKit => + { + cmsKit.ConfigureBlog(plan => // extend the Blog entity + { + plan.AddOrUpdateProperty( //property type: string + "BlogDescription", //property name + property => { + //validation rules + property.Attributes.Add(new RequiredAttribute()); //adds required attribute to the defined property + + //...other configurations for this property + } + ); + }); + + cmsKit.ConfigureBlogPost(blogPost => // extend the BlogPost entity + { + blogPost.AddOrUpdateProperty( //property type: string + "BlogPostDescription", //property name + property => { + //validation rules + property.Attributes.Add(new RequiredAttribute()); //adds required attribute to the defined property + property.Attributes.Add( + new StringLengthAttribute(MyConsts.MaximumDescriptionLength) { + MinimumLength = MyConsts.MinimumDescriptionLength + } + ); + + //...other configurations for this property + } + ); + }); + }); + }); +} +``` + +* `ConfigureCmsKit(...)` method is used to configure the entities of the CMS Kit module. + +* `cmsKit.ConfigureBlog(...)` is used to configure the **Blog** entity of the CMS Kit module. You can add or update your extra properties of the +**Blog** entity. + +* `cmsKit.ConfigureBlogPost(...)` is used to configure the **BlogPost** entity of the CMS Kit module. You can add or update your extra properties of the **BlogPost** entity. + +* You can also set some validation rules for the property that you defined. In the above sample, `RequiredAttribute` and `StringLengthAttribute` were added for the property named **"BlogPostDescription"**. + +* When you define the new property, it will automatically add to **Entity**, **HTTP API** and **UI** for you. + * Once you define a property, it appears in the create and update forms of the related entity. + * New properties also appear in the datatable of the related page. + diff --git a/docs/en/Road-Map.md b/docs/en/Road-Map.md index 8fa7b9b2e7..f8b772dbca 100644 --- a/docs/en/Road-Map.md +++ b/docs/en/Road-Map.md @@ -4,11 +4,11 @@ This document provides a road map, release schedule and planned features for the ## Next Versions -### v7.3 +### v7.4 -The next version will be 7.3 and planned to release the stable 7.3 version in July, 2023. In the version 7.3, we will mostly focus on stabilizing and enhancing existing features, improving the developer experience, as well as adding relatively minor new features. +The next version will be 7.4 and planned to release the stable 7.4 version in September, 2023. In the version 7.4, we will mostly focus on stabilizing and enhancing existing features, improving the developer experience, as well as adding relatively minor new features. -See the [7.3 milestone](https://github.com/abpframework/abp/milestone/82) for all the issues we've planned to work on. +See the [7.4 milestone](https://github.com/abpframework/abp/milestone/85) for all the issues we've planned to work on. ## Backlog Items @@ -28,6 +28,8 @@ Here, a list of major items in the backlog we are considering to work on in the * [#16342](https://github.com/abpframework/abp/issues/16342) / CmsKit: Meta information for SEO * [#16260](https://github.com/abpframework/abp/issues/16260) / GCP Blob Storage Provider * [#15932](https://github.com/abpframework/abp/issues/15932) / Introduce ABP Diagnostics Module +* [#16756](https://github.com/abpframework/abp/issues/16756) / Blob Storing - Provider configuration UI +* [#16744](https://github.com/abpframework/abp/issues/16744) / State Management API You can always check the milestone planning and the prioritized backlog issues on [the GitHub repository](https://github.com/abpframework/abp/milestones) for a detailed road map. The backlog items are subject to change. We are adding new items and changing priorities based on the community feedbacks and goals of the project. diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Applications/AbpApplicationManager.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Applications/AbpApplicationManager.cs index 5b90574e59..e02d671652 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Applications/AbpApplicationManager.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Applications/AbpApplicationManager.cs @@ -44,8 +44,8 @@ public class AbpApplicationManager : OpenIddictApplicationManager(); + _testData = ServiceProvider.GetRequiredService(); + } + + [Fact] + public async Task Populate_Descriptor_With_Application_Test() + { + var app1 = (await _applicationManager.FindByClientIdAsync(_testData.App1ClientId)).As(); + + var descriptor = new AbpApplicationDescriptor(); + await _applicationManager.PopulateAsync(descriptor, app1); + + app1.ClientUri.ShouldNotBeNull(); + app1.LogoUri.ShouldNotBeNull(); + + descriptor.ClientUri.ShouldBe(app1.ClientUri); + descriptor.LogoUri.ShouldBe(app1.LogoUri); + } + + [Fact] + public async Task Populate_Application_With_Descriptor_Test() + { + var app1 = (await _applicationManager.FindByClientIdAsync(_testData.App1ClientId)).As(); + + var descriptor = new AbpApplicationDescriptor() + { + ClientUri = "https://new.com", + LogoUri = "https://new.com/logo.png" + }; + await _applicationManager.PopulateAsync(app1, descriptor); + + app1.ClientUri.ShouldBe(descriptor.ClientUri); + app1.LogoUri.ShouldBe(descriptor.LogoUri); + } +} diff --git a/modules/openiddict/test/Volo.Abp.OpenIddict.TestBase/Volo/Abp/OpenIddict/OpenIddictDataSeedContributor.cs b/modules/openiddict/test/Volo.Abp.OpenIddict.TestBase/Volo/Abp/OpenIddict/OpenIddictDataSeedContributor.cs index eccdf828c6..df8a88a9d3 100644 --- a/modules/openiddict/test/Volo.Abp.OpenIddict.TestBase/Volo/Abp/OpenIddict/OpenIddictDataSeedContributor.cs +++ b/modules/openiddict/test/Volo.Abp.OpenIddict.TestBase/Volo/Abp/OpenIddict/OpenIddictDataSeedContributor.cs @@ -92,7 +92,7 @@ public class OpenIddictDataSeedContributor : IDataSeedContributor, ITransientDep private async Task CreateApplicationsAsync() { - await _applicationManager.CreateAsync(await GetOpenIddictApplicationModelAsync(_testData.App1Id, new OpenIddictApplicationDescriptor + await _applicationManager.CreateAsync(await GetOpenIddictApplicationModelAsync(_testData.App1Id, new AbpApplicationDescriptor { ClientId = _testData.App1ClientId, ConsentType = OpenIddictConstants.ConsentTypes.Explicit, @@ -137,10 +137,12 @@ public class OpenIddictDataSeedContributor : IDataSeedContributor, ITransientDep OpenIddictConstants.Permissions.Scopes.Phone, OpenIddictConstants.Permissions.Prefixes.Scope + _testData.Scope1Name - } + }, + ClientUri = "https://abp.io/TestApplication", + LogoUri = "https://abp.io/TestApplication.png" })); - await _applicationManager.CreateAsync(await GetOpenIddictApplicationModelAsync(_testData.App2Id, new OpenIddictApplicationDescriptor + await _applicationManager.CreateAsync(await GetOpenIddictApplicationModelAsync(_testData.App2Id, new AbpApplicationDescriptor { ClientId = _testData.App2ClientId, ConsentType = OpenIddictConstants.ConsentTypes.Explicit, @@ -186,7 +188,9 @@ public class OpenIddictDataSeedContributor : IDataSeedContributor, ITransientDep OpenIddictConstants.Permissions.Prefixes.Scope + _testData.Scope1Name, OpenIddictConstants.Permissions.Prefixes.Scope + _testData.Scope2Name, - } + }, + ClientUri = "https://abp.io/TestApplication2", + LogoUri = "https://abp.io/TestApplication2.png" })); } @@ -240,7 +244,6 @@ public class OpenIddictDataSeedContributor : IDataSeedContributor, ITransientDep Subject = "TestSubject1", Type = OpenIddictConstants.AuthorizationTypes.Permanent, CreationDate = _clock.Now - })); await _authorizationManager.CreateAsync(await GetOpenIddictAuthorizationModelAsync(_testData.Authorization2Id, new OpenIddictAuthorizationDescriptor diff --git a/npm/ng-packs/apps/dev-app/project.json b/npm/ng-packs/apps/dev-app/project.json index 88ce39325b..30fed19de1 100644 --- a/npm/ng-packs/apps/dev-app/project.json +++ b/npm/ng-packs/apps/dev-app/project.json @@ -24,9 +24,9 @@ "bundleName": "bootstrap-rtl.min" }, { - "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", - "inject": true, - "bundleName": "bootstrap-ltr.min" + "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", + "inject": true, + "bundleName": "bootstrap-ltr.min" }, { "input": "node_modules/@volo/ngx-lepton-x.lite/assets/css/bootstrap-dim.css", diff --git a/npm/ng-packs/apps/dev-app/src/app/app.module.ts b/npm/ng-packs/apps/dev-app/src/app/app.module.ts index 65c79a5707..ac56d2736e 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app.module.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app.module.ts @@ -1,22 +1,22 @@ -import { ThemeBasicModule } from '@abp/ng.theme.basic'; -import { AccountConfigModule } from '@abp/ng.account/config'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CoreModule } from '@abp/ng.core'; import { registerLocale } from '@abp/ng.core/locale'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x'; +import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts'; import { IdentityConfigModule } from '@abp/ng.identity/config'; +import { AbpOAuthModule } from '@abp/ng.oauth'; import { SettingManagementConfigModule } from '@abp/ng.setting-management/config'; import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config'; -import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x'; -import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts'; -import { ThemeSharedModule } from '@abp/ng.theme.shared'; -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { FeatureManagementModule } from '@abp/ng.feature-management'; +import { AccountConfigModule } from '@abp/ng.account/config'; +import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account/account-layout'; import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { APP_ROUTE_PROVIDER } from './route.provider'; -import { FeatureManagementModule } from '@abp/ng.feature-management'; -import { AbpOAuthModule } from '@abp/ng.oauth'; @NgModule({ imports: [ @@ -36,7 +36,9 @@ import { AbpOAuthModule } from '@abp/ng.oauth'; TenantManagementConfigModule.forRoot(), FeatureManagementModule.forRoot(), SettingManagementConfigModule.forRoot(), - ThemeBasicModule.forRoot(), + ThemeLeptonXModule.forRoot(), + SideMenuLayoutModule.forRoot(), + AccountLayoutModule.forRoot(), ], providers: [APP_ROUTE_PROVIDER], declarations: [AppComponent], diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index edac2bebb9..287bd0963f 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -55,7 +55,7 @@ "@abp/ng.setting-management": "~7.3.0-rc.1", "@abp/ng.tenant-management": "~7.3.0-rc.1", "@abp/ng.theme.basic": "~7.3.0-rc.1", - "@abp/ng.theme.lepton-x": "^2.2.0", + "@abp/ng.theme.lepton-x": "^2.3.0-rc.1", "@abp/ng.theme.shared": "~7.3.0-rc.1", "@abp/utils": "~7.3.0-rc.1", "@angular-devkit/build-angular": "16.0.1", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs index 6726069d0d..a7e9c7eb2c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs @@ -15,7 +15,7 @@ public class MyProjectNameEFCoreDbSchemaMigrator : ITransientDependency public async Task MigrateAsync() { - /* We intentionally resolving the MyProjectNameDbContext + /* We intentionally resolve the MyProjectNameDbContext * from IServiceProvider (instead of directly injecting it) * to properly get the connection string of the current tenant in the * current scope. diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs index 6726069d0d..a7e9c7eb2c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Data/MyProjectNameEFCoreDbSchemaMigrator.cs @@ -15,7 +15,7 @@ public class MyProjectNameEFCoreDbSchemaMigrator : ITransientDependency public async Task MigrateAsync() { - /* We intentionally resolving the MyProjectNameDbContext + /* We intentionally resolve the MyProjectNameDbContext * from IServiceProvider (instead of directly injecting it) * to properly get the connection string of the current tenant in the * current scope. diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Data/MyProjectNameEFCoreDbSchemaMigrator.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Data/MyProjectNameEFCoreDbSchemaMigrator.cs index 6726069d0d..a7e9c7eb2c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Data/MyProjectNameEFCoreDbSchemaMigrator.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Data/MyProjectNameEFCoreDbSchemaMigrator.cs @@ -15,7 +15,7 @@ public class MyProjectNameEFCoreDbSchemaMigrator : ITransientDependency public async Task MigrateAsync() { - /* We intentionally resolving the MyProjectNameDbContext + /* We intentionally resolve the MyProjectNameDbContext * from IServiceProvider (instead of directly injecting it) * to properly get the connection string of the current tenant in the * current scope. diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Data/MyProjectNameEFCoreDbSchemaMigrator.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Data/MyProjectNameEFCoreDbSchemaMigrator.cs index 6726069d0d..a7e9c7eb2c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Data/MyProjectNameEFCoreDbSchemaMigrator.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Data/MyProjectNameEFCoreDbSchemaMigrator.cs @@ -15,7 +15,7 @@ public class MyProjectNameEFCoreDbSchemaMigrator : ITransientDependency public async Task MigrateAsync() { - /* We intentionally resolving the MyProjectNameDbContext + /* We intentionally resolve the MyProjectNameDbContext * from IServiceProvider (instead of directly injecting it) * to properly get the connection string of the current tenant in the * current scope. diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs index 10b3d75c3d..f4b87fbd57 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs @@ -20,7 +20,7 @@ public class EntityFrameworkCoreMyProjectNameDbSchemaMigrator public async Task MigrateAsync() { - /* We intentionally resolving the MyProjectNameDbContext + /* We intentionally resolve the MyProjectNameDbContext * from IServiceProvider (instead of directly injecting it) * to properly get the connection string of the current tenant in the * current scope.