mirror of https://github.com/abpframework/abp.git
46 changed files with 702 additions and 198 deletions
@ -0,0 +1,13 @@ |
|||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Building |
||||
|
{ |
||||
|
public enum DatabaseManagementSystem |
||||
|
{ |
||||
|
NotSpecified, |
||||
|
SQLServer, |
||||
|
MySQL, |
||||
|
PostgreSQL, |
||||
|
Oracle, |
||||
|
OracleDevart, |
||||
|
SQLite |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp.Cli.ProjectBuilding.Files; |
||||
|
|
||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps |
||||
|
{ |
||||
|
public class DatabaseManagementSystemChangeStep : ProjectBuildPipelineStep |
||||
|
{ |
||||
|
public override void Execute(ProjectBuildContext context) |
||||
|
{ |
||||
|
switch (context.BuildArgs.DatabaseManagementSystem) |
||||
|
{ |
||||
|
case DatabaseManagementSystem.MySQL: |
||||
|
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.MySQL", |
||||
|
"Volo.Abp.EntityFrameworkCore.MySQL", |
||||
|
"AbpEntityFrameworkCoreMySQLModule"); |
||||
|
AddMySqlServerVersion(context); |
||||
|
ChangeUseSqlServer(context,"UseMySQL", "UseMySql"); |
||||
|
break; |
||||
|
|
||||
|
case DatabaseManagementSystem.PostgreSQL: |
||||
|
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.PostgreSql", |
||||
|
"Volo.Abp.EntityFrameworkCore.PostgreSql", |
||||
|
"AbpEntityFrameworkCorePostgreSqlModule"); |
||||
|
ChangeUseSqlServer(context,"UseNpgsql"); |
||||
|
break; |
||||
|
|
||||
|
case DatabaseManagementSystem.Oracle: |
||||
|
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle", |
||||
|
"Volo.Abp.EntityFrameworkCore.Oracle", |
||||
|
"AbpEntityFrameworkCoreOracleModule"); |
||||
|
ChangeUseSqlServer(context,"UseOracle"); |
||||
|
break; |
||||
|
|
||||
|
case DatabaseManagementSystem.OracleDevart: |
||||
|
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle.Devart", |
||||
|
"Volo.Abp.EntityFrameworkCore.Oracle.Devart", |
||||
|
"AbpEntityFrameworkCoreOracleDevartModule"); |
||||
|
AdjustOracleDbContextOptionsBuilder(context); |
||||
|
ChangeUseSqlServer(context,"UseOracle"); |
||||
|
break; |
||||
|
|
||||
|
case DatabaseManagementSystem.SQLite: |
||||
|
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Sqlite", |
||||
|
"Volo.Abp.EntityFrameworkCore.Sqlite", |
||||
|
"AbpEntityFrameworkCoreSqliteModule"); |
||||
|
ChangeUseSqlServer(context,"UseSqlite"); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void AdjustOracleDbContextOptionsBuilder(ProjectBuildContext context) |
||||
|
{ |
||||
|
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); |
||||
|
|
||||
|
dbContextFactoryFile.ReplaceText("new DbContextOptionsBuilder", |
||||
|
$"(DbContextOptionsBuilder<{context.BuildArgs.SolutionName.ProjectName}MigrationsDbContext>) new DbContextOptionsBuilder"); |
||||
|
} |
||||
|
|
||||
|
private void AddMySqlServerVersion(ProjectBuildContext context) |
||||
|
{ |
||||
|
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); |
||||
|
|
||||
|
dbContextFactoryFile.ReplaceText("configuration.GetConnectionString(\"Default\")", |
||||
|
"configuration.GetConnectionString(\"Default\"), MySqlServerVersion.LatestSupportedServerVersion"); |
||||
|
} |
||||
|
|
||||
|
private void ChangeEntityFrameworkCoreDependency(ProjectBuildContext context, string newPackageName, string newModuleNamespace, string newModuleClass) |
||||
|
{ |
||||
|
var efCoreProjectFile = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase)); |
||||
|
efCoreProjectFile.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName); |
||||
|
|
||||
|
var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); |
||||
|
efCoreModuleClass.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace); |
||||
|
efCoreModuleClass.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass); |
||||
|
} |
||||
|
|
||||
|
private void ChangeUseSqlServer(ProjectBuildContext context, string newUseMethodForEfModule, string newUseMethodForDbContext = null) |
||||
|
{ |
||||
|
if (newUseMethodForDbContext == null) |
||||
|
{ |
||||
|
newUseMethodForDbContext = newUseMethodForEfModule; |
||||
|
} |
||||
|
|
||||
|
var oldUseMethod = "UseSqlServer"; |
||||
|
|
||||
|
var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); |
||||
|
efCoreModuleClass.ReplaceText(oldUseMethod, newUseMethodForEfModule); |
||||
|
|
||||
|
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); |
||||
|
dbContextFactoryFile.ReplaceText(oldUseMethod, newUseMethodForDbContext); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Volo.Abp.Cli.ProjectBuilding.Building; |
||||
|
|
||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Templates |
||||
|
{ |
||||
|
public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep |
||||
|
{ |
||||
|
public override void Execute(ProjectBuildContext context) |
||||
|
{ |
||||
|
var httpApiHostAppSettings = context.Files.FirstOrDefault(f => f.Name.EndsWith(".HttpApi.Host/appsettings.json")); |
||||
|
|
||||
|
if (httpApiHostAppSettings == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var portsToRemoveFromCors = new List<string>(); |
||||
|
|
||||
|
var appSettingsJson = JObject.Parse(httpApiHostAppSettings.Content); |
||||
|
var appJson = (JObject) appSettingsJson["App"]; |
||||
|
|
||||
|
if (context.BuildArgs.UiFramework != UiFramework.Angular) |
||||
|
{ |
||||
|
appJson.Property("ClientUrl")?.Remove(); |
||||
|
portsToRemoveFromCors.Add("4200"); |
||||
|
} |
||||
|
if (context.BuildArgs.UiFramework != UiFramework.Blazor) |
||||
|
{ |
||||
|
portsToRemoveFromCors.Add("44307"); |
||||
|
} |
||||
|
|
||||
|
if (appJson["CorsOrigins"] != null) |
||||
|
{ |
||||
|
appJson["CorsOrigins"] = string.Join(",", |
||||
|
appJson["CorsOrigins"].ToString().Split(",").Where(u=> !portsToRemoveFromCors.Any(u.EndsWith)) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
httpApiHostAppSettings.SetContent(JsonConvert.SerializeObject(appSettingsJson, Formatting.Indented)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Volo.Abp.Cli.Utils; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Cli.ProjectModification |
||||
|
{ |
||||
|
public class EfCoreMigrationRecreater : ITransientDependency |
||||
|
{ |
||||
|
public ILogger<EfCoreMigrationRecreater> Logger { get; set; } |
||||
|
|
||||
|
public EfCoreMigrationRecreater() |
||||
|
{ |
||||
|
Logger = NullLogger<EfCoreMigrationRecreater>.Instance; |
||||
|
} |
||||
|
|
||||
|
public void Recreate(string solutionFolder) |
||||
|
{ |
||||
|
if (Directory.Exists(Path.Combine(solutionFolder, "aspnet-core"))) |
||||
|
{ |
||||
|
solutionFolder = Path.Combine(solutionFolder, "aspnet-core"); |
||||
|
} |
||||
|
|
||||
|
var srcFolder = Path.Combine(solutionFolder, "src"); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
var migrationsFolder = Directory.GetDirectories(srcFolder).First(d => d.EndsWith(".EntityFrameworkCore.DbMigrations")); |
||||
|
Directory.Delete(Path.Combine(migrationsFolder, "Migrations"), true); |
||||
|
|
||||
|
var migratorFolder = Directory.GetDirectories(srcFolder).First(d => d.EndsWith(".DbMigrator")); |
||||
|
var migratorProjectFile = Directory.GetFiles(migratorFolder).First(d => d.EndsWith(".DbMigrator.csproj")); |
||||
|
var addMigrationCommand = $"dotnet ef migrations add Initial --startup-project {migratorProjectFile}"; |
||||
|
CmdHelper.RunCmd($"cd {migrationsFolder} && {addMigrationCommand}"); |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
Logger.LogWarning("Re-creating migrations process failed."); |
||||
|
throw e; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { HttpRequest } from '@angular/common/http'; |
||||
|
import { InternalStore } from '../utils/internal-store-utils'; |
||||
|
|
||||
|
export interface HttpWaitState { |
||||
|
requests: Set<HttpRequest<any>>; |
||||
|
} |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class HttpWaitService { |
||||
|
protected store = new InternalStore<HttpWaitState>({ requests: new Set() }); |
||||
|
|
||||
|
getLoading() { |
||||
|
return !!this.store.state.requests.size; |
||||
|
} |
||||
|
|
||||
|
getLoading$() { |
||||
|
return this.store.sliceState(({ requests }) => !!requests.size); |
||||
|
} |
||||
|
|
||||
|
updateLoading$() { |
||||
|
return this.store.sliceUpdate(({ requests }) => !!requests.size); |
||||
|
} |
||||
|
|
||||
|
clearLoading() { |
||||
|
this.store.patch({ requests: new Set() }); |
||||
|
} |
||||
|
|
||||
|
addRequest(request: HttpRequest<any>) { |
||||
|
const requests = this.store.state.requests; |
||||
|
requests.add(request); |
||||
|
this.store.patch({ requests }); |
||||
|
} |
||||
|
|
||||
|
deleteRequest(request: HttpRequest<any>) { |
||||
|
const requests = this.store.state.requests; |
||||
|
requests.delete(request); |
||||
|
this.store.patch({ requests }); |
||||
|
} |
||||
|
|
||||
|
// TODO: Add filter function
|
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { InternalStore } from '../utils/internal-store-utils'; |
||||
|
|
||||
|
export interface ResourceWaitState { |
||||
|
resources: Set<string>; |
||||
|
} |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class ResourceWaitService { |
||||
|
private store = new InternalStore<ResourceWaitState>({ resources: new Set() }); |
||||
|
|
||||
|
getLoading() { |
||||
|
return !!this.store.state.resources.size; |
||||
|
} |
||||
|
|
||||
|
getLoading$() { |
||||
|
return this.store.sliceState(({ resources }) => !!resources.size); |
||||
|
} |
||||
|
|
||||
|
updateLoading$() { |
||||
|
return this.store.sliceUpdate(({ resources }) => !!resources.size); |
||||
|
} |
||||
|
|
||||
|
clearLoading() { |
||||
|
this.store.patch({ resources: new Set() }); |
||||
|
} |
||||
|
|
||||
|
addResource(resource: string) { |
||||
|
const resources = this.store.state.resources; |
||||
|
resources.add(resource); |
||||
|
this.store.patch({ resources }); |
||||
|
} |
||||
|
|
||||
|
deleteResource(resource: string) { |
||||
|
const resources = this.store.state.resources; |
||||
|
resources.delete(resource); |
||||
|
this.store.patch({ resources }); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { |
||||
|
NavigationCancel, |
||||
|
NavigationEnd, |
||||
|
NavigationError, |
||||
|
NavigationStart, |
||||
|
Router, |
||||
|
} from '@angular/router'; |
||||
|
import { filter } from 'rxjs/operators'; |
||||
|
import { InternalStore } from '../utils/internal-store-utils'; |
||||
|
|
||||
|
export interface RouterWaitState { |
||||
|
loading: boolean; |
||||
|
} |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class RouterWaitService { |
||||
|
private store = new InternalStore<RouterWaitState>({ loading: false }); |
||||
|
constructor(private router: Router) { |
||||
|
this.router.events |
||||
|
.pipe( |
||||
|
filter( |
||||
|
event => |
||||
|
event instanceof NavigationStart || |
||||
|
event instanceof NavigationEnd || |
||||
|
event instanceof NavigationError || |
||||
|
event instanceof NavigationCancel, |
||||
|
), |
||||
|
) |
||||
|
.subscribe(event => { |
||||
|
if (event instanceof NavigationStart) this.setLoading(true); |
||||
|
else this.setLoading(false); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
getLoading() { |
||||
|
return this.store.state.loading; |
||||
|
} |
||||
|
|
||||
|
getLoading$() { |
||||
|
return this.store.sliceState(({ loading }) => loading); |
||||
|
} |
||||
|
|
||||
|
updateLoading$() { |
||||
|
return this.store.sliceUpdate(({ loading }) => loading); |
||||
|
} |
||||
|
|
||||
|
setLoading(loading: boolean) { |
||||
|
this.store.patch({ loading }); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './mock-rest.service'; |
||||
@ -0,0 +1,21 @@ |
|||||
|
import { ABP, CORE_OPTIONS, EnvironmentService, RestService } from '@abp/ng.core'; |
||||
|
import { HttpClient } from '@angular/common/http'; |
||||
|
import { Inject, Injectable } from '@angular/core'; |
||||
|
import { Observable, throwError } from 'rxjs'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class MockRestService extends RestService { |
||||
|
constructor( |
||||
|
@Inject(CORE_OPTIONS) protected options: ABP.Root, |
||||
|
protected http: HttpClient, |
||||
|
protected environment: EnvironmentService, |
||||
|
) { |
||||
|
super(options, http, environment, null); |
||||
|
} |
||||
|
|
||||
|
handleError(err: any): Observable<any> { |
||||
|
return throwError(err); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/theme-shared/testing", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
import { |
||||
|
BaseThemeSharedModule, |
||||
|
DateParserFormatter, |
||||
|
THEME_SHARED_ROUTE_PROVIDERS, |
||||
|
} from '@abp/ng.theme.shared'; |
||||
|
import { ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
import { RouterTestingModule } from '@angular/router/testing'; |
||||
|
import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap'; |
||||
|
|
||||
|
/** |
||||
|
* ThemeSharedTestingModule is the module that will be used in tests |
||||
|
*/ |
||||
|
@NgModule({ |
||||
|
exports: [RouterTestingModule, BaseThemeSharedModule], |
||||
|
imports: [RouterTestingModule, BaseThemeSharedModule], |
||||
|
}) |
||||
|
export class ThemeSharedTestingModule { |
||||
|
static withConfig(): ModuleWithProviders<ThemeSharedTestingModule> { |
||||
|
return { |
||||
|
ngModule: ThemeSharedTestingModule, |
||||
|
providers: [ |
||||
|
THEME_SHARED_ROUTE_PROVIDERS, |
||||
|
{ provide: NgbDateParserFormatter, useClass: DateParserFormatter }, |
||||
|
], |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './lib/theme-shared-testing.module'; |
||||
Loading…
Reference in new issue