From 4eadee29c64e9e2b730444378ee9ee5dbeb220aa Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 23 Oct 2019 17:21:24 +0800 Subject: [PATCH 01/75] Added DataTimeValueConverters function. Resolve #1983 --- .../Abp/EntityFrameworkCore/AbpDbContext.cs | 43 +++++++++++++++ .../AbpDateTimeValueConverter.cs | 17 ++++++ .../AbpDateTimeValueConverter_Tests.cs | 9 ++++ .../Volo/Abp/TestApp/Domain/Person.cs | 6 +++ .../AbpDateTimeValueConverter_Tests.cs | 53 +++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs create mode 100644 framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs create mode 100644 framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 3d4b45d75d..9064ddc2ba 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -18,10 +18,12 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EntityFrameworkCore.EntityHistory; +using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.Reflection; using Volo.Abp.Threading; +using Volo.Abp.Timing; namespace Volo.Abp.EntityFrameworkCore { @@ -48,6 +50,8 @@ namespace Volo.Abp.EntityFrameworkCore public IAuditingManager AuditingManager { get; set; } + public IClock Clock { get; set; } + public ILogger> Logger { get; set; } private static readonly MethodInfo ConfigureBasePropertiesMethodInfo @@ -57,6 +61,13 @@ namespace Volo.Abp.EntityFrameworkCore BindingFlags.Instance | BindingFlags.NonPublic ); + private static readonly MethodInfo ConfigureValueConverterMethodInfo + = typeof(AbpDbContext) + .GetMethod( + nameof(ConfigureValueConverter), + BindingFlags.Instance | BindingFlags.NonPublic + ); + protected AbpDbContext(DbContextOptions options) : base(options) { @@ -75,6 +86,10 @@ namespace Volo.Abp.EntityFrameworkCore ConfigureBasePropertiesMethodInfo .MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); + + ConfigureValueConverterMethodInfo + .MakeGenericMethod(entityType.ClrType) + .Invoke(this, new object[] { modelBuilder, entityType }); } } @@ -488,6 +503,34 @@ namespace Volo.Abp.EntityFrameworkCore } } + protected virtual void ConfigureValueConverter(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + where TEntity : class + { + if (mutableEntityType.BaseType == null && + !typeof(TEntity).IsDefined(typeof(DisableDateTimeNormalizationAttribute), true) && + !typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) && + !mutableEntityType.IsOwned()) + { + var dateTimeValueConverter = new AbpDateTimeValueConverter(Clock); + + var dateTimePropertyInfos = typeof(TEntity).GetProperties() + .Where(property => + (property.PropertyType == typeof(DateTime) || + property.PropertyType == typeof(DateTime?)) && + property.CanWrite && + !property.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true) + ).ToList(); + + dateTimePropertyInfos.ForEach(property => + { + modelBuilder + .Entity() + .Property(property.Name) + .HasConversion(dateTimeValueConverter); + }); + } + } + protected virtual bool ShouldFilterEntity(IMutableEntityType entityType) where TEntity : class { if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity))) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs new file mode 100644 index 0000000000..e3562c4134 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter.cs @@ -0,0 +1,17 @@ +using System; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.Timing; + +namespace Volo.Abp.EntityFrameworkCore.ValueConverters +{ + public class AbpDateTimeValueConverter : ValueConverter + { + public AbpDateTimeValueConverter(IClock clock, [CanBeNull] ConverterMappingHints mappingHints = null) + : base( + x => x.HasValue ? clock.Normalize(x.Value) : x, + x => x.HasValue ? clock.Normalize(x.Value) : x, mappingHints) + { + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs new file mode 100644 index 0000000000..c2793b3b67 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs @@ -0,0 +1,9 @@ +using Volo.Abp.TestApp.Testing; + +namespace Volo.Abp.EntityFrameworkCore.ValueConverters +{ + public class AbpDateTimeValueConverter_Tests : AbpDateTimeValueConverter_Tests + { + + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs index 3bbec118a2..9075740f11 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/Person.cs @@ -2,6 +2,7 @@ using System; using System.Collections.ObjectModel; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; namespace Volo.Abp.TestApp.Domain { @@ -15,6 +16,11 @@ namespace Volo.Abp.TestApp.Domain public virtual int Age { get; set; } + public virtual DateTime? Birthday { get; set; } + + [DisableDateTimeNormalization] + public virtual DateTime? LastActive { get; set; } + public virtual Collection Phones { get; set; } private Person() diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs new file mode 100644 index 0000000000..cbeef807cb --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Modularity; +using Volo.Abp.TestApp.Domain; +using Volo.Abp.Timing; +using Xunit; + +namespace Volo.Abp.TestApp.Testing +{ + public abstract class AbpDateTimeValueConverter_Tests : TestAppTestBase + where TStartupModule : IAbpModule + { + private readonly IBasicRepository _personRepository; + + protected AbpDateTimeValueConverter_Tests() + { + _personRepository = GetRequiredService>(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => options.Kind = DateTimeKind.Utc); + } + + [Fact] + public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test() + { + var personId = Guid.Parse("4125582e-d100-4c27-aa84-e4de85830dca"); + await _personRepository.InsertAsync(new Person(personId, "bob lee", 18) + { + Birthday = DateTime.Parse("2020-01-01 00:00:00"), + LastActive = DateTime.Parse("2020-01-01 00:00:00"), + }, true); + + var person = await _personRepository.GetAsync(personId); + + person.ShouldNotBeNull(); + person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); + + person.Birthday.ShouldNotBeNull(); + person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); + person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); + + //LastActive DisableDateTimeNormalization + person.LastActive.ShouldNotBeNull(); + person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); + person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); + } + } +} \ No newline at end of file From a898b4abe8135812aea6069c2f32fb33baf182c3 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 23 Oct 2019 18:09:49 +0800 Subject: [PATCH 02/75] Handling Clock in AbpDbContext may be null. --- .../Volo/Abp/EntityFrameworkCore/AbpDbContext.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 9064ddc2ba..aa91755f5d 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; @@ -511,6 +511,11 @@ namespace Volo.Abp.EntityFrameworkCore !typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) && !mutableEntityType.IsOwned()) { + if (Clock == null) + { + return; + } + var dateTimeValueConverter = new AbpDateTimeValueConverter(Clock); var dateTimePropertyInfos = typeof(TEntity).GetProperties() From 91ba0f2594c83d00e2a8c35aea82579ed862f570 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 23 Oct 2019 20:50:26 +0800 Subject: [PATCH 03/75] Configuring AbpClockOptions in AbpEntityFrameworkCoreTestModule. --- .../Volo/Abp/EntityFrameworkCore/AbpDbContext.cs | 2 +- .../EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs | 6 +++++- .../Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs | 5 ----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index aa91755f5d..b42a2cfc66 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -511,7 +511,7 @@ namespace Volo.Abp.EntityFrameworkCore !typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) && !mutableEntityType.IsOwned()) { - if (Clock == null) + if (Clock == null || !Clock.SupportsMultipleTimezone) { return; } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs index b1b92ab5b2..85eb1119d5 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Data.Sqlite; +using System; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; @@ -10,6 +11,7 @@ using Volo.Abp.Modularity; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.EntityFrameworkCore; +using Volo.Abp.Timing; namespace Volo.Abp.EntityFrameworkCore { @@ -41,6 +43,8 @@ namespace Volo.Abp.EntityFrameworkCore abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection); }); }); + + Configure(options => options.Kind = DateTimeKind.Utc); } public override void OnPreApplicationInitialization(ApplicationInitializationContext context) diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs index cbeef807cb..6b0caaa7b6 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs @@ -20,11 +20,6 @@ namespace Volo.Abp.TestApp.Testing _personRepository = GetRequiredService>(); } - protected override void AfterAddApplication(IServiceCollection services) - { - services.Configure(options => options.Kind = DateTimeKind.Utc); - } - [Fact] public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test() { From 7d39a35a1bd1495ad7fb5658c61505dee2821938 Mon Sep 17 00:00:00 2001 From: Super Date: Thu, 7 Nov 2019 18:31:42 +0800 Subject: [PATCH 04/75] Add missing DataTables options for tenant-management module. --- .../Pages/TenantManagement/Tenants/Index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js index 18d0cceafc..581a71b774 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js @@ -17,6 +17,9 @@ var _dataTable = _$wrapper.find('table').DataTable(abp.libs.datatables.normalizeConfiguration({ order: [[1, "asc"]], + processing: true, + paging: true, + serverSide: true, ajax: abp.libs.datatables.createAjax(_tenantAppService.getList), columnDefs: [ { From 1569ebcd1a5d5fcbbfb82d4ebf364cac30c3299d Mon Sep 17 00:00:00 2001 From: bartvanhoey Date: Sat, 9 Nov 2019 08:41:31 +0100 Subject: [PATCH 05/75] datepicker-requirements-right-below-date-picker-implementation --- docs/en/Tutorials/Angular/Part-II.md | 40 +++++++++++++++------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/en/Tutorials/Angular/Part-II.md b/docs/en/Tutorials/Angular/Part-II.md index ed6afcb947..07ae82e778 100644 --- a/docs/en/Tutorials/Angular/Part-II.md +++ b/docs/en/Tutorials/Angular/Part-II.md @@ -218,25 +218,6 @@ Open `book-list.component.html` and add the form in the body template of the mod > We've used [NgBootstrap datepicker](https://ng-bootstrap.github.io/#/components/datepicker/overview) in this component. -Open the `book-list.component.ts` and then create an array, named `bookTypeArr`: - -```js -//... -form: FormGroup; - -bookTypeArr = Object.keys(Books.BookType).filter( - bookType => typeof this.booksType[bookType] === 'number' -); -``` - -The `bookTypeArr` contains the fields of the `BookType` enum. Resulting array is shown below: - -```js -['Adventure', 'Biography', 'Dystopia', 'Fantastic' ...] -``` - -This array was used in the previous form template (in the `ngFor` loop). - #### Datepicker Requirements You need to import `NgbDatepickerModule` to the `books.module.ts`: @@ -268,6 +249,27 @@ export class BookListComponent implements OnInit { > The `NgbDateAdapter` converts Datepicker value to `Date` type. See the [datepicker adapters](https://ng-bootstrap.github.io/#/components/datepicker/overview) for more details. + +Open the `book-list.component.ts` and then create an array, named `bookTypeArr`: + +```js +//... +form: FormGroup; + +bookTypeArr = Object.keys(Books.BookType).filter( + bookType => typeof this.booksType[bookType] === 'number' +); +``` + +The `bookTypeArr` contains the fields of the `BookType` enum. Resulting array is shown below: + +```js +['Adventure', 'Biography', 'Dystopia', 'Fantastic' ...] +``` + +This array was used in the previous form template (in the `ngFor` loop). + + ![new-book-form](images/bookstore-new-book-form.png) #### Saving the Book From b4940f135cf6cb122b12267f0a693b11807865d0 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 10 Nov 2019 14:28:06 +0800 Subject: [PATCH 06/75] Added Keyless Entity Types unit test. https://docs.microsoft.com/en-us/ef/core/modeling/keyless-entity-types --- .../AbpEntityFrameworkCoreTestModule.cs | 3 ++ .../EntityFrameworkCore/PersonRepository.cs | 24 +++++++++++++++ .../EntityFrameworkCore/TestAppDbContext.cs | 9 ++++++ .../Abp/TestApp/Domain/IPersonRepository.cs | 13 +++++++++ .../Volo/Abp/TestApp/Domain/PersonView.cs | 19 ++++++++++++ .../AbpDateTimeValueConverter_Tests.cs | 29 +++++++++++++++++-- 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs create mode 100644 framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs create mode 100644 framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs index 85eb1119d5..8925c2bff3 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs @@ -60,6 +60,9 @@ namespace Volo.Abp.EntityFrameworkCore using (var context = new TestMigrationsDbContext(new DbContextOptionsBuilder().UseSqlite(connection).Options)) { context.GetService().CreateTables(); + context.Database.ExecuteSqlRaw( + @"CREATE VIEW View_PersonView AS + SELECT Id, Name, CreationTime, Birthday, LastActive FROM People"); } return connection; diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs new file mode 100644 index 0000000000..e42d88c2b8 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.TestApp.Domain; + +namespace Volo.Abp.TestApp.EntityFrameworkCore +{ + public class PersonRepository : EfCoreRepository, IPersonRepository + { + public PersonRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task GetViewAsync(Guid id) + { + return await DbContext.PersonView.Where(x => x.Id == id).FirstOrDefaultAsync(); + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs index bfcecdeb65..5e243b9a03 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs @@ -11,6 +11,8 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public DbSet Cities { get; set; } + public DbSet PersonView { get; set; } + public DbSet DummyEntities { get; set; } public DbSet EntityWithIntPks { get; set; } @@ -29,6 +31,13 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore { b.HasKey(p => new {p.PersonId, p.Number}); }); + + modelBuilder + .Entity(p => + { + p.HasNoKey(); + p.ToView("View_PersonView"); + }); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs new file mode 100644 index 0000000000..ac094de826 --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.TestApp.Domain +{ + public interface IPersonRepository : IBasicRepository + { + Task GetViewAsync(Guid id); + } +} diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs new file mode 100644 index 0000000000..72249fa541 --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs @@ -0,0 +1,19 @@ +using System; +using Volo.Abp.Timing; + +namespace Volo.Abp.TestApp.Domain +{ + public class PersonView + { + public Guid Id { get; set; } + + public string Name { get; set; } + + public DateTime CreationTime { get; set; } + + public DateTime? Birthday { get; set; } + + [DisableDateTimeNormalization] + public DateTime? LastActive { get; set; } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs index 6b0caaa7b6..bf95982daa 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs @@ -13,11 +13,11 @@ namespace Volo.Abp.TestApp.Testing public abstract class AbpDateTimeValueConverter_Tests : TestAppTestBase where TStartupModule : IAbpModule { - private readonly IBasicRepository _personRepository; + private readonly IPersonRepository _personRepository; protected AbpDateTimeValueConverter_Tests() { - _personRepository = GetRequiredService>(); + _personRepository = GetRequiredService(); } [Fact] @@ -44,5 +44,30 @@ namespace Volo.Abp.TestApp.Testing person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); } + + [Fact] + public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test() + { + var personId = Guid.Parse("7a942bca-c911-4473-93aa-2daf88e18fb9"); + await _personRepository.InsertAsync(new Person(personId, "bob lee", 18) + { + Birthday = DateTime.Parse("2020-01-01 00:00:00"), + LastActive = DateTime.Parse("2020-01-01 00:00:00"), + }, true); + + var person = await _personRepository.GetViewAsync(personId); + + person.ShouldNotBeNull(); + person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); + + person.Birthday.ShouldNotBeNull(); + person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); + person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); + + //LastActive DisableDateTimeNormalization + person.LastActive.ShouldNotBeNull(); + person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); + person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); + } } } \ No newline at end of file From 6944da4a8200b6f6b26a7601f9569d2a28eba677 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 10 Nov 2019 14:38:52 +0800 Subject: [PATCH 07/75] Remove the id property from the view. --- .../EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs | 2 +- .../Abp/TestApp/EntityFrameworkCore/PersonRepository.cs | 4 ++-- .../Volo/Abp/TestApp/Domain/IPersonRepository.cs | 2 +- .../Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs | 2 -- .../Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs | 6 +++--- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs index 8925c2bff3..71522d0216 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs @@ -62,7 +62,7 @@ namespace Volo.Abp.EntityFrameworkCore context.GetService().CreateTables(); context.Database.ExecuteSqlRaw( @"CREATE VIEW View_PersonView AS - SELECT Id, Name, CreationTime, Birthday, LastActive FROM People"); + SELECT Name, CreationTime, Birthday, LastActive FROM People"); } return connection; diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs index e42d88c2b8..ab8c1920a7 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/PersonRepository.cs @@ -16,9 +16,9 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore { } - public async Task GetViewAsync(Guid id) + public async Task GetViewAsync(string name) { - return await DbContext.PersonView.Where(x => x.Id == id).FirstOrDefaultAsync(); + return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync(); } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs index ac094de826..9058522346 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/IPersonRepository.cs @@ -8,6 +8,6 @@ namespace Volo.Abp.TestApp.Domain { public interface IPersonRepository : IBasicRepository { - Task GetViewAsync(Guid id); + Task GetViewAsync(string name); } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs index 72249fa541..e77827c263 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/PersonView.cs @@ -5,8 +5,6 @@ namespace Volo.Abp.TestApp.Domain { public class PersonView { - public Guid Id { get; set; } - public string Name { get; set; } public DateTime CreationTime { get; set; } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs index bf95982daa..e36225e53c 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs @@ -48,14 +48,14 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test() { - var personId = Guid.Parse("7a942bca-c911-4473-93aa-2daf88e18fb9"); - await _personRepository.InsertAsync(new Person(personId, "bob lee", 18) + var personName = "bob lee"; + await _personRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18) { Birthday = DateTime.Parse("2020-01-01 00:00:00"), LastActive = DateTime.Parse("2020-01-01 00:00:00"), }, true); - var person = await _personRepository.GetViewAsync(personId); + var person = await _personRepository.GetViewAsync(personName); person.ShouldNotBeNull(); person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); From 357be9a8e348796c55753bb1fad68fdd1d0acd23 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 12 Nov 2019 17:51:54 +0800 Subject: [PATCH 08/75] Implement AbpDateTimeModelBinderProvider & AbpDateTimeModelBinder Resolve #2143 --- .../AspNetCore/Mvc/AbpMvcOptionsExtensions.cs | 3 +- .../ModelBinding/AbpDateTimeModelBinder.cs | 49 +++++++++ .../AbpDateTimeModelBinderProvider.cs | 47 ++++++++ .../ModelBinding/ModelBindingController.cs | 61 +++++++++++ .../ModelBindingController_Tests.cs | 100 ++++++++++++++++++ 5 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinderProvider.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs index 59c7de8840..a633edb37e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs @@ -4,6 +4,7 @@ using Volo.Abp.AspNetCore.Mvc.Auditing; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.Features; +using Volo.Abp.AspNetCore.Mvc.ModelBinding; using Volo.Abp.AspNetCore.Mvc.Uow; using Volo.Abp.AspNetCore.Mvc.Validation; @@ -35,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc private static void AddModelBinders(MvcOptions options) { - //options.ModelBinderProviders.Add(new AbpDateTimeModelBinderProvider()); + options.ModelBinderProviders.Insert(0, new AbpDateTimeModelBinderProvider()); } private static void AddMetadataProviders(MvcOptions options, IServiceCollection services) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs new file mode 100644 index 0000000000..1916b9aa16 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinder.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Volo.Abp.Timing; + +namespace Volo.Abp.AspNetCore.Mvc.ModelBinding +{ + public class AbpDateTimeModelBinder : IModelBinder + { + private readonly Type _type; + private readonly SimpleTypeModelBinder _simpleTypeModelBinder; + private readonly IClock _clock; + + public AbpDateTimeModelBinder(ModelBinderProviderContext context) + { + _type = context.Metadata.ModelType; + _clock = context.Services.GetRequiredService(); + _simpleTypeModelBinder = new SimpleTypeModelBinder(context.Metadata.ModelType, + context.Services.GetRequiredService()); + } + + public async Task BindModelAsync(ModelBindingContext bindingContext) + { + await _simpleTypeModelBinder.BindModelAsync(bindingContext); + + if (!bindingContext.Result.IsModelSet) + { + return; + } + + if (_type == typeof(DateTime)) + { + var dateTime = (DateTime) bindingContext.Result.Model; + bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime)); + } + else + { + var dateTime = (DateTime?) bindingContext.Result.Model; + if (dateTime != null) + { + bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime.Value)); + } + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinderProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinderProvider.cs new file mode 100644 index 0000000000..fd55e2b61a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpDateTimeModelBinderProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; +using Volo.Abp.Timing; + +namespace Volo.Abp.AspNetCore.Mvc.ModelBinding +{ + public class AbpDateTimeModelBinderProvider : IModelBinderProvider + { + public IModelBinder GetBinder(ModelBinderProviderContext context) + { + if (context.Metadata.ModelType != typeof(DateTime) && + context.Metadata.ModelType != typeof(DateTime?)) + { + return null; + } + + if (context.Metadata.ContainerType == null) + { + if (context.Metadata is DefaultModelMetadata defaultModelMetadata && + defaultModelMetadata.Attributes.Attributes.All(x => x.GetType() != typeof(DisableDateTimeNormalizationAttribute))) + { + return new AbpDateTimeModelBinder(context); + } + } + else + { + var dateNormalizationDisabledForClass = + context.Metadata.ContainerType.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true); + + var dateNormalizationDisabledForProperty = context.Metadata.ContainerType + .GetProperty(context.Metadata.PropertyName) + ?.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true); + + if (!dateNormalizationDisabledForClass && + dateNormalizationDisabledForProperty != null && + !dateNormalizationDisabledForProperty.Value) + { + return new AbpDateTimeModelBinder(context); + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs new file mode 100644 index 0000000000..2c5a69e7e7 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs @@ -0,0 +1,61 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Timing; + +namespace Volo.Abp.AspNetCore.Mvc.ModelBinding +{ + [Route("api/model-Binding-test")] + public class ModelBindingController : AbpController + { + [HttpGet("DateTimeKind")] + public string DateTimeKind(DateTime input) + { + return input.Kind.ToString().ToLower(); + } + + [HttpGet("NullableDateTimeKind")] + public string NullableDateTimeKind(DateTime? input) + { + return input.Value.Kind.ToString().ToLower(); + } + + [HttpGet("DisableDateTimeNormalizationDateTimeKind")] + public string DisableDateTimeNormalizationDateTimeKind([DisableDateTimeNormalization]DateTime input) + { + return input.Kind.ToString().ToLower(); + } + + [HttpGet("DisableDateTimeNormalizationNullableDateTimeKind")] + public string DisableDateTimeNormalizationNullableDateTimeKind([DisableDateTimeNormalization]DateTime? input) + { + return input.Value.Kind.ToString().ToLower(); + } + + [HttpGet("ComplexTypeDateTimeKind")] + public string ComplexTypeDateTimeKind(GetDateTimeKindModel input) + { + return input.Time1.Kind.ToString().ToLower() + "_" + + input.Time2.Kind.ToString().ToLower() + "_" + + input.Time3.Value.Kind.ToString().ToLower() + "_" + + input.InnerModel.Time4.Kind.ToString().ToLower(); + } + } + + public class GetDateTimeKindModel + { + [DisableDateTimeNormalization] + public DateTime Time1 { get; set; } + + public DateTime Time2 { get; set; } + + public DateTime? Time3 { get; set; } + + public GetDateTimeKindInnerModel InnerModel { get; set; } + + [DisableDateTimeNormalization] + public class GetDateTimeKindInnerModel + { + public DateTime Time4 { get; set; } + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs new file mode 100644 index 0000000000..632a02194f --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -0,0 +1,100 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Shouldly; +using Volo.Abp.Timing; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.ModelBinding +{ + public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase + { + protected DateTimeKind DateTimeKind { get; set; } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(x => x.Kind = DateTimeKind); + } + + [Fact] + public async Task DateTimeKind_Test() + { + var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z"); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); + } + + [Fact] + public async Task NullableDateTimeKind_Test() + { + var response = + await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z"); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); + } + + [Fact] + public async Task DisableDateTimeNormalizationDateTimeKind_Test() + { + var response = + await Client.GetAsync( + "/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z"); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. + resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); + } + + [Fact] + public async Task DisableDateTimeNormalizationNullableDateTimeKind_Test() + { + var response = + await Client.GetAsync( + "/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z"); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. + resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); + } + + [Fact] + public async Task ComplexTypeDateTimeKind_Test() + { + var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" + + "Time1=2010-01-01T00:00:00Z&" + + "Time2=2010-01-01T00:00:00Z&" + + "Time3=2010-01-01T00:00:00Z&" + + "InnerModel.Time4=2010-01-01T00:00:00Z"); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local. + resultAsString.ShouldBe( + $"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local"); + } + } + + public class ModelBindingController_Utc_Tests : ModelBindingController_Tests + { + public ModelBindingController_Utc_Tests() + { + DateTimeKind = DateTimeKind.Utc; + } + } + + public class ModelBindingController_Local_Tests : ModelBindingController_Tests + { + public ModelBindingController_Local_Tests() + { + DateTimeKind = DateTimeKind.Local; + } + } +} \ No newline at end of file From af68bc2110c9adfb7a932fd5215df6dc361996ea Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 15 Nov 2019 14:30:19 +0800 Subject: [PATCH 09/75] Implement external login only. --- .../Account/IdentityServerSupportedLoginModel.cs | 11 ++++++----- .../Areas/Account/Controllers/LogoutController.cs | 7 ++++++- .../Pages/Account/Login.cshtml.cs | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index b6902e86d8..0714d5b323 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -1,4 +1,4 @@ -using IdentityModel; +using IdentityModel; using IdentityServer4.Events; using IdentityServer4.Models; using IdentityServer4.Services; @@ -40,7 +40,7 @@ namespace Volo.Abp.Account.Web.Pages.Account IdentityServerEvents = identityServerEvents; } - public override async Task OnGetAsync() + public override async Task OnGetAsync() { LoginInput = new LoginInputModel(); @@ -63,7 +63,7 @@ namespace Volo.Abp.Account.Web.Pages.Account { LoginInput.UserNameOrEmailAddress = context.LoginHint; ExternalProviders = new[] { new ExternalProviderModel { AuthenticationScheme = context.IdP } }; - return; + return Page(); } var schemes = await _schemeProvider.GetAllSchemesAsync(); @@ -96,9 +96,10 @@ namespace Volo.Abp.Account.Web.Pages.Account if (IsExternalLoginOnly) { - //return await ExternalLogin(vm.ExternalLoginScheme, returnUrl); - throw new NotImplementedException(); + return await base.OnPostExternalLogin(providers.First().AuthenticationScheme); } + + return Page(); } [UnitOfWork] //TODO: Will be removed when we implement action filter diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs index 1f1b43b853..eb7d1cbc84 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs @@ -17,10 +17,15 @@ namespace Volo.Abp.Account.Web.Areas.Account.Controllers } //todo@alper: this method can be moved to AccountController like "account/logout" - public async Task Index() + public async Task Index(string returnUrl = null) { await _signInManager.SignOutAsync(); + if (returnUrl != null) + { + return LocalRedirect(returnUrl); + } + return RedirectToPage("/Account/Login"); } } diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index cc82de414f..74691dba33 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -56,7 +56,7 @@ namespace Volo.Abp.Account.Web.Pages.Account _accountOptions = accountOptions.Value; } - public virtual async Task OnGetAsync() + public virtual async Task OnGetAsync() { LoginInput = new LoginInputModel(); @@ -80,6 +80,8 @@ namespace Volo.Abp.Account.Web.Pages.Account //return await ExternalLogin(vm.ExternalLoginScheme, returnUrl); throw new NotImplementedException(); } + + return Page(); } [UnitOfWork] //TODO: Will be removed when we implement action filter From 7e0fd93bebad4976070b5c8fa8e31645f8750e54 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 15 Nov 2019 15:04:03 +0800 Subject: [PATCH 10/75] Add Abp.Account.EnableLocalLogin setting. --- .../Pages/Account/IdentityServerSupportedLoginModel.cs | 6 ++++-- .../Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs | 8 +++++--- .../Settings/AccountSettingDefinitionProvider.cs | 4 ++++ .../Volo.Abp.Account.Web/Settings/AccountSettingNames.cs | 2 ++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs index 0714d5b323..f1abf44750 100644 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs +++ b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs @@ -12,8 +12,10 @@ using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; +using Volo.Abp.Account.Web.Settings; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Settings; using Volo.Abp.Uow; namespace Volo.Abp.Account.Web.Pages.Account @@ -77,7 +79,7 @@ namespace Volo.Abp.Account.Web.Pages.Account }) .ToList(); - EnableLocalLogin = true; //TODO: We can get default from a setting? + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); if (context?.ClientId != null) { var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId); @@ -105,7 +107,7 @@ namespace Volo.Abp.Account.Web.Pages.Account [UnitOfWork] //TODO: Will be removed when we implement action filter public override async Task OnPostAsync(string action) { - EnableLocalLogin = true; //TODO: We can get default from a setting? + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); if (action == "Cancel") { diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 74691dba33..e7e625416a 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -10,8 +10,10 @@ using System.Diagnostics; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using Volo.Abp.Account.Web.Settings; using Volo.Abp.Identity; using Volo.Abp.Security.Claims; +using Volo.Abp.Settings; using Volo.Abp.Uow; using Volo.Abp.Validation; using IdentityUser = Volo.Abp.Identity.IdentityUser; @@ -71,8 +73,8 @@ namespace Volo.Abp.Account.Web.Pages.Account }) .ToList(); - EnableLocalLogin = true; //TODO: We can get default from a setting? - + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); + ExternalProviders = providers.ToArray(); if (IsExternalLoginOnly) @@ -87,7 +89,7 @@ namespace Volo.Abp.Account.Web.Pages.Account [UnitOfWork] //TODO: Will be removed when we implement action filter public virtual async Task OnPostAsync(string action) { - EnableLocalLogin = true; //TODO: We can get default from a setting? + EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin); ValidateModel(); diff --git a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs b/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs index 8d3ccba7c9..be16fa7045 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingDefinitionProvider.cs @@ -9,6 +9,10 @@ namespace Volo.Abp.Account.Web.Settings context.Add( new SettingDefinition(AccountSettingNames.IsSelfRegistrationEnabled, "true") ); + + context.Add( + new SettingDefinition(AccountSettingNames.EnableLocalLogin, "true") + ); } } } \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs b/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs index 3122dbdc6a..a167be0ce8 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Settings/AccountSettingNames.cs @@ -3,5 +3,7 @@ public class AccountSettingNames { public const string IsSelfRegistrationEnabled = "Abp.Account.IsSelfRegistrationEnabled"; + + public const string EnableLocalLogin = "Abp.Account.EnableLocalLogin"; } } From cfd2845a9e8c0895c64031cd09915e6e7ac60c2c Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 18 Nov 2019 17:59:04 +0800 Subject: [PATCH 11/75] Hide language switch menu if the app has only one language. Resolve #2204 --- .../Toolbar/LanguageSwitch/Default.cshtml | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml index fe6e8c36fd..ae3255abbf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml @@ -1,14 +1,18 @@ -@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch +@using System.Linq +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch @model LanguageSwitchViewComponentModel - +} From 0fa2cbafe3c32a72e46323839655fe6d16e792ba Mon Sep 17 00:00:00 2001 From: brittos Date: Mon, 18 Nov 2019 15:58:01 -0300 Subject: [PATCH 12/75] Create dotnetcore.yml --- .github/workflows/dotnetcore.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/dotnetcore.yml diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 0000000000..0f9d2a6777 --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,17 @@ +name: .NET Core + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 2.2.108 + - name: Build with dotnet + run: dotnet build --configuration Release From a80fd3abbc69ab428dada46a8e989a3faf8f96ab Mon Sep 17 00:00:00 2001 From: brittos Date: Mon, 18 Nov 2019 16:01:31 -0300 Subject: [PATCH 13/75] Delete dotnetcore.yml --- .github/workflows/dotnetcore.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/dotnetcore.yml diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml deleted file mode 100644 index 0f9d2a6777..0000000000 --- a/.github/workflows/dotnetcore.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: .NET Core - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 2.2.108 - - name: Build with dotnet - run: dotnet build --configuration Release From fbf09340a049c295523a5afe34b00386713f77f6 Mon Sep 17 00:00:00 2001 From: brittos Date: Mon, 18 Nov 2019 16:34:34 -0300 Subject: [PATCH 14/75] Update pt-BR.json fix localization --- .../AbpIoLocalization/Www/Localization/Resources/pt-BR.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json index a01d460e01..c34a08f7ed 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/pt-BR.json @@ -18,10 +18,10 @@ "AbpShortDescription": "ABP é uma arquitetura completa e uma forte infraestrutura para criar aplicativos da web modernos! Segue as melhores práticas e convenções para fornecer uma sólida experiência de desenvolvimento.", "SourceCodeUpper": "CÓDIGO FONTE", "LatestReleaseLogs": "Últimos registros de lançamento", - "Infrastructure": "Infra-estrutura", + "Infrastructure": "Infraestrutura", "Architecture": "Arquitetura", "Modular": "Modular", - "DontRepeatYourself": "Não se repita", + "DontRepeatYourself": "Não repita a si mesmo", "DeveloperFocused": "Desenvolvedor focado", "FullStackApplicationInfrastructure": "Infraestrutura de aplicativos full stack.", "DomainDrivenDesign": "Design Orientado a Domínio", @@ -30,7 +30,7 @@ "AuthorizationExplanation": "Autorização avançada com usuário, função e sistema de permissão refinado. Criada na biblioteca Microsoft Identity.", "MultiTenancy": "Múltiplos inquilinos", "MultiTenancyExplanation": "Aplicativos SaaS facilitados! Multilocação integrada do banco de dados à interface do usuário.", - "CrossCuttingConcerns": "Preocupações transversais", + "CrossCuttingConcerns": "Características transversais", "CrossCuttingConcernsExplanation": "Infraestrutura completa para autorização, validação, tratamento de exceções, armazenamento em cache, log de auditoria, gerenciamento de transações e assim por diante.", "BuiltInBundlingMinification": "Pacote & Minificação Integrados", "BuiltInBundlingMinificationExplanation": "Pare de usar ferramentas externas para empacotamento e minificação. O ABP oferece uma maneira mais simples, dinâmica, poderosa, modular e integrada!", From 67ed3bb372b6e920179da437bc084cac69f336fb Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 19 Nov 2019 11:33:51 +0300 Subject: [PATCH 15/75] Update Index.md --- docs/en/Modules/Index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/en/Modules/Index.md b/docs/en/Modules/Index.md index bd608c4528..9d1c1d301f 100644 --- a/docs/en/Modules/Index.md +++ b/docs/en/Modules/Index.md @@ -19,8 +19,7 @@ There are some **free and open source** application modules developed and mainta * **Identity**: Used to manage roles, users and their permissions. * **Identity Server**: Integrates to IdentityServer4. * **Permission Management**: Used to persist permissions. -* **[Setting Management](Setting-Management.md)**: Used to persist -and manage the [settings](../Settings.md). +* **[Setting Management](Setting-Management.md)**: Used to persist and manage the [settings](../Settings.md). * **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application. * **Users**: Used to abstract users, so other modules can depend on this instead of the Identity module. From 99957e4c29b983beab556aa9361d4b76e746e5f3 Mon Sep 17 00:00:00 2001 From: Super Date: Wed, 20 Nov 2019 17:25:15 +0800 Subject: [PATCH 16/75] Create dotnetcore.yml --- .github/workflows/dotnetcore.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/dotnetcore.yml diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 0000000000..0f9d2a6777 --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,17 @@ +name: .NET Core + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 2.2.108 + - name: Build with dotnet + run: dotnet build --configuration Release From 667294cc8b363bacb7705dc29a6b1dfd65772e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 21 Nov 2019 17:39:22 +0300 Subject: [PATCH 17/75] #2231 Change applicationUrls for the microservice demo applications --- .../applications/AuthServer.Host/Properties/launchSettings.json | 2 +- .../BackendAdminApp.Host/Properties/launchSettings.json | 2 +- .../PublicWebSite.Host/Properties/launchSettings.json | 2 +- .../BackendAdminAppGateway.Host/Properties/launchSettings.json | 2 +- .../InternalGateway.Host/Properties/launchSettings.json | 2 +- .../PublicWebSiteGateway.Host/Properties/launchSettings.json | 2 +- .../BloggingService.Host/Properties/launchSettings.json | 2 +- .../IdentityService.Host/Properties/launchSettings.json | 2 +- .../ProductService.Host/Properties/launchSettings.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json index 64eeed40fe..d8e84747ac 100644 --- a/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/applications/AuthServer.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "AuthServer.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:64999", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/Properties/launchSettings.json index affa8826fb..f7ea179db1 100644 --- a/samples/MicroserviceDemo/applications/BackendAdminApp.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/applications/BackendAdminApp.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "BackendAdminApp.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:51954", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/applications/PublicWebSite.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/applications/PublicWebSite.Host/Properties/launchSettings.json index 3945c0c403..9b9ac6527f 100644 --- a/samples/MicroserviceDemo/applications/PublicWebSite.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/applications/PublicWebSite.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "PublicWebSite.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:53435", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Properties/launchSettings.json index 981961f411..f56a0bdb72 100644 --- a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "BackendAdminAppGateway.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:65115", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/gateways/InternalGateway.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/gateways/InternalGateway.Host/Properties/launchSettings.json index f65859f468..c56831d419 100644 --- a/samples/MicroserviceDemo/gateways/InternalGateway.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/gateways/InternalGateway.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "InternalGateway.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:65129", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Properties/launchSettings.json index fa3d33da52..b24931efcf 100644 --- a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "PublicWebSiteGateway.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:64897", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/microservices/BloggingService.Host/Properties/launchSettings.json index b8f8803266..0ad1aabc2a 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "BloggingService.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:62157", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/microservices/IdentityService.Host/Properties/launchSettings.json index cd85573717..d47ed9055c 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "IdentityService.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:63568", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/Properties/launchSettings.json b/samples/MicroserviceDemo/microservices/ProductService.Host/Properties/launchSettings.json index b93ef90918..d6620ecc08 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/Properties/launchSettings.json +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/Properties/launchSettings.json @@ -18,7 +18,7 @@ "ProductService.Host": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "http://localhost:5000", + "applicationUrl": "http://localhost:60244", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From 0b9563e36f43f93740a1da762aa0d4cda57195ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 21 Nov 2019 17:39:50 +0300 Subject: [PATCH 18/75] Resolved #2231: Create PS1 file to run the microservice demo from the command line. --- .gitignore | 1 + samples/MicroserviceDemo/_run/01_AuthServer.ps1 | 2 ++ samples/MicroserviceDemo/_run/02_IdentityService.ps1 | 2 ++ samples/MicroserviceDemo/_run/03_BloggingService.ps1 | 2 ++ samples/MicroserviceDemo/_run/04_ProductService.ps1 | 2 ++ samples/MicroserviceDemo/_run/05_InternalGateway.ps1 | 2 ++ .../MicroserviceDemo/_run/06_BackendAdminAppGateway.ps1 | 2 ++ .../MicroserviceDemo/_run/07_PublicWebSiteGateway.ps1 | 2 ++ samples/MicroserviceDemo/_run/08_BackendAdminApp.ps1 | 2 ++ samples/MicroserviceDemo/_run/09_PublicWebSite.ps1 | 2 ++ samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 | 9 +++++++++ samples/MicroserviceDemo/_run/11_Run_Browser.ps1 | 1 + samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 | 2 ++ 13 files changed, 31 insertions(+) create mode 100644 samples/MicroserviceDemo/_run/01_AuthServer.ps1 create mode 100644 samples/MicroserviceDemo/_run/02_IdentityService.ps1 create mode 100644 samples/MicroserviceDemo/_run/03_BloggingService.ps1 create mode 100644 samples/MicroserviceDemo/_run/04_ProductService.ps1 create mode 100644 samples/MicroserviceDemo/_run/05_InternalGateway.ps1 create mode 100644 samples/MicroserviceDemo/_run/06_BackendAdminAppGateway.ps1 create mode 100644 samples/MicroserviceDemo/_run/07_PublicWebSiteGateway.ps1 create mode 100644 samples/MicroserviceDemo/_run/08_BackendAdminApp.ps1 create mode 100644 samples/MicroserviceDemo/_run/09_PublicWebSite.ps1 create mode 100644 samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 create mode 100644 samples/MicroserviceDemo/_run/11_Run_Browser.ps1 create mode 100644 samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 diff --git a/.gitignore b/.gitignore index 4eabbccebd..73d74ec7c6 100644 --- a/.gitignore +++ b/.gitignore @@ -289,4 +289,5 @@ samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Logs/logs.txt samples/MicroserviceDemo/applications/PublicWebSite.Host/Logs/logs.txt samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Logs/logs.txt samples/MicroserviceDemo/microservices/BloggingService.Host/Logs/logs.txt +samples/MicroserviceDemo/applications/ConsoleClientDemo/Logs/logs.txt modules/docs/app/Volo.DocsTestApp/Logs/logs.txt diff --git a/samples/MicroserviceDemo/_run/01_AuthServer.ps1 b/samples/MicroserviceDemo/_run/01_AuthServer.ps1 new file mode 100644 index 0000000000..14d1b32981 --- /dev/null +++ b/samples/MicroserviceDemo/_run/01_AuthServer.ps1 @@ -0,0 +1,2 @@ +cd ../applications/AuthServer.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/02_IdentityService.ps1 b/samples/MicroserviceDemo/_run/02_IdentityService.ps1 new file mode 100644 index 0000000000..c47c8406c3 --- /dev/null +++ b/samples/MicroserviceDemo/_run/02_IdentityService.ps1 @@ -0,0 +1,2 @@ +cd ../microservices/IdentityService.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/03_BloggingService.ps1 b/samples/MicroserviceDemo/_run/03_BloggingService.ps1 new file mode 100644 index 0000000000..65b2c9ca11 --- /dev/null +++ b/samples/MicroserviceDemo/_run/03_BloggingService.ps1 @@ -0,0 +1,2 @@ +cd ../microservices/BloggingService.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/04_ProductService.ps1 b/samples/MicroserviceDemo/_run/04_ProductService.ps1 new file mode 100644 index 0000000000..1181edd4e0 --- /dev/null +++ b/samples/MicroserviceDemo/_run/04_ProductService.ps1 @@ -0,0 +1,2 @@ +cd ../microservices/ProductService.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/05_InternalGateway.ps1 b/samples/MicroserviceDemo/_run/05_InternalGateway.ps1 new file mode 100644 index 0000000000..f27befba7b --- /dev/null +++ b/samples/MicroserviceDemo/_run/05_InternalGateway.ps1 @@ -0,0 +1,2 @@ +cd ../gateways/InternalGateway.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/06_BackendAdminAppGateway.ps1 b/samples/MicroserviceDemo/_run/06_BackendAdminAppGateway.ps1 new file mode 100644 index 0000000000..3d819542c2 --- /dev/null +++ b/samples/MicroserviceDemo/_run/06_BackendAdminAppGateway.ps1 @@ -0,0 +1,2 @@ +cd ../gateways/BackendAdminAppGateway.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/07_PublicWebSiteGateway.ps1 b/samples/MicroserviceDemo/_run/07_PublicWebSiteGateway.ps1 new file mode 100644 index 0000000000..009f45bc66 --- /dev/null +++ b/samples/MicroserviceDemo/_run/07_PublicWebSiteGateway.ps1 @@ -0,0 +1,2 @@ +cd ../gateways/PublicWebSiteGateway.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/08_BackendAdminApp.ps1 b/samples/MicroserviceDemo/_run/08_BackendAdminApp.ps1 new file mode 100644 index 0000000000..356d7ac981 --- /dev/null +++ b/samples/MicroserviceDemo/_run/08_BackendAdminApp.ps1 @@ -0,0 +1,2 @@ +cd ../applications/BackendAdminApp.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/09_PublicWebSite.ps1 b/samples/MicroserviceDemo/_run/09_PublicWebSite.ps1 new file mode 100644 index 0000000000..24d31ced0f --- /dev/null +++ b/samples/MicroserviceDemo/_run/09_PublicWebSite.ps1 @@ -0,0 +1,2 @@ +cd ../applications/PublicWebSite.Host +dotnet run \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 b/samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 new file mode 100644 index 0000000000..9129959d85 --- /dev/null +++ b/samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 @@ -0,0 +1,9 @@ +start powershell .\01_AuthServer.ps1 +start powershell .\02_IdentityService.ps1 +start powershell .\03_BloggingService.ps1 +start powershell .\04_ProductService.ps1 +start powershell .\05_InternalGateway.ps1 +start powershell .\06_BackendAdminAppGateway.ps1 +start powershell .\07_PublicWebSiteGateway.ps1 +start powershell .\08_BackendAdminApp.ps1 +start powershell .\09_PublicWebSite.ps1 \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/11_Run_Browser.ps1 b/samples/MicroserviceDemo/_run/11_Run_Browser.ps1 new file mode 100644 index 0000000000..50c010b9bb --- /dev/null +++ b/samples/MicroserviceDemo/_run/11_Run_Browser.ps1 @@ -0,0 +1 @@ +start chrome http://localhost:64999,http://localhost:63568,http://localhost:62157,http://localhost:60244,http://localhost:65129/swagger,http://localhost:65115/swagger,http://localhost:64897/swagger,http://localhost:51954,http://localhost:53435 \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 b/samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 new file mode 100644 index 0000000000..0fc3d40edc --- /dev/null +++ b/samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 @@ -0,0 +1,2 @@ +cd ../applications/ConsoleClientDemo +dotnet run \ No newline at end of file From c5fc902fb3aa45422d7efb5728d12b0e31b0ff8c Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 22 Nov 2019 11:48:52 +0300 Subject: [PATCH 19/75] feat(permissin-guard): add a handling permission condition --- .../packages/core/src/lib/guards/permission.guard.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts index ca69eb127d..97c6c3ebc8 100644 --- a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts +++ b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts @@ -2,9 +2,10 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate } from '@angular/router'; import { Store } from '@ngxs/store'; import { Observable } from 'rxjs'; -import { ConfigState } from '../states'; import { tap } from 'rxjs/operators'; +import snq from 'snq'; import { RestOccurError } from '../actions'; +import { ConfigState } from '../states'; @Injectable({ providedIn: 'root', @@ -13,7 +14,7 @@ export class PermissionGuard implements CanActivate { constructor(private store: Store) {} canActivate({ data }: ActivatedRouteSnapshot): Observable { - const resource = data.requiredPolicy as string; + const resource = snq(() => data.routes.requiredPolicy) || (data.requiredPolicy as string); return this.store.select(ConfigState.getGrantedPolicy(resource)).pipe( tap(access => { if (!access) { From 790a26c45853bb516677f4d2fd1f31771de032b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 22 Nov 2019 13:28:15 +0300 Subject: [PATCH 20/75] Add readme --- ...lientDemo.ps1 => 10_ConsoleClientDemo.ps1} | 0 samples/MicroserviceDemo/_run/README.md | 19 +++++++++++++++++++ ...lication.ps1 => __Run_All_Application.ps1} | 0 .../{11_Run_Browser.ps1 => __Run_Browser.ps1} | 0 4 files changed, 19 insertions(+) rename samples/MicroserviceDemo/_run/{12_ConsoleClientDemo.ps1 => 10_ConsoleClientDemo.ps1} (100%) create mode 100644 samples/MicroserviceDemo/_run/README.md rename samples/MicroserviceDemo/_run/{10_Run_All_Application.ps1 => __Run_All_Application.ps1} (100%) rename samples/MicroserviceDemo/_run/{11_Run_Browser.ps1 => __Run_Browser.ps1} (100%) diff --git a/samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 b/samples/MicroserviceDemo/_run/10_ConsoleClientDemo.ps1 similarity index 100% rename from samples/MicroserviceDemo/_run/12_ConsoleClientDemo.ps1 rename to samples/MicroserviceDemo/_run/10_ConsoleClientDemo.ps1 diff --git a/samples/MicroserviceDemo/_run/README.md b/samples/MicroserviceDemo/_run/README.md new file mode 100644 index 0000000000..f81e093cc2 --- /dev/null +++ b/samples/MicroserviceDemo/_run/README.md @@ -0,0 +1,19 @@ +# Run the Microservice Demo Solution + +This folder contains PowerShell files to run the system: + +* **__Run_All_Application.ps1**: Runs all the applications in one click. +* **__Run_Browser.ps1**: Opens all the UIs of the applications in Google Chrome browser. + +Other files runs the individual applications. + +> This files are only tested in Windows 10. + +### Pre-Requirements + +- [SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads) 2015+ (can be [express edition](https://www.microsoft.com/en-us/sql-server/sql-server-editions-express)) +- [Redis](https://redis.io/download) 5.0+ +- [RabbitMQ](https://www.rabbitmq.com/install-windows.html) 3.7.11+ +- [MongoDB](https://www.mongodb.com/download-center) 4.0+ +- [ElasticSearch](https://www.elastic.co/downloads/elasticsearch) 6.6+ +- [Kibana](https://www.elastic.co/downloads/kibana) 6.6+ (optional, recommended to see logs) \ No newline at end of file diff --git a/samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 b/samples/MicroserviceDemo/_run/__Run_All_Application.ps1 similarity index 100% rename from samples/MicroserviceDemo/_run/10_Run_All_Application.ps1 rename to samples/MicroserviceDemo/_run/__Run_All_Application.ps1 diff --git a/samples/MicroserviceDemo/_run/11_Run_Browser.ps1 b/samples/MicroserviceDemo/_run/__Run_Browser.ps1 similarity index 100% rename from samples/MicroserviceDemo/_run/11_Run_Browser.ps1 rename to samples/MicroserviceDemo/_run/__Run_Browser.ps1 From d8bdcffd4c69787e69fb7ae3c3375a44a0067e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 22 Nov 2019 15:31:24 +0300 Subject: [PATCH 21/75] Fix claims mapping for the microservice demo --- .../BackendAdminAppGatewayHostModule.cs | 29 +++++++++++++------ .../InternalGatewayHostModule.cs | 29 +++++++++++++------ .../PublicWebSiteGatewayHostModule.cs | 29 +++++++++++++------ .../BloggingServiceHostModule.cs | 27 ++++++++++++----- .../IdentityServiceHostModule.cs | 29 +++++++++++++------ .../ProductServiceHostModule.cs | 29 +++++++++++++------ 6 files changed, 119 insertions(+), 53 deletions(-) diff --git a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs index d30dc8e4fb..81a109a6f0 100644 --- a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using Ocelot.DependencyInjection; @@ -52,14 +55,6 @@ namespace BackendAdminAppGateway.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -94,6 +89,22 @@ namespace BackendAdminAppGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs index 8b470f826f..a3572551f9 100644 --- a/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using Ocelot.DependencyInjection; @@ -41,14 +44,6 @@ namespace InternalGateway.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -83,6 +78,22 @@ namespace InternalGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs index 2add48443a..0129663e5a 100644 --- a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using Ocelot.DependencyInjection; @@ -39,14 +42,6 @@ namespace PublicWebSiteGateway.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -81,6 +76,22 @@ namespace PublicWebSiteGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseSwagger(); app.UseSwaggerUI(options => { diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs index 1f80e0c605..2d7e945cf5 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; @@ -57,14 +60,6 @@ namespace BloggingService.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -113,6 +108,22 @@ namespace BloggingService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index 96899af0a0..2bf102a465 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; @@ -44,14 +47,6 @@ namespace IdentityService.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -95,6 +90,22 @@ namespace IdentityService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs index 8389067092..97235133f9 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs @@ -1,4 +1,7 @@ -using Microsoft.AspNetCore.Builder; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using ProductManagement; @@ -46,14 +49,6 @@ namespace ProductService.Host options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = false; - //TODO: Should create an extension method for that (may require to create a new ABP package depending on the IdentityServer4.AccessTokenValidation) - //options.InboundJwtClaimTypeMap["sub"] = AbpClaimTypes.UserId; - //options.InboundJwtClaimTypeMap["role"] = AbpClaimTypes.Role; - //options.InboundJwtClaimTypeMap["email"] = AbpClaimTypes.Email; - //options.InboundJwtClaimTypeMap["email_verified"] = AbpClaimTypes.EmailVerified; - //options.InboundJwtClaimTypeMap["phone_number"] = AbpClaimTypes.PhoneNumber; - //options.InboundJwtClaimTypeMap["phone_number_verified"] = AbpClaimTypes.PhoneNumberVerified; - //options.InboundJwtClaimTypeMap["name"] = AbpClaimTypes.UserName; }); context.Services.AddSwaggerGen(options => @@ -97,6 +92,22 @@ namespace ProductService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + + app.Use(async (ctx, next) => + { + var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); + var map = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + //any other map + }; + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); + await next(); + }); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => From 3125fd6a46bcdf098a480c88ac3ecf7dbe2998eb Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Fri, 22 Nov 2019 15:40:15 +0300 Subject: [PATCH 22/75] localization --- .../Abp/IdentityServer/Localization/Resources/tr.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/tr.json diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/tr.json b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/tr.json new file mode 100644 index 0000000000..9340b7999f --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/Localization/Resources/tr.json @@ -0,0 +1,8 @@ +{ + "culture": "tr", + "texts": { + "Volo.IdentityServer:DuplicateIdentityResourceName": "Identity Resource adı zaten mevcut: {Name}", + "Volo.IdentityServer:DuplicateApiResourceName": "Api Resource adı zaten mevcut: {Name}", + "Volo.IdentityServer:DuplicateClientId": "ClientId already zaten mevcut: {ClientId}" + } +} \ No newline at end of file From 26ae9a0179f085716cf073ac0ad33fa35e6171e1 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 22 Nov 2019 17:23:03 +0300 Subject: [PATCH 23/75] chore: update angular versions --- templates/app/angular/package.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index 5caed49ce5..2035c3e6b2 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -18,23 +18,23 @@ "@abp/ng.setting-management": "^1.0.4", "@abp/ng.tenant-management": "^1.0.4", "@abp/ng.theme.basic": "^1.0.4", - "@angular/animations": "~8.2.13", - "@angular/common": "~8.2.13", - "@angular/compiler": "~8.2.13", - "@angular/core": "~8.2.13", - "@angular/forms": "~8.2.13", - "@angular/platform-browser": "~8.2.13", - "@angular/platform-browser-dynamic": "~8.2.13", - "@angular/router": "~8.2.13", + "@angular/animations": "~8.2.14", + "@angular/common": "~8.2.14", + "@angular/compiler": "~8.2.14", + "@angular/core": "~8.2.14", + "@angular/forms": "~8.2.14", + "@angular/platform-browser": "~8.2.14", + "@angular/platform-browser-dynamic": "~8.2.14", + "@angular/router": "~8.2.14", "rxjs": "~6.4.0", "tslib": "^1.10.0", "zone.js": "~0.9.1" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.803.17", - "@angular/cli": "~8.3.17", - "@angular/compiler-cli": "~8.2.13", - "@angular/language-service": "~8.2.13", + "@angular-devkit/build-angular": "~0.803.19", + "@angular/cli": "~8.3.19", + "@angular/compiler-cli": "~8.2.14", + "@angular/language-service": "~8.2.14", "@angularclass/hmr": "^2.1.3", "@ngxs/hmr-plugin": "^3.5.1", "@ngxs/logger-plugin": "^3.5.1", From 3516a811c9aead4a85d1c6983a7b337fa7b2f414 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 22 Nov 2019 17:23:23 +0300 Subject: [PATCH 24/75] chore: change home component selector --- templates/app/angular/src/app/app.component.ts | 1 + templates/app/angular/src/app/home/home.component.spec.ts | 2 +- templates/app/angular/src/app/home/home.component.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/templates/app/angular/src/app/app.component.ts b/templates/app/angular/src/app/app.component.ts index f1d46f7b08..4780afbfd5 100644 --- a/templates/app/angular/src/app/app.component.ts +++ b/templates/app/angular/src/app/app.component.ts @@ -22,6 +22,7 @@ export class AppComponent implements OnInit { 'fontawesome-v4-shims.min.css', ], 'style', + null, 'head', ) .subscribe(); diff --git a/templates/app/angular/src/app/home/home.component.spec.ts b/templates/app/angular/src/app/home/home.component.spec.ts index c0c7686591..b52901d692 100644 --- a/templates/app/angular/src/app/home/home.component.spec.ts +++ b/templates/app/angular/src/app/home/home.component.spec.ts @@ -13,7 +13,7 @@ describe('HomeComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [HomeModule, NgxsModule.forRoot(), RouterTestingModule], + imports: [ NgxsModule.forRoot(), HomeModule, RouterTestingModule], providers: [{ provide: OAuthService, useValue: { hasValidAccessToken: () => false } }], }); fixture = TestBed.createComponent(HomeComponent); diff --git a/templates/app/angular/src/app/home/home.component.ts b/templates/app/angular/src/app/home/home.component.ts index aa56d34131..a42b960493 100644 --- a/templates/app/angular/src/app/home/home.component.ts +++ b/templates/app/angular/src/app/home/home.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { OAuthService } from 'angular-oauth2-oidc'; @Component({ - selector: 'abp-home', + selector: 'app-home', templateUrl: './home.component.html', }) export class HomeComponent { From 6b78dbff863e92f6c41358fceb25210763571388 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 22 Nov 2019 17:23:46 +0300 Subject: [PATCH 25/75] feat(core): add undefined and empty string params control to rest service --- .../core/src/lib/services/rest.service.ts | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts index 4057a4a29a..0ad32ba010 100644 --- a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts @@ -23,17 +23,31 @@ export class RestService { config = config || ({} as Rest.Config); const { observe = Rest.Observe.Body, skipHandleError } = config; const url = (api || this.store.selectSnapshot(ConfigState.getApiUrl())) + request.url; - const { method, ...options } = request; + const { method, params, ...options } = request; - return this.http.request(method, url, { observe, ...options } as any).pipe( - observe === Rest.Observe.Body ? take(1) : tap(), - catchError(err => { - if (skipHandleError) { - return throwError(err); - } + return this.http + .request(method, url, { + observe, + ...(params && { + params: Object.keys(params).reduce( + (acc, key) => ({ + ...acc, + ...(typeof params[key] !== 'undefined' && params[key] !== '' && { [key]: params[key] }), + }), + {}, + ), + }), + ...options, + } as any) + .pipe( + observe === Rest.Observe.Body ? take(1) : tap(), + catchError(err => { + if (skipHandleError) { + return throwError(err); + } - return this.handleError(err); - }), - ); + return this.handleError(err); + }), + ); } } From 9e67e1e7709c5ebd5236719b3d0d02fc14ee61ba Mon Sep 17 00:00:00 2001 From: gdlcf88 <47396430@qq.com> Date: Sat, 23 Nov 2019 18:24:42 +0800 Subject: [PATCH 26/75] Update for Module-Architecture docs. --- docs/en/Best-Practices/Module-Architecture.md | 2 +- .../Best-Practices/Module-Architecture.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/en/Best-Practices/Module-Architecture.md b/docs/en/Best-Practices/Module-Architecture.md index f37d60d68b..88f376352f 100644 --- a/docs/en/Best-Practices/Module-Architecture.md +++ b/docs/en/Best-Practices/Module-Architecture.md @@ -85,5 +85,5 @@ Next section describes the packages in more details. #### Web Layer -* Do create a **Web** package, named as *CompanyName.ModuleName.Web*, that contains pages, views, scripts, styles, images and other UI components. +* **Do** create a **Web** package, named as *CompanyName.ModuleName.Web*, that contains pages, views, scripts, styles, images and other UI components. * Web package only depends on the **HttpApi** package. \ No newline at end of file diff --git a/docs/zh-Hans/Best-Practices/Module-Architecture.md b/docs/zh-Hans/Best-Practices/Module-Architecture.md index ad38509ef8..6f761ef8cb 100644 --- a/docs/zh-Hans/Best-Practices/Module-Architecture.md +++ b/docs/zh-Hans/Best-Practices/Module-Architecture.md @@ -57,33 +57,33 @@ * **推荐** 将领域层划分为两个项目: * **Domain.Shared** 包(项目) 命名为*CompanyName.ModuleName.Domain.Shared*,包含常量,枚举和其他类型, 它不能包含实体,存储库,域服务或任何其他业务对象. 可以安全地与模块中的所有层使用. 此包也可以与第三方客户端使用. * **Domain** 包(项目) 命名为*CompanyName.ModuleName.Domain*, 包含实体, 仓储接口,领域服务接口及其实现和其他领域对象. - * Domain package 依赖于 **Domain.Share** package. + * Domain 包依赖于 **Domain.Share** 包. #### 应用服务层 * **推荐** 将应用服务层划分为两个项目: * **Application.Contracts** 包(项目) 命名为*CompanyName.ModuleName.Application.Contracts,包含应用服务接口和相关的数据传输对象(DTO). - * Application contract package 依赖于 **Domain.Shared** package. + * Application contract 包依赖于 **Domain.Shared** 包. * **Application** 包(项目)命名为*CompanyName.ModuleName.Application*,包含应用服务实现. - * Application package 依赖于 **Domain** 和 **Application.Contracts** packages. + * Application 包依赖于 **Domain** 包和 **Application.Contracts** 包. #### 基础设施层 * **推荐** 为每个orm/数据库集成创建一个独立的集成包, 比如Entity Framework Core 和 MongoDB. - * **推荐** 例如, 创建一个抽象Entity Framework Core集成的*CompanyName.ModuleName.EntityFrameworkCore* package. ORM 集成 package 依赖于 **Domain** package. + * **推荐** 例如, 创建一个抽象Entity Framework Core集成的*CompanyName.ModuleName.EntityFrameworkCore* 包. ORM 集成包依赖于 **Domain** 包. * **不推荐** 依赖于orm/数据库集成包中的其他层. * **推荐** 为每个主要的库创建一个独立的集成包, 在不影响其他包的情况下可以被另一个库替换. #### HTTP 层 * **推荐** 创建命名为*CompanyName.ModuleName.HttpApi*的**HTTP API**包, 为模块开发REST风格的HTTP API. - * HTTP API package 只依赖于 **Application.Contracts** package. 不要依赖 Application package. + * HTTP API 包只依赖于 **Application.Contracts** 包. 不要依赖 Application 包. * **推荐** 为每个应用服务创建一个Controller (通常通过实现其接口). 这些控制器使用应用服务接口来委托操作. 它根据需要配置路由, HTTP方法和其他与Web相关的东西. -* **推荐** 创建一个为HTTP API包提供客户端服务的**HTTP API Client**包, 它的命名为*companyname.modulename.httpapi*. 这些客户端服务将应用服务接口实现远程端点的客户端. - * HTTP API Client package 仅依赖于 **Application.Contracts** package. +* **推荐** 创建一个为HTTP API包提供客户端服务的**HTTP API Client**包, 它的命名为*Companyname.ModuleName.HttpApi.Client*. 这些客户端服务将应用服务接口实现远程端点的客户端. + * HTTP API Client 包仅依赖于 **Application.Contracts** 包. * **推荐** 使用ABP框架提供的动态代理HTTP C#客户端的功能. #### Web 层 * **推荐** 创建命名为*CompanyName.ModuleName.Web*的 **Web**包. 包含页面,视图,脚本,样式,图像和其他UI组件. - * Web package 仅依赖于 **HttpApi** package. \ No newline at end of file + * Web 包仅依赖于 **HttpApi** 包. \ No newline at end of file From d761851399115dcfd77c6adafba01f3f7c65a5ca Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 23 Nov 2019 18:32:03 +0800 Subject: [PATCH 27/75] Remove "Preview" stage note! --- docs/zh-Hans/Index.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/zh-Hans/Index.md b/docs/zh-Hans/Index.md index fbe003b8e7..d946d8f0bb 100644 --- a/docs/zh-Hans/Index.md +++ b/docs/zh-Hans/Index.md @@ -6,12 +6,6 @@ ABP是一个**开源应用程序框架**,专注于基于ASP.NET Core的Web应用 浏览左侧导航菜单以深入了解文档. -## 项目状态 - -ABP是开源[ASP.NET Boilerplate](https://aspnetboilerplate.com/)框架的**下一代框架**, 它目前处于早期预览阶段,尚未准备好在生产中使用. 文档仍在进行中,远未完成. - -对于短期和生产级应用程序, 建议使用[ASP.NET Boilerplate](https://aspnetboilerplate.com/)框架,该框架具有丰富的功能集,成熟,积极维护和最新. - ## 入门 使用ABP开发新项目的最简单方法是使用启动模板: From 2080e0c23304cb35a5787624a5d892542300947d Mon Sep 17 00:00:00 2001 From: gdlcf88 <47396430@qq.com> Date: Sat, 23 Nov 2019 18:32:12 +0800 Subject: [PATCH 28/75] Delete cutstom workflows. --- .github/workflows/dotnetcore.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/dotnetcore.yml diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml deleted file mode 100644 index 0f9d2a6777..0000000000 --- a/.github/workflows/dotnetcore.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: .NET Core - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 2.2.108 - - name: Build with dotnet - run: dotnet build --configuration Release From 030d593ee97250a73423e1deaa15f2a1c82223ad Mon Sep 17 00:00:00 2001 From: gdlcf88 <47396430@qq.com> Date: Sun, 24 Nov 2019 03:19:32 +0800 Subject: [PATCH 29/75] Fix a spelling mistake. --- docs/en/Best-Practices/Module-Architecture.md | 2 +- docs/zh-Hans/Best-Practices/Module-Architecture.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Best-Practices/Module-Architecture.md b/docs/en/Best-Practices/Module-Architecture.md index 88f376352f..d9f833726f 100644 --- a/docs/en/Best-Practices/Module-Architecture.md +++ b/docs/en/Best-Practices/Module-Architecture.md @@ -57,7 +57,7 @@ Next section describes the packages in more details. * **Do** divide the domain layer into two projects: * **Domain.Shared** package, named as *CompanyName.ModuleName.Domain.Shared*, that contains constants, enums and other types those can be safely shared with the all layers of the module. This package can also be shared to 3rd-party clients. It can not contain entities, repositories, domain services or any other business objects. * **Domain** package, named as *CompanyName.ModuleName.Domain*, that contains entities, repository interfaces, domain service interfaces and their implementations and other domain objects. - * Domain package depends on the **Domain.Share** package. + * Domain package depends on the **Domain.Shared** package. #### Application Layer diff --git a/docs/zh-Hans/Best-Practices/Module-Architecture.md b/docs/zh-Hans/Best-Practices/Module-Architecture.md index 6f761ef8cb..648bf660b1 100644 --- a/docs/zh-Hans/Best-Practices/Module-Architecture.md +++ b/docs/zh-Hans/Best-Practices/Module-Architecture.md @@ -57,7 +57,7 @@ * **推荐** 将领域层划分为两个项目: * **Domain.Shared** 包(项目) 命名为*CompanyName.ModuleName.Domain.Shared*,包含常量,枚举和其他类型, 它不能包含实体,存储库,域服务或任何其他业务对象. 可以安全地与模块中的所有层使用. 此包也可以与第三方客户端使用. * **Domain** 包(项目) 命名为*CompanyName.ModuleName.Domain*, 包含实体, 仓储接口,领域服务接口及其实现和其他领域对象. - * Domain 包依赖于 **Domain.Share** 包. + * Domain 包依赖于 **Domain.Shared** 包. #### 应用服务层 From 23c778f978c048647f07a0a075709de756fbb08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 23 Nov 2019 23:05:34 +0300 Subject: [PATCH 30/75] Fix typo: Surname --- .../Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs index 23632efce0..aca1535c3c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Identity public virtual string Name { get; set; } /// - /// Gets or sets the Surame for the user. + /// Gets or sets the Surname for the user. /// public virtual string Surname { get; set; } From 63f48c706aa828ecda77a4e83724e72c4742eb0d Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 25 Nov 2019 14:41:29 +0800 Subject: [PATCH 31/75] Change SQL Server to LocalDb for the startup template connection strings Resolve #2224 --- .../MyCompanyName.MyProjectName.DbMigrator/appsettings.json | 2 +- .../MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json | 2 +- .../appsettings.json | 2 +- .../appsettings.json | 2 +- .../src/MyCompanyName.MyProjectName.Web/appsettings.json | 2 +- .../MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json | 4 ++-- .../appsettings.json | 2 +- .../MyCompanyName.MyProjectName.Web.Unified/appsettings.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json index dd942783d6..d45a2093e7 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" }, "IdentityServer": { "Clients": { diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index bad453f08a..2e0c5d044b 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -3,7 +3,7 @@ "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200" }, "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json index ffe84edc52..dd3055b873 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/appsettings.json @@ -4,7 +4,7 @@ "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200" }, "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" }, "AuthServer": { "Authority": "https://localhost:44305" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index 45f23d7895..6b650ad8c6 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -4,7 +4,7 @@ "CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200" }, "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json index 828ea38e60..03262e4a34 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/appsettings.json @@ -3,7 +3,7 @@ "SelfUrl": "https://localhost:44303" }, "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true" }, "AuthServer": { "Authority": "https://localhost:44301" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json index 9ee790cc41..6a2d586b0e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/appsettings.json @@ -1,7 +1,7 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true", - "MyProjectName": "Server=localhost;Database=MyProjectName_Module;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true", + "MyProjectName": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Module;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json index 84503601a5..ea636d00ad 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/appsettings.json @@ -1,7 +1,7 @@ { "AppSelfUrl": "https://localhost:44301/", "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Main;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Redis": { "Configuration": "127.0.0.1" diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json index 9536f7781f..e081a57a67 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/appsettings.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "Default": "Server=localhost;Database=MyProjectName_Unified;Trusted_Connection=True;MultipleActiveResultSets=true" + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProjectName_Unified;Trusted_Connection=True;MultipleActiveResultSets=true" } } \ No newline at end of file From d7c9a6044c32b7b20232a76c5e98b9d874c79cd7 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Mon, 25 Nov 2019 09:46:21 +0300 Subject: [PATCH 32/75] fix(theme-shared): breadcrumb type error --- .../core/src/lib/states/config.state.ts | 164 ++++++++---------- .../breadcrumb/breadcrumb.component.ts | 29 ++-- .../lib/tests/breadcrumb.component.spec.ts | 15 ++ 3 files changed, 105 insertions(+), 103 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 381dc3e0f6..e18693ccb7 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -26,12 +26,9 @@ export class ConfigState { } static getOne(key: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - return state[key]; - }, - ); + const selector = createSelector([ConfigState], (state: Config.State) => { + return state[key]; + }); return selector; } @@ -45,87 +42,71 @@ export class ConfigState { throw new Error('The argument must be a dot string or an string array.'); } - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - return (keys as string[]).reduce((acc, val) => { - if (acc) { - return acc[val]; - } - - return undefined; - }, state); - }, - ); + const selector = createSelector([ConfigState], (state: Config.State) => { + return (keys as string[]).reduce((acc, val) => { + if (acc) { + return acc[val]; + } + + return undefined; + }, state); + }); return selector; } - static getRoute(path?: string, name?: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - const { flattedRoutes } = state; - return (flattedRoutes as ABP.FullRoute[]).find(route => { - if (path && route.path === path) { - return route; - } else if (name && route.name === name) { - return route; - } - }); - }, - ); + static getRoute(path?: string, name?: string, url?: string) { + const selector = createSelector([ConfigState], (state: Config.State) => { + const { flattedRoutes } = state; + return (flattedRoutes as ABP.FullRoute[]).find(route => { + if (path && route.path === path) { + return route; + } else if (name && route.name === name) { + return route; + } else if (url && route.url === url) { + return route; + } + }); + }); return selector; } static getApiUrl(key?: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State): string => { - return state.environment.apis[key || 'default'].url; - }, - ); + const selector = createSelector([ConfigState], (state: Config.State): string => { + return state.environment.apis[key || 'default'].url; + }); return selector; } static getSetting(key: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - return snq(() => state.setting.values[key]); - }, - ); + const selector = createSelector([ConfigState], (state: Config.State) => { + return snq(() => state.setting.values[key]); + }); return selector; } static getSettings(keyword?: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - if (keyword) { - const keys = snq(() => Object.keys(state.setting.values).filter(key => key.indexOf(keyword) > -1), []); - - if (keys.length) { - return keys.reduce((acc, key) => ({ ...acc, [key]: state.setting.values[key] }), {}); - } + const selector = createSelector([ConfigState], (state: Config.State) => { + if (keyword) { + const keys = snq(() => Object.keys(state.setting.values).filter(key => key.indexOf(keyword) > -1), []); + + if (keys.length) { + return keys.reduce((acc, key) => ({ ...acc, [key]: state.setting.values[key] }), {}); } + } - return snq(() => state.setting.values, {}); - }, - ); + return snq(() => state.setting.values, {}); + }); return selector; } static getGrantedPolicy(key: string) { - const selector = createSelector( - [ConfigState], - (state: Config.State): boolean => { - if (!key) return true; - return snq(() => state.auth.grantedPolicies[key], false); - }, - ); + const selector = createSelector([ConfigState], (state: Config.State): boolean => { + if (!key) return true; + return snq(() => state.auth.grantedPolicies[key], false); + }); return selector; } @@ -141,47 +122,44 @@ export class ConfigState { if (!key) key = ''; const keys = key.split('::') as string[]; - const selector = createSelector( - [ConfigState], - (state: Config.State) => { - if (!state.localization) return defaultValue || key; - - const { defaultResourceName } = state.environment.localization; - if (keys[0] === '') { - if (!defaultResourceName) { - throw new Error( - `Please check your environment. May you forget set defaultResourceName? + const selector = createSelector([ConfigState], (state: Config.State) => { + if (!state.localization) return defaultValue || key; + + const { defaultResourceName } = state.environment.localization; + if (keys[0] === '') { + if (!defaultResourceName) { + throw new Error( + `Please check your environment. May you forget set defaultResourceName? Here is the example: { production: false, localization: { defaultResourceName: 'MyProjectName' } }`, - ); - } - - keys[0] = snq(() => defaultResourceName); + ); } - let localization = (keys as any).reduce((acc, val) => { - if (acc) { - return acc[val]; - } - - return undefined; - }, state.localization.values); + keys[0] = snq(() => defaultResourceName); + } - interpolateParams = interpolateParams.filter(params => params != null); - if (localization && interpolateParams && interpolateParams.length) { - interpolateParams.forEach(param => { - localization = localization.replace(/[\'\"]?\{[\d]+\}[\'\"]?/, param); - }); + let localization = (keys as any).reduce((acc, val) => { + if (acc) { + return acc[val]; } - if (typeof localization !== 'string') localization = ''; - return localization || defaultValue || key; - }, - ); + return undefined; + }, state.localization.values); + + interpolateParams = interpolateParams.filter(params => params != null); + if (localization && interpolateParams && interpolateParams.length) { + interpolateParams.forEach(param => { + localization = localization.replace(/[\'\"]?\{[\d]+\}[\'\"]?/, param); + }); + } + + if (typeof localization !== 'string') localization = ''; + return localization || defaultValue || key; + }); return selector; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts index 90b49e8efb..7e6beb162a 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -16,21 +16,30 @@ export class BreadcrumbComponent implements OnInit { ngOnInit(): void { this.show = !!this.store.selectSnapshot(state => state.LeptonLayoutState); + if (this.show) { + const splittedUrl = this.router.url.split('/').filter(chunk => chunk); - const splittedUrl = this.router.url.split('/').filter(chunk => chunk); + const currentUrl: ABP.FullRoute = + this.store.selectSnapshot(ConfigState.getRoute(splittedUrl[0])) || + this.store.selectSnapshot(ConfigState.getRoute(null, null, this.router.url)); - const currentUrl: ABP.FullRoute = this.store.selectSnapshot(ConfigState.getRoute(splittedUrl[0])); - this.segments.push(currentUrl.name); + if (!currentUrl) { + this.show = false; + return; + } + + this.segments.push(currentUrl.name); - if (splittedUrl.length > 1) { - const [, ...arr] = splittedUrl; + if (splittedUrl.length > 1) { + const [, ...arr] = splittedUrl; - let childRoute: ABP.FullRoute = currentUrl; - for (let i = 0; i < arr.length; i++) { - const element = arr[i]; - childRoute = childRoute.children.find(child => child.path === element); + let childRoute: ABP.FullRoute = currentUrl; + for (let i = 0; i < arr.length; i++) { + const element = arr[i]; + childRoute = childRoute.children.find(child => child.path === element); - this.segments.push(childRoute.name); + this.segments.push(childRoute.name); + } } } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts index 85b3729bf7..bf93d11188 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts @@ -46,4 +46,19 @@ describe('BreadcrumbComponent', () => { expect(elements[1]).toHaveText('Identity'); expect(elements[2]).toHaveText('Users'); }); + + it('should not display the breadcrumb', () => { + const router = spectator.get(Router); + (router as any).url = '/identity/users'; + spectator.detectChanges(); + expect(spectator.query('ol.breadcrumb')).toBeFalsy(); + }); + + it('should not display the breadcrumb when abp route not found', () => { + const router = spectator.get(Router); + (router as any).url = '/identity/users'; + store.selectSnapshot.mockReturnValueOnce({ LeptonLayoutState: {} }); + spectator.detectChanges(); + expect(spectator.query('ol.breadcrumb')).toBeFalsy(); + }); }); From 8488b7adad088ba9728936ed97c183c78c1f1239 Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Mon, 25 Nov 2019 10:00:44 +0300 Subject: [PATCH 33/75] Create labeler.yml --- .github/workflows/labeler.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/labeler.yml diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..3f1b8ad3a1 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,11 @@ +name: "Pull Request Labeler" +on: + pull_request: + branches: + - master + - dev +jobs: + angular-label: + runs-on: ubuntu-18.04 + steps: + - uses: actions/labeler@v2 From 42532e1f68ba9943b0ebb2ff4aeefedccd072881 Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Mon, 25 Nov 2019 10:01:10 +0300 Subject: [PATCH 34/75] Create labeler.yml --- .github/labeler.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/labeler.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..738b727317 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,4 @@ +ui-angular: + - npm/ng-packs/**/* + - templates/app/angular/**/* + - templates/module/angular/**/* From 4a2f7e1eccdbd5c77f13a20e087805d8f0132382 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Mon, 25 Nov 2019 11:49:31 +0300 Subject: [PATCH 35/75] fix(theme-shared): bread crumb type error --- .../components/breadcrumb/breadcrumb.component.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts index 7e6beb162a..ae7a589617 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -17,15 +17,17 @@ export class BreadcrumbComponent implements OnInit { ngOnInit(): void { this.show = !!this.store.selectSnapshot(state => state.LeptonLayoutState); if (this.show) { - const splittedUrl = this.router.url.split('/').filter(chunk => chunk); + let splittedUrl = this.router.url.split('/').filter(chunk => chunk); - const currentUrl: ABP.FullRoute = - this.store.selectSnapshot(ConfigState.getRoute(splittedUrl[0])) || - this.store.selectSnapshot(ConfigState.getRoute(null, null, this.router.url)); + let currentUrl: ABP.FullRoute = this.store.selectSnapshot(ConfigState.getRoute(splittedUrl[0])); if (!currentUrl) { - this.show = false; - return; + currentUrl = this.store.selectSnapshot(ConfigState.getRoute(null, null, this.router.url)); + splittedUrl = [this.router.url]; + if (!currentUrl) { + this.show = false; + return; + } } this.segments.push(currentUrl.name); From 383c4f6a29d2412e9225283b0c2f8d0e8db50936 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Mon, 25 Nov 2019 11:50:05 +0300 Subject: [PATCH 36/75] fix(theme-shared): modal animation and backdrop height --- .../lib/components/modal/modal.component.html | 58 ++++++++++--------- .../lib/components/modal/modal.component.ts | 4 +- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html index 9b712d7199..c3168bad92 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html @@ -1,30 +1,34 @@ - -