@ -0,0 +1,139 @@ |
|||
# ABP Commercial 4.3 RC Has Been Published |
|||
|
|||
ABP Commercial version 4.3 RC (Release Candidate) has been published alongside ABP Framework 4.3. RC (TODO: link). I will introduce the new features in this blog post. Here, a list of highlights for this release; |
|||
|
|||
* The **microservice starter template** is getting more mature. We've also added a **service template** to add new microservices to the solution. |
|||
* New option for the application starter template to have a **separate database schema for tenant databases**. |
|||
* New **Forms** module to create surveys |
|||
* **Enable/disable modules** per edition/tenant. |
|||
* **Lepton theme** and **Account module**'s source codes are available with the Team License. |
|||
|
|||
Here, some other features already covered in the ABP Framework announcement, but worth mentioning here since they are also implemented for the ABP Commercial; |
|||
|
|||
* **Blazor UI server-side** support |
|||
|
|||
* **Email setting** management UI |
|||
* **Module extensibility** system is now available for the **Blazor UI** too. |
|||
|
|||
> This post doesn't cover the features and changes done on the ABP Framework side. Please also see the **ABP Framework 4.3. RC blog post** (TODO: link). |
|||
|
|||
## The Migration Guide |
|||
|
|||
**This upgrade requires some manual work documented in [the migration guide](https://docs.abp.io/en/commercial/4.3/migration-guides/v4_3).** Please read the guide carefully. Even if your application doesn't break on upgrade, you should apply the changes to avoid future release problems. |
|||
|
|||
## What's New With The ABP Commercial 4.3 |
|||
|
|||
### The Microservice Starter Template |
|||
|
|||
We'd introduced an initial version of the [microservice starter template](https://docs.abp.io/en/commercial/4.3/startup-templates/microservice/index) in the [previous version](https://blog.abp.io/abp/ABP-IO-Platform-v4-2-RC-Has-Been-Released). It is getting more mature with this release. We've made a lot of improvements and changes, including; |
|||
|
|||
* New **"service" template** to add new microservices for the solution. It still requires some manual work to integrate to other services and gateways; however, it makes progress very easy and straightforward. |
|||
* Added [Tye](https://github.com/dotnet/tye) configuration to develop and test the solution easier. |
|||
* Added [Prometheus](https://prometheus.io/), [Grafana](https://grafana.com/) integrations for monitoring the solution. |
|||
* **Automatic database migrations**. Every microservice automatically checks and migrates/seeds its database on startup (concurrency issues are resolved for multiple instances). For multi-tenant systems, tenant databases are also upgraded by the queue. |
|||
* For multi-tenant systems, **databases are being created on the fly** for new tenants with separate connection strings. |
|||
* Created **separate solution (`.sln`) file** for each microservice, gateway, and application. In this way, you can focus on what you are working on. The main (roof) solution file only includes the executable projects in these solutions. |
|||
* All microservices are converted to the standard **layered module structure**, making it easier to align with ABP application development practices. |
|||
|
|||
After this release, **we will be preparing microservice development guides** based on this startup solution. |
|||
|
|||
### Separate Tenant Schema |
|||
|
|||
ABP's multi-tenancy system allows to the creation of dedicated databases for tenants. However, the application startup solution comes with a single database migration path; hence it has a single database schema. As a result, tenant databases have some host-related tables. These tables are not used for tenants, and they are always empty. However, their existence may disturb us as a clean developer. |
|||
|
|||
With this release, the application startup template provides an option to address this problem. So, if you want, you can have a separate migration path for tenant databases. Of course, this has a cost; You will have two DbContexts for migration purposes, bringing additional complexity to your solution. We've done our best to reduce this complexity and added a README file into the migration assembly. If you prefer this approach, please check that README file. |
|||
|
|||
You can specify the new `--separate-tenant-schema` parameter while you are creating a new solution using the [ABP CLI](https://docs.abp.io/en/abp/4.3/CLI): |
|||
|
|||
````bash |
|||
abp new Acme.BookStore --separate-tenant-schema |
|||
```` |
|||
|
|||
If you prefer the [ABP Suite](https://docs.abp.io/en/commercial/latest/abp-suite/create-solution) to create solutions, you can check the *Separated tenant schema* option. |
|||
|
|||
 |
|||
|
|||
### Creating Tenant Databases On The Fly |
|||
|
|||
With this release, the separate tenant database feature becomes more mature. When you create a new tenant with specifying a connection string, the **new database is automatically created** with all the tables and the initial seed data if available. So, tenants can immediately start to use the new database. With this change, tenant connection string textboxes come in the tenant creation modal: |
|||
|
|||
 |
|||
|
|||
Besides, we've added an "**Apply database migrations**" action to the tenant management UI to manually trigger the database creation & migration in case you have a problem with automatic migration: |
|||
|
|||
 |
|||
|
|||
Automatic migration only tries one time. If it fails, it writes the exception log and discards this request. For example, this can happen if the connection string is wrong or the database server is not available. In this case, you can manually retry with this action. |
|||
|
|||
> Note that this feature requires to **make changes in your solution**, if you upgrade from an older version. Because the tenant database creation and migration code are located in the application startup template. See the [version 4.3 migration guide](https://docs.abp.io/en/commercial/4.3/migration-guides/v4_3) for details. |
|||
|
|||
### New Module: CMS Kit |
|||
|
|||
CMS Kit module initial version has been released with this version. As stated in the ABP Framework 4.3 announcement post (TODO: link), it should be considered premature for now. |
|||
|
|||
For ABP Commercial application startup template, we are providing an option to include the CMS Kit into the solution while creating new solutions: |
|||
|
|||
 |
|||
|
|||
It is available only if you select the *Public web site* option. Once you include CMS Kit, a *Cms* item is shown on the menu: |
|||
|
|||
 |
|||
|
|||
Each CMS Kit feature can be individually enabled/disabled, using the global feature system. Once you disable a feature, it becomes completely invisible; even the related tables are not included in your database. |
|||
|
|||
CMS Kit features are separated into two categories: Open source (free) features and pro (commercial) features. For now, only newsletter and contact form features are commercial. By the time, we will add more free and commercial features. |
|||
|
|||
> We will create a separate blog post for the CMS Kit module, so I keep it short. |
|||
|
|||
### New Module: Forms |
|||
|
|||
*Forms* is a new module that is being introduced with this version. It looks like the Google Forms application; You dynamically create forms on the UI and send them to people to answer. Then you can get statistics/report and export answers to a CSV file. |
|||
|
|||
Forms module currently supports the following question types; |
|||
|
|||
* **Free text** |
|||
* Selecting a **single option** from a **dropdown** list or a **radio button** list |
|||
* **Multiple choice**: Selecting multiple options from a checkbox list |
|||
|
|||
**Screenshot: editing form and questions - view responses** |
|||
|
|||
 |
|||
|
|||
**Screenshot: answering to the form** |
|||
|
|||
 |
|||
|
|||
|
|||
|
|||
### Team License Source Code for Modules |
|||
|
|||
Team License users can't access the source code of modules and themes as a license restriction. You have to buy a Business or Enterprise license to download any module/theme's full source code. However, we got a lot of feedback from the Team License owners on the source code of the account module and the lepton theme. We see that customization of these two modules is highly necessary for most of our customers. |
|||
|
|||
With this version, we decided to allow Team License holders to download the source code of the **Account Module** and the **Lepton Theme** to freely customize them based on their requirements. |
|||
|
|||
You can **Replace these modules with their source code** using the ABP Suite: |
|||
|
|||
 |
|||
|
|||
Remember that; when you include the source code in your solution, it is your responsibility to upgrade them when we release new versions (while you don't have to upgrade them). |
|||
|
|||
### Lepton Theme Public Website Layout |
|||
|
|||
We'd added a public website application in the application starter template in the previous versions. It was using the public website layout of the Lepton Theme. We realized that the layout of this application is customized or completely changed in most of the solutions. So, with this version, the layout is included inside the application in the downloaded solution. You can freely change it. Before, you had to download it separately and include it in your solution manually. |
|||
|
|||
### Enable/Disable Modules |
|||
|
|||
With this release, all modules can be enabled/disabled per edition/tenant. You can allow/disallow modules when you click *Features* action for an edition or tenant: |
|||
|
|||
 |
|||
|
|||
### Other Features/Changes |
|||
|
|||
* ABP Suite now supports defining *required* navigation properties on code generation. |
|||
* **Blazor server-side** (with tiered option) is added for the application and microservice starter templates. |
|||
* An **"Email"** tab has been added to the Settings page to configure the email settings. |
|||
|
|||
## Feedback |
|||
|
|||
Please check out the ABP Commercial 4.3 RC to help us to release a more stable version. **The planned release date for the 4.3.0 final version is April 15, 2021**. |
|||
|
|||
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1,3 @@ |
|||
# Introducing the CMS Kit Module for the ABP Framework |
|||
|
|||
TODO... |
|||
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 126 KiB |
@ -1,3 +1,31 @@ |
|||
# ABP Framework 4.x to 4.3 Migration Guide |
|||
|
|||
TODO |
|||
## Blazor UI |
|||
|
|||
Implemented the Blazor Server Side support with this release. It required some packages and namespaces arrangements. **Existing Blazor (WebAssembly) applications should done the changes explained in this section**. |
|||
|
|||
### Namespace Changes |
|||
|
|||
- `AbpBlazorMessageLocalizerHelper` -> moved to Volo.Abp.AspNetCore.Components.Web |
|||
- `AbpRouterOptions` -> moved to Volo.Abp.AspNetCore.Components.Web.Theming.Routing |
|||
- `AbpToolbarOptions` and `IToolbarContributor` -> moved to Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars |
|||
- `IAbpUtilsService` -> moved to Volo.Abp.AspNetCore.Components.Web |
|||
- `PageHeader` -> moved to `Volo.Abp.AspNetCore.Components.Web.Theming.Layout`. |
|||
|
|||
In practice, if your application is broken because of the `Volo.Abp.AspNetCore.Components.WebAssembly.*` namespace, please try to switch to `Volo.Abp.AspNetCore.Components.Web.*` namespace. |
|||
|
|||
Remember to change namespaces in the `_Imports.razor` files. |
|||
|
|||
### Package Changes |
|||
|
|||
No change on the framework packages, but **module packages are separated as Web Assembly & Server**; |
|||
|
|||
* Use `Volo.Abp.Identity.Blazor.WebAssembly` NuGet package instead of `Volo.Abp.Identity.Blazor` package. Also, change `AbpIdentityBlazorModule` usage to `AbpIdentityBlazorWebAssemblyModule` in the `[DependsOn]` attribute on your module class. |
|||
* Use `Volo.Abp.TenantManagement.Blazor.WebAssembly` NuGet package instead of `Volo.Abp.TenantManagement.Blazor` package. Also, change `AbpTenantManagementBlazorModule` usage to `AbpTenantManagementBlazorWebAssemblyModule` in the `[DependsOn]` attribute on your module class. |
|||
* Use `Volo.Abp.PermissionManagement.Blazor.WebAssembly` NuGet package instead of `Volo.Abp.PermissionManagement.Blazor` package. Also, change `AbpPermissionManagementBlazorModule` usage to `AbpPermissionManagementBlazorWebAssemblyModule` in the `[DependsOn]` attribute on your module class. |
|||
* Use `Volo.Abp.SettingManagement.Blazor.WebAssembly` NuGet package instead of `Volo.Abp.SettingManagement.Blazor` package. Also, change `AbpSettingManagementBlazorModule` usage to `AbpSettingManagementBlazorWebAssemblyModule` in the `[DependsOn]` attribute on your module class. |
|||
* Use `Volo.Abp.FeatureManagement.Blazor.WebAssembly` NuGet package instead of `Volo.Abp.FeatureManagement.Blazor` package. Also, change `AbpFeatureManagementBlazorModule` usage to `AbpFeatureManagementBlazorWebAssemblyModule` in the `[DependsOn]` attribute on your module class. |
|||
|
|||
### Other Changes |
|||
|
|||
* `EntityAction.RequiredPermission` has been marked as obsolete, because of performance reasons. It is suggested to use the `Visible` property by checking the permission/policy yourself and assigning to a variable. |
|||
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 96 KiB |
@ -1,100 +0,0 @@ |
|||
# 多语言实体 |
|||
|
|||
ABP框架为多语言实体定义了两个基本接口用于翻译实体的标准模型. |
|||
|
|||
## IHasMultiLingual |
|||
|
|||
`IHasMultiLingual<TTranslation>` 接口用于标记多语言实体. 通过 `IHasMultiLingual<TTranslation>` 接口被标记为多语言的实体定义与语言无关的信息. 多语言实体包含翻译集合,其中包含与语言有关的信息. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class Product : Entity<Guid>, IMultiLingualEntity<ProductTranslation> |
|||
{ |
|||
public decimal Price { get; set; } |
|||
|
|||
public ICollection<ProductTranslation> Translations { get; set; } |
|||
} |
|||
``` |
|||
|
|||
## IMultiLingualTranslation |
|||
|
|||
`IMultiLingualTranslation` 接口用于标记多语言实体的翻译. 通过 `IHasMultiLingual<TTranslation>` 接口被标记为的翻译实体定义与语言有关的信息. 翻译实体包含 `Language` 字段,用于翻译的语言代码. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class ProductTranslation : Entity<Guid>, IMultiLingualTranslation |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Language { get; set; } |
|||
} |
|||
``` |
|||
|
|||
## 映射为DTO对象 |
|||
|
|||
ABP提供了[对象到对象的映射](Object-To-Object-Mapping.md)系统,你可以通过实现 `IObjectMapper<TSource, TDestination>` 接口将多语言实体映射为DTO. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class MultiLingualProductObjectMapper : IObjectMapper<Product, ProductDto>, ITransientDependency |
|||
{ |
|||
private readonly IMultiLingualObjectManager _multiLingualObjectManager; |
|||
|
|||
public MultiLingualProductObjectMapper(IMultiLingualObjectManager multiLingualObjectManager) |
|||
{ |
|||
_multiLingualObjectManager = multiLingualObjectManager; |
|||
} |
|||
|
|||
public ProductDto Map(Product source) |
|||
{ |
|||
var translation = _multiLingualObjectManager.GetTranslation<Product, ProductDto>(source); |
|||
|
|||
return new ProductDto |
|||
{ |
|||
Price = source.Price, |
|||
Id = source.Id, |
|||
Name = translation?.Name |
|||
}; |
|||
} |
|||
|
|||
public ProductDto Map(Product source, ProductDto destination) |
|||
{ |
|||
return default; |
|||
} |
|||
} |
|||
|
|||
``` |
|||
|
|||
### AutoMapper集成 |
|||
|
|||
ABP提供了 `CreateMultiLingualMap` 扩展方法用于将多语言实体映射为DTO. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class ProductProfile : Profile |
|||
{ |
|||
public ProductProfile() |
|||
{ |
|||
var mapResult = this.CreateMultiLingualMap<Product, ProductTranslation, ProductDto>(); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
`CreateMultiLingualMap` 扩展方法返回了一个类型为 `CreateMultiLingualMapResult` 的对象,它包含 `EntityMap` 和 `TranslationMap` 字段. 这些字段可以用于自定义多语言映射. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
this.CreateMultiLingualMap<Order, OrderTranslation, OrderListDto>(context) |
|||
.EntityMap.ForMember(dest => dest.ProductCount, opt => opt.MapFrom(src => src.Products.Count)); |
|||
``` |
|||
|
|||
## IMultiLingualObjectManager |
|||
|
|||
`IMultiLingualObjectManager` 接口定义了 `GetTranslation` 和 `GetTranslationAsync` 方法用于获取实体当前的翻译对象. |
|||
|
|||
`IMultiLingualObjectManager` 的默认实现首先使用当前的UI语言寻找翻译, 如果当前的UI语言没有对应的翻译, 那么会搜索默认语言设置(参阅[设置](Settings.md))用于寻找翻译. 如果默认语言没有对应的翻译, 那么它会返回已存在翻译集合中的第一个翻译对象. |
|||
@ -1,54 +0,0 @@ |
|||
using Volo.Abp.MultiLingualObject; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace AutoMapper |
|||
{ |
|||
public static class AbpAutoMapperMultiLingualDtoExtensions |
|||
{ |
|||
public static CreateMultiLingualMapResult<TSource, TTranslation, TDestination> CreateMultiLingualMap<TSource, TTranslation, TDestination>(this Profile profile) |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
where TSource : IHasMultiLingual<TTranslation> |
|||
{ |
|||
|
|||
return new( |
|||
profile.CreateMap<TSource, TDestination>().BeforeMap<AbpMultiLingualMapperAction<TSource, TTranslation, TDestination>>(), |
|||
profile.CreateMap<TTranslation, TDestination>()); |
|||
} |
|||
} |
|||
|
|||
public class AbpMultiLingualMapperAction<TSource, TTranslation, TDestination> : IMappingAction<TSource, TDestination> |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
where TSource : IHasMultiLingual<TTranslation> |
|||
{ |
|||
private readonly IMultiLingualObjectManager _multiLingualObjectManager; |
|||
|
|||
public AbpMultiLingualMapperAction(IMultiLingualObjectManager multiLingualObjectManager) |
|||
{ |
|||
_multiLingualObjectManager = multiLingualObjectManager; |
|||
} |
|||
|
|||
public void Process(TSource source, TDestination destination, ResolutionContext context) |
|||
{ |
|||
var translation = AsyncHelper.RunSync(() => _multiLingualObjectManager.GetTranslationAsync<TSource, TTranslation>(source)); |
|||
if (translation != null) |
|||
{ |
|||
context.Mapper.Map(translation, destination); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class CreateMultiLingualMapResult<TSource, TTranslation, TDestination> |
|||
{ |
|||
public IMappingExpression<TSource, TDestination> EntityMap { get; } |
|||
|
|||
public IMappingExpression<TTranslation, TDestination> TranslateMap { get; } |
|||
|
|||
public CreateMultiLingualMapResult( |
|||
IMappingExpression<TSource, TDestination> entityMap, |
|||
IMappingExpression<TTranslation, TDestination> translateMap) |
|||
{ |
|||
EntityMap = entityMap; |
|||
TranslateMap = translateMap; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using Volo.Abp.Cli.ProjectBuilding.Building.Steps; |
|||
using Volo.Abp.Cli.ProjectBuilding.Templates; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding.Building |
|||
{ |
|||
public static class NpmPackageProjectBuildPipelineBuilder |
|||
{ |
|||
public static ProjectBuildPipeline Build(ProjectBuildContext context) |
|||
{ |
|||
var pipeline = new ProjectBuildPipeline(context); |
|||
|
|||
pipeline.Steps.Add(new FileEntryListReadStep()); |
|||
pipeline.Steps.Add(new CreateProjectResultZipStep()); |
|||
|
|||
return pipeline; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Cli.ProjectModification; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding |
|||
{ |
|||
public interface INpmPackageInfoProvider |
|||
{ |
|||
Task<NpmPackageInfo> GetAsync(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Cli.Http; |
|||
using Volo.Abp.Cli.ProjectModification; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding |
|||
{ |
|||
public class NpmPackageInfoProvider : INpmPackageInfoProvider, ITransientDependency |
|||
{ |
|||
public IJsonSerializer JsonSerializer { get; } |
|||
public ICancellationTokenProvider CancellationTokenProvider { get; } |
|||
public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } |
|||
|
|||
private readonly CliHttpClientFactory _cliHttpClientFactory; |
|||
|
|||
public NpmPackageInfoProvider( |
|||
IJsonSerializer jsonSerializer, |
|||
ICancellationTokenProvider cancellationTokenProvider, |
|||
IRemoteServiceExceptionHandler remoteServiceExceptionHandler, |
|||
CliHttpClientFactory cliHttpClientFactory) |
|||
{ |
|||
JsonSerializer = jsonSerializer; |
|||
CancellationTokenProvider = cancellationTokenProvider; |
|||
RemoteServiceExceptionHandler = remoteServiceExceptionHandler; |
|||
_cliHttpClientFactory = cliHttpClientFactory; |
|||
} |
|||
|
|||
public async Task<NpmPackageInfo> GetAsync(string name) |
|||
{ |
|||
var packageList = await GetPackageListInternalAsync(); |
|||
|
|||
var package = packageList.FirstOrDefault(m => m.Name == name); |
|||
|
|||
if (package == null) |
|||
{ |
|||
throw new Exception("Package is not found or downloadable!"); |
|||
} |
|||
|
|||
return package; |
|||
} |
|||
|
|||
private async Task<List<NpmPackageInfo>> GetPackageListInternalAsync() |
|||
{ |
|||
var client = _cliHttpClientFactory.CreateClient(); |
|||
|
|||
using (var responseMessage = await client.GetAsync( |
|||
$"{CliUrls.WwwAbpIo}api/download/npmPackages/", |
|||
CancellationTokenProvider.Token |
|||
)) |
|||
{ |
|||
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); |
|||
var result = await responseMessage.Content.ReadAsStringAsync(); |
|||
return JsonSerializer.Deserialize<List<NpmPackageInfo>>(result); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Cli.Commands; |
|||
using Volo.Abp.Cli.Licensing; |
|||
using Volo.Abp.Cli.ProjectBuilding.Analyticses; |
|||
using Volo.Abp.Cli.ProjectBuilding.Building; |
|||
using Volo.Abp.Cli.ProjectModification; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Json; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding |
|||
{ |
|||
public class NpmPackageProjectBuilder : IProjectBuilder, ITransientDependency |
|||
{ |
|||
public ILogger<NpmPackageProjectBuilder> Logger { get; set; } |
|||
protected ISourceCodeStore SourceCodeStore { get; } |
|||
protected INpmPackageInfoProvider NpmPackageInfoProvider { get; } |
|||
protected ICliAnalyticsCollect CliAnalyticsCollect { get; } |
|||
protected AbpCliOptions Options { get; } |
|||
protected IJsonSerializer JsonSerializer { get; } |
|||
protected IApiKeyService ApiKeyService { get; } |
|||
|
|||
public NpmPackageProjectBuilder(ISourceCodeStore sourceCodeStore, |
|||
INpmPackageInfoProvider npmPackageInfoProvider, |
|||
ICliAnalyticsCollect cliAnalyticsCollect, |
|||
IOptions<AbpCliOptions> options, |
|||
IJsonSerializer jsonSerializer, |
|||
IApiKeyService apiKeyService) |
|||
{ |
|||
SourceCodeStore = sourceCodeStore; |
|||
NpmPackageInfoProvider = npmPackageInfoProvider; |
|||
CliAnalyticsCollect = cliAnalyticsCollect; |
|||
Options = options.Value; |
|||
JsonSerializer = jsonSerializer; |
|||
ApiKeyService = apiKeyService; |
|||
|
|||
Logger = NullLogger<NpmPackageProjectBuilder>.Instance; |
|||
} |
|||
|
|||
public async Task<ProjectBuildResult> BuildAsync(ProjectBuildArgs args) |
|||
{ |
|||
var packageInfo = await GetPackageInfoAsync(args); |
|||
|
|||
var templateFile = await SourceCodeStore.GetAsync( |
|||
args.TemplateName, |
|||
SourceCodeTypes.NpmPackage, |
|||
args.Version, |
|||
null, |
|||
args.ExtraProperties.ContainsKey(GetSourceCommand.Options.Preview.Long) |
|||
); |
|||
|
|||
var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync(); |
|||
if (apiKeyResult?.ApiKey != null) |
|||
{ |
|||
args.ExtraProperties["api-key"] = apiKeyResult.ApiKey; |
|||
} |
|||
|
|||
if (apiKeyResult?.LicenseCode != null) |
|||
{ |
|||
args.ExtraProperties["license-code"] = apiKeyResult.LicenseCode; |
|||
} |
|||
|
|||
var context = new ProjectBuildContext( |
|||
null, |
|||
null, |
|||
null, |
|||
packageInfo, |
|||
templateFile, |
|||
args |
|||
); |
|||
|
|||
NpmPackageProjectBuildPipelineBuilder.Build(context).Execute(); |
|||
|
|||
// Exclude unwanted or known options.
|
|||
var options = args.ExtraProperties |
|||
.Where(x => !x.Key.Equals(CliConsts.Command, StringComparison.InvariantCultureIgnoreCase)) |
|||
.Where(x => !x.Key.Equals(NewCommand.Options.OutputFolder.Long, StringComparison.InvariantCultureIgnoreCase) && |
|||
!x.Key.Equals(NewCommand.Options.OutputFolder.Short, StringComparison.InvariantCultureIgnoreCase)) |
|||
.Where(x => !x.Key.Equals(NewCommand.Options.Version.Long, StringComparison.InvariantCultureIgnoreCase) && |
|||
!x.Key.Equals(NewCommand.Options.Version.Short, StringComparison.InvariantCultureIgnoreCase)) |
|||
.Where(x => !x.Key.Equals(NewCommand.Options.TemplateSource.Short, StringComparison.InvariantCultureIgnoreCase) && |
|||
!x.Key.Equals(NewCommand.Options.TemplateSource.Long, StringComparison.InvariantCultureIgnoreCase)) |
|||
.Select(x => x.Key).ToList(); |
|||
|
|||
await CliAnalyticsCollect.CollectAsync(new CliAnalyticsCollectInputDto |
|||
{ |
|||
Tool = Options.ToolName, |
|||
Command = args.ExtraProperties.ContainsKey(CliConsts.Command) ? args.ExtraProperties[CliConsts.Command] : "", |
|||
DatabaseProvider = null, |
|||
IsTiered = null, |
|||
UiFramework = null, |
|||
Options = JsonSerializer.Serialize(options), |
|||
ProjectName = null, |
|||
TemplateName = args.TemplateName, |
|||
TemplateVersion = templateFile.Version |
|||
}); |
|||
|
|||
return new ProjectBuildResult(context.Result.ZipContent, args.TemplateName); |
|||
} |
|||
|
|||
private async Task<NpmPackageInfo> GetPackageInfoAsync(ProjectBuildArgs args) |
|||
{ |
|||
return await NpmPackageInfoProvider.GetAsync(args.TemplateName); |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
{ |
|||
ICollection<TTranslation> Translations { get; set; } |
|||
} |
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IMultiLingualObjectManager |
|||
{ |
|||
TTranslation GetTranslation<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
bool fallbackToParentCultures = true, |
|||
string culture = null) |
|||
where TMultiLingual : IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation; |
|||
|
|||
Task<TTranslation> GetTranslationAsync<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
bool fallbackToParentCultures = true, |
|||
string culture = null) |
|||
where TMultiLingual : IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation; |
|||
} |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IMultiLingualTranslation |
|||
{ |
|||
string Language { get; set; } |
|||
} |
|||
} |
|||
@ -1,11 +1,11 @@ |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpMultiLingualObjectModule : AbpModule |
|||
public class AbpMultiLingualObjectsModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IMultiLingualObject<TTranslation> |
|||
where TTranslation : class, IObjectTranslation |
|||
{ |
|||
ICollection<TTranslation> Translations { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IMultiLingualObjectManager |
|||
{ |
|||
Task<TTranslation> GetTranslationAsync<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
string culture = null, |
|||
bool fallbackToParentCultures = true) |
|||
where TMultiLingual : IMultiLingualObject<TTranslation> |
|||
where TTranslation : class, IObjectTranslation; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IObjectTranslation |
|||
{ |
|||
string Language { get; set; } |
|||
} |
|||
} |
|||