Browse Source

Merge branch 'dev' into issue-#3286

pull/18561/head
denizdemirkan 2 years ago
parent
commit
f0fdf2acfc
  1. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  2. 10
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  3. 24
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  4. 18
      docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md
  5. 2
      docs/en/Tutorials/Part-1.md
  6. 14
      docs/en/Tutorials/Part-10.md
  7. 55
      docs/en/Tutorials/Part-4.md
  8. 16
      docs/en/Tutorials/Part-6.md
  9. 52
      docs/en/Tutorials/Part-8.md
  10. 8
      docs/en/Tutorials/Part-9.md
  11. 130
      docs/en/UI/Angular/Authorization.md
  12. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs
  13. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs
  14. 33
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs
  15. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs
  16. 7
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml
  17. 151
      modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml
  18. 31
      modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css
  19. 1
      modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
  20. 2
      modules/openiddict/app/angular/package.json
  21. 2
      npm/ng-packs/package.json
  22. 40
      npm/ng-packs/packages/core/src/lib/abstracts/auth-error-filter.ts
  23. 3
      npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts
  24. 1
      npm/ng-packs/packages/core/src/lib/abstracts/index.ts
  25. 1
      npm/ng-packs/packages/core/src/lib/core.module.ts
  26. 54
      npm/ng-packs/packages/core/src/lib/models/auth-events.ts
  27. 11
      npm/ng-packs/packages/core/src/lib/models/auth.ts
  28. 1
      npm/ng-packs/packages/core/src/lib/models/index.ts
  29. 6
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  30. 1
      npm/ng-packs/packages/oauth/src/lib/services/index.ts
  31. 45
      npm/ng-packs/packages/oauth/src/lib/services/oauth-error-filter.service.ts
  32. 6
      npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts
  33. 21
      npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts
  34. 3
      npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts
  35. 100
      npm/scripts/change-package-version.ts
  36. 5
      npm/scripts/package.json
  37. 10
      npm/scripts/yarn.lock
  38. 6
      templates/app-nolayers/angular/angular.json
  39. 2
      templates/app-nolayers/angular/package.json
  40. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/Program.cs
  41. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Program.cs
  42. 6
      templates/app/angular/angular.json
  43. 2
      templates/app/angular/package.json
  44. 6
      templates/module/angular/angular.json

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -50,7 +50,7 @@
"AbpCommercialShortDescription": "ABP Commercial provides pre-built application modules, rapid application development tooling, professional UI themes, premium support and more.",
"LiveDemo": "Live Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> using your ABP account, <a href=\"{2}\">{3}</a> to abp.io <br/> or fill the form below to create a live demo now",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "There is already an account with the given email address: <b>{0}</b><br/> You can login with your account to proceed.",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "There is already an account with the given email address: <b>{0}</b><br/> You should login with your account to proceed.",
"GetLicence": "Get a License",
"Application": "Application",
"StartupTemplates": "Startup Templates",

10
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json

@ -844,6 +844,14 @@
"ComesWithTheSourceCode_Description": "Mobil uygulamalar kaynak koduyla birlikte sağlanır. Marka yönergelerini karşılamak için uygulamalarınızın UX/UI'sini kolayca özelleştirin.",
"MultipleOrganizationInfo": "Tüm Organizasyonlarınızı Görün",
"PaymentFailedInfo": "Üzgünüz, Ödeme başarısız oldu! Bu hata, yatersiz bakiye, yanlış kredi kartı numarası veya yanlış PIN numarasından dolayı olabilir.",
"UsedPayment": "Bu ödeme zaten kullanımda."
"UsedPayment": "Bu ödeme zaten kullanımda.",
"TestimonialText": "Referans Yazınız",
"Position": "Poziyonunuz",
"ExperienceYear": "Yazılım Sektöründeki Tecrübeniz (Yıl)",
"Select": "Seçiniz",
"TestimonialTitle": "Referans",
"TestimonialInfo": "Düşüncelerinizi Paylaşın",
"Share": "Paylaş",
"YouAreNotAuthorizedToWriteTestimonial" : "Referansınızı paylaşabilmeniz için giriş yapmanız gerekmektedir"
}
}

24
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -440,7 +440,29 @@
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically.",
"VideosLoginAndRegisterMessage": "To be able to watch videos, you must sign in.",
"Filter": "Filter",
"VideoCourses": "Video Courses"
"VideoCourses": "Video Courses",
"TestimonialText": "Your testimonial",
"Position": "Position",
"ExperienceYear": "Years of Experience",
"FullName": "Full Name",
"CompanySize": "Company Size",
"Image": "Your profile picture",
"TestimonialTitle": "Let's hear your testimonial",
"TestimonialInfo": "What our customers say matters! Tell us about your experience with our product and service.",
"Country": "Country",
"TestimonialTextPlaceholder": "Write a brief story about how ABP helped you build and deliver your project. ",
"PositionPlaceholder": "Your position at your company.",
"SelectExperienceYearPlaceholder": "How many years have you been in software stuff",
"FullNamePlaceholder": "Your full name.",
"CompanyNamePlaceholder": "Your company name.",
"SelectCompanySizePlaceholder": "Employee count",
"ImagePlaceholder": "Your image.",
"SelectCountryPlaceholder": "Your country.",
"YouAreNotAuthorizedToWriteTestimonial": "To be able to write testimonial letter, you must be sign in.",
"UnAuthorizeTestimonialInfo": "If you want to share your opinion, you must be <a id='signin-btn'>sign in</a>",
"TheFileIsTooLargeForImage": "Your profile picture cannot be more than 1 MB",
"ThisExtensionIsNotAllowedForImage": "This extension is not allowed.",
"FileUploadError": "File upload error"
}
}

18
docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md

@ -2,7 +2,7 @@
A new .NET version was released on November 14, 2023 and ABP 8.0 RC.1 shipped based on .NET 8.0 just after Microsoft's .NET 8.0 release. Therefore, it's a good time to see what we need to do to upgrade our existing projects to .NET 8.0.
Despite all the related dependency upgrades and changes made on ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections.
Despite all the related dependency upgrades and changes made on the ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections.
## Installing the .NET 8.0 SDK
@ -52,7 +52,7 @@ For example, you can update the ASP.NET Core image as follows:
```diff
- FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0
```
You can check the related images from Docker Hub and update them accordingly:
@ -63,22 +63,28 @@ You can check the related images from Docker Hub and update them accordingly:
## Upgrading Your Existing Projects to ABP 8.0
Updating your application to ABP 8.0 is pretty straight-forward. You first need to upgrade the ABP CLI to version `8.0.0-rc.1` using a command line terminal:
Updating your application to ABP 8.0 is pretty straight-forward. You first need to upgrade the ABP CLI to version `8.0.0` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 8.0.0-rc.1
dotnet tool update Volo.Abp.Cli -g --version 8.0.0
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 8.0.0-rc.1
dotnet tool install Volo.Abp.Cli -g --version 8.0.0
````
Then, you can use the `abp update` command to update all the ABP related NuGet and NPM packages in your solution:
```bash
abp update --version 8.0.0-rc.1
abp update --version 8.0.0
```
Also, if you are using ABP Commercial, you can update the ABP Suite version with the following command:
```bash
abp suite update --version 8.0.0
```
After that, you need to check the migration guide documents, listed below:

2
docs/en/Tutorials/Part-1.md

@ -368,7 +368,7 @@ public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;

14
docs/en/Tutorials/Part-10.md

@ -614,19 +614,19 @@ using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
private readonly IAuthorAppService _authorAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
_authorAppService = GetRequiredService<IAuthorAppService>();
@ -643,7 +643,7 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
//Assert
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "1984" &&
b.AuthorName == "George Orwell");
b.AuthorName == "George Orwell");
}
[Fact]
@ -788,7 +788,7 @@ public class CreateModalModel : BookStorePageModel
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;
@ -871,7 +871,7 @@ public class EditModalModel : BookStorePageModel
[Required]
[StringLength(128)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public BookType Type { get; set; } = BookType.Undefined;

55
docs/en/Tutorials/Part-4.md

@ -82,19 +82,18 @@ using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
}
@ -114,6 +113,41 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
}
````
{{if DB == "EF"}}
Add a new implementation class of `BookAppService_Tests` class, named `EfCoreBookAppService_Tests` in the `EntityFrameworkCore\Applications\Books` namespace (folder) of the `Acme.BookStore.EntityFrameworkCore.Tests` project:
````csharp
using Acme.BookStore.Books;
using Xunit;
namespace Acme.BookStore.EntityFrameworkCore.Applications.Books;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class EfCoreBookAppService_Tests : BookAppService_Tests<BookStoreEntityFrameworkCoreTestModule>
{
}
````
{{end}}
{{if DB == "Mongo"}}
Add a new implementation class of `BookAppService_Tests` class, named `MongoDBBookAppService_Tests` in the `MongoDb\Applications\Books` namespace (folder) of the `Acme.BookStore.MongoDB.Tests` project:
````csharp
using Acme.BookStore.MongoDB;
using Acme.BookStore.Books;
using Xunit;
namespace Acme.BookStore.MongoDb.Applications.Books;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class MongoDBBookAppService_Tests : BookAppService_Tests<BookStoreMongoDbTestModule>
{
}
````
{{end}}
* `Should_Get_List_Of_Books` test simply uses `BookAppService.GetListAsync` method to get and check the list of books.
* We can safely check the book "1984" by its name, because we know that this books is available in the database since we've added it in the seed data.
@ -174,19 +208,18 @@ using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class BookAppService_Tests : BookStoreApplicationTestBase
public abstract class BookAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IBookAppService _bookAppService;
public BookAppService_Tests()
protected BookAppService_Tests()
{
_bookAppService = GetRequiredService<IBookAppService>();
}
@ -203,7 +236,7 @@ public class BookAppService_Tests : BookStoreApplicationTestBase
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "1984");
}
[Fact]
public async Task Should_Create_A_Valid_Book()
{

16
docs/en/Tutorials/Part-6.md

@ -75,9 +75,9 @@ public class Author : FullAuditedAggregateRoot<Guid>
internal Author(
Guid id,
[NotNull] string name,
string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
string? shortBio = null)
: base(id)
{
SetName(name);
@ -85,13 +85,13 @@ public class Author : FullAuditedAggregateRoot<Guid>
ShortBio = shortBio;
}
internal Author ChangeName([NotNull] string name)
internal Author ChangeName(string name)
{
SetName(name);
return this;
}
private void SetName([NotNull] string name)
private void SetName(string name)
{
Name = Check.NotNullOrWhiteSpace(
name,
@ -146,9 +146,9 @@ public class AuthorManager : DomainService
}
public async Task<Author> CreateAsync(
[NotNull] string name,
string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
string? shortBio = null)
{
Check.NotNullOrWhiteSpace(name, nameof(name));
@ -167,8 +167,8 @@ public class AuthorManager : DomainService
}
public async Task ChangeNameAsync(
[NotNull] Author author,
[NotNull] string newName)
Author author,
string newName)
{
Check.NotNull(author, nameof(author));
Check.NotNullOrWhiteSpace(newName, nameof(newName));

52
docs/en/Tutorials/Part-8.md

@ -123,12 +123,12 @@ public class CreateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
````
@ -146,12 +146,12 @@ public class UpdateAuthorDto
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
````
@ -481,18 +481,17 @@ Finally, we can write some tests for the `IAuthorAppService`. Add a new class, n
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Acme.BookStore.Authors;
{{if DB=="Mongo"}}
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
{{end}}
public class AuthorAppService_Tests : BookStoreApplicationTestBase
public abstract class AuthorAppService_Tests<TStartupModule> : BookStoreApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IAuthorAppService _authorAppService;
public AuthorAppService_Tests()
protected AuthorAppService_Tests()
{
_authorAppService = GetRequiredService<IAuthorAppService>();
}
@ -554,6 +553,41 @@ public class AuthorAppService_Tests : BookStoreApplicationTestBase
}
````
{{if DB == "EF"}}
Add a new implementation class of `AuthorAppService_Tests` class, named `EfCoreAuthorAppService_Tests` in the `EntityFrameworkCore\Applications\Authors` namespace (folder) of the `Acme.BookStore.EntityFrameworkCore.Tests` project:
````csharp
using Acme.BookStore.Authors;
using Xunit;
namespace Acme.BookStore.EntityFrameworkCore.Applications.Authors;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class EfCoreAuthorAppService_Tests : AuthorAppService_Tests<BookStoreEntityFrameworkCoreTestModule>
{
}
````
{{end}}
{{if DB == "Mongo"}}
Add a new implementation class of `AuthorAppService_Tests` class, named `MongoDBAuthorAppService_Tests` in the `MongoDb\Applications\Authors` namespace (folder) of the `Acme.BookStore.MongoDB.Tests` project:
````csharp
using Acme.BookStore.MongoDB;
using Acme.BookStore.Authors;
using Xunit;
namespace Acme.BookStore.MongoDb.Applications.Authors;
[Collection(BookStoreTestConsts.CollectionDefinitionName)]
public class MongoDBAuthorAppService_Tests : AuthorAppService_Tests<BookStoreMongoDbTestModule>
{
}
````
{{end}}
Created some tests for the application service methods, which should be clear to understand.
## The Next Part

8
docs/en/Tutorials/Part-9.md

@ -331,14 +331,14 @@ public class CreateModalModel : BookStorePageModel
{
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
}
```
@ -454,14 +454,14 @@ public class EditModalModel : BookStorePageModel
[Required]
[StringLength(AuthorConsts.MaxNameLength)]
public string Name { get; set; }
public string Name { get; set; } = string.Empty;
[Required]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
[TextArea]
public string ShortBio { get; set; }
public string? ShortBio { get; set; }
}
}
```

130
docs/en/UI/Angular/Authorization.md

@ -1,9 +1,9 @@
## Authorization in Angular UI
OAuth is preconfigured in Angular application templates. So, when you start a project using the CLI (or Suite, for that matter), authorization already works. ABP Angular UI packages are using [angular-oauth2-oidc library](https://github.com/manfredsteyer/angular-oauth2-oidc#logging-in) for managing OAuth in the Angular client.
OAuth is preconfigured in Angular application templates. So, when you start a project using the CLI (or Suite, for that matter), authorization already works. ABP Angular UI packages are using [angular-oauth2-oidc library](https://github.com/manfredsteyer/angular-oauth2-oidc#logging-in) for managing OAuth in the Angular client.
You can find **OAuth configuration** in the _environment.ts_ files.
### Authorization Code Flow
### Authorization Code Flow
```js
import { Config } from '@abp/ng.core';
@ -29,7 +29,6 @@ export const environment = {
This configuration results in an [OAuth authorization code flow with PKCE](https://tools.ietf.org/html/rfc7636).
According to this flow, the user is redirected to an external login page which is built with MVC. So, if you need **to customize the login page**, please follow [this community article](https://community.abp.io/articles/how-to-customize-the-login-page-for-mvc-razor-page-applications-9a40f3cd).
### Resource Owner Password Flow
If you have used the [Angular UI account module](./Account-Module) in your project, you can switch to the resource owner password flow by changing the OAuth configuration in the _environment.ts_ files as shown below:
@ -52,3 +51,128 @@ export const environment = {
```
According to this flow, the user is redirected to the login page in the account module.
### Error Filtering
In [AuthFlowStrategy](https://github.com/abpframework/abp/blob/21e70fd66154d4064d03b1a438f20a2e4318715e/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts#L24) class, there is a method called `listenToOauthErrors` that listens to `OAuthErrorEvent` errors. This method clears the localStorage for OAuth keys. However, in certain cases, we might want to skip this process. To achieve this, we can use the `AuthErrorFilterService`.
The `AuthErrorFilterService` is an abstract service that needs to be replaced with a custom implementation
> By default, this service is replaced in the `@abp/ng.oauth` package
**Usage**
1.Create an auth-filter.provider
```js
import { APP_INITIALIZER, inject } from '@angular/core';
import { AuthErrorFilter, AuthErrorEvent, AuthErrorFilterService } from '@abp/ng.core';
import { eCustomersAuthFilterNames } from '../enums';
export const CUSTOMERS_AUTH_FILTER_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureAuthFilter, multi: true },
];
type Reason = object & { error: { grant_type: string | undefined } };
function configureAuthFilter() {
const errorFilterService = inject(
AuthErrorFilterService<AuthErrorFilter<AuthErrorEvent>, AuthErrorEvent>,
);
const filter: AuthErrorFilter = {
id: eCustomersAuthFilterNames.LinkedUser,
executable: true,
execute: (event: AuthErrorEvent) => {
const { reason } = event;
const {
error: { grant_type },
} = <Reason>(reason || {});
return !!grant_type && grant_type === eCustomersAuthFilterNames.LinkedUser;
},
};
return () => errorFilterService.add(filter);
}
```
- `AuthErrorFilter:` is a model for filter object and it have 3 properties
- `id:` a unique key in the list for the filter object
- `executable:` a status for the filter object. If it's false then it won't work, yet it'll stay in the list
- `execute:` a function that stores the skip logic
2.Add to the FeatureConfigModule
```js
import { ModuleWithProviders, NgModule } from "@angular/core";
import { CUSTOMERS_AUTH_FILTER_PROVIDER } from "./providers/auth-filter.provider";
@NgModule()
export class CustomersConfigModule {
static forRoot(): ModuleWithProviders<CustomersConfigModule> {
return {
ngModule: CustomersConfigModule,
providers: [CUSTOMERS_AUTH_FILTER_PROVIDER],
};
}
}
```
Now it'll skip the clearing of OAuth storage keys for `LinkedUser` grant_type if any `OAuthErrorEvent` occurs
**Replace with custom implementation**
- Use the `AbstractAuthErrorFilter<T,E>` class for signs of process.
**Example**
`my-auth-error-filter.service.ts`
```js
import { Injectable, signal } from '@angular/core';
import { MyAuthErrorEvent } from 'angular-my-auth-oidc';
import { AbstractAuthErrorFilter, AuthErrorFilter } from '@abp/ng.core';
@Injectable({ providedIn: 'root' })
export class OAuthErrorFilterService extends AbstractAuthErrorFilter<
AuthErrorFilter<MyAuthErrorEvent>,
MyAuthErrorEvent
> {
protected readonly _filters = signal<Array<AuthErrorFilter<MyAuthErrorEvent>>>([]);
readonly filters = this._filters.asReadonly();
get(id: string): AuthErrorFilter<MyAuthErrorEvent> {
return this._filters().find(({ id: _id }) => _id === id);
}
add(filter: AuthErrorFilter<MyAuthErrorEvent>): void {
this._filters.update(items => [...items, filter]);
}
patch(item: Partial<AuthErrorFilter<MyAuthErrorEvent>>): void {
const _item = this.filters().find(({ id }) => id === item.id);
if (!_item) {
return;
}
Object.assign(_item, item);
}
remove(id: string): void {
const item = this.filters().find(({ id: _id }) => _id === id);
if (!item) {
return;
}
this._filters.update(items => items.filter(({ id: _id }) => _id !== id));
}
run(event: MyAuthErrorEvent): boolean {
return this.filters()
.filter(({ executable }) => !!executable)
.map(({ execute }) => execute(event))
.some(item => item);
}
}
```

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs

@ -73,6 +73,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
private readonly List<FileEntry> _entries;
private readonly bool _isMicroserviceServiceTemplate;
private readonly string _projectName;
protected bool CentralPackageManagement { get; }
protected ProjectReferenceReplacer(
ProjectBuildContext context,
@ -81,6 +82,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
_entries = context.Files;
_isMicroserviceServiceTemplate = MicroserviceServiceTemplateBase.IsMicroserviceServiceTemplate(context.Template?.Name);
_projectName = projectName;
CentralPackageManagement = context.Files.Any(x => x.Name.EndsWith("Directory.Packages.props"));
}
public void Run()
@ -165,7 +167,7 @@ public class ProjectReferenceReplaceStep : ProjectBuildPipelineStep
includeAttr.Value = ConvertToNugetReference(oldNodeIncludeValue);
newNode.Attributes.Append(includeAttr);
var versionAttr = doc.CreateAttribute("Version");
var versionAttr = doc.CreateAttribute(CentralPackageManagement ? "VersionOverride" : "Version");
versionAttr.Value = _nugetPackageVersion;
newNode.Attributes.Append(versionAttr);
return newNode;

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RandomizeAuthServerPassPhraseStep.cs

@ -12,6 +12,8 @@ public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep
private const string LocalhostPfx = "localhost.pfx -p 00000000-0000-0000-0000-000000000000";
private const string DotnetDevCerts = "openiddict.pfx -p 00000000-0000-0000-0000-000000000000";
private const string ProductionEncryptionAndSigningCertificate = "AddProductionEncryptionAndSigningCertificate(\"openiddict.pfx\", \"00000000-0000-0000-0000-000000000000\");";
private const string ReadmeCallout = "`00000000-0000-0000-0000-000000000000`";
private readonly static string RandomPassword = Guid.NewGuid().ToString("D");
public readonly static string RandomOpenIddictPassword = Guid.NewGuid().ToString("D");
@ -59,6 +61,13 @@ public class RandomizeAuthServerPassPhraseStep : ProjectBuildPipelineStep
RandomOpenIddictPassword));
}
if (lines[i].Contains(ReadmeCallout))
{
lines[i] = lines[i].Replace(ReadmeCallout,
ReadmeCallout.Replace(DefaultPassword,
RandomOpenIddictPassword));
}
if (lines[i].Contains(ProductionEncryptionAndSigningCertificate))
{
lines[i] = lines[i].Replace(ProductionEncryptionAndSigningCertificate,

33
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs

@ -12,7 +12,6 @@ public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
RemoveUnnecessaryDbMigratorClients(context);
RemoveUnnecessaryHttpApiHostPorts(context);
}
@ -66,36 +65,4 @@ public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep
httpApiHostAppSettings.SetLines(newlines);
}
private static void RemoveUnnecessaryDbMigratorClients(ProjectBuildContext context)
{
var dbMigratorAppSettings = context.Files
.FirstOrDefault(f =>
f.Name.Contains("MyCompanyName.MyProjectName.DbMigrator") && f.Name.EndsWith("appsettings.json"));
if (dbMigratorAppSettings == null)
{
return;
}
var appSettingsJsonObject = JObject.Parse(dbMigratorAppSettings.Content);
var authServerJsonObject = (JObject)appSettingsJsonObject?["IdentityServer"] ?? (JObject)appSettingsJsonObject["OpenIddict"];
var clientsJsonObject = (JObject)authServerJsonObject?["Clients"] ?? (JObject)authServerJsonObject?["Applications"];
if (clientsJsonObject == null)
{
return;
}
if (context.BuildArgs.UiFramework != UiFramework.Blazor)
{
clientsJsonObject.Remove("MyProjectName_Blazor");
}
if (!context.BuildArgs.PublicWebSite)
{
clientsJsonObject.Remove("MyProjectName_Web_Public");
}
dbMigratorAppSettings.SetContent(appSettingsJsonObject.ToString(Formatting.Indented));
}
}

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxying/CSharp/CSharpServiceProxyGenerator.cs

@ -220,7 +220,7 @@ public class CSharpServiceProxyGenerator : ServiceProxyGeneratorBase<CSharpServi
}
classTemplate.Replace($"{UsingPlaceholder}", string.Join(Environment.NewLine, classUsingNamespaceList.Distinct().OrderBy(x => x).Select(x => x)));
classTemplate.Replace($"{Environment.NewLine}{Environment.NewLine} {MethodPlaceholder}", string.Empty);
classTemplate.Replace($"{Environment.NewLine}{Environment.NewLine} {MethodPlaceholder}", string.Empty).Replace(MethodPlaceholder, string.Empty);
filePath = Path.Combine(args.WorkDirectory, folder, $"{clientProxyName}.Generated.cs");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));

7
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml

@ -456,14 +456,9 @@ else
var post = Model.PostsList[index];
<div class="post-item">
<div class="post-type-cont">
<a href="/members/@Model.Post.Writer.UserName" class="text-decoration-none">
<img gravatar-email="@Model.Post.Writer.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
</a>
<span class="post-type">
<i class="fas fa-pen-nib"></i>
@L["Blog"].Value.ToUpper()
</span>
</a>
</div>
<div class="post-detail-cont">
<div class="post-info fs-12 mb-2">

151
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml

@ -26,73 +26,81 @@
<div class="col-md-4 mb-5 mb-md-0">
<div class="card h-auto member-profile-info">
<div class="card-body">
<div class="d-inline-block position-relative">
<img gravatar-email="@Model.User.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
</div>
@if (Model.User.Name != null && Model.User.Surname != null)
{
<h2 class="m-1">@Model.User.Name @Model.User.Surname</h2>
}
@if (Model.User.Company != null)
{
<h4 class="m-2">@Model.User.Company</h4>
}
@if (Model.User.JobTitle != null)
{
<h4>@Model.User.JobTitle</h4>
}
<small class="d-block">@L["UserName"].Value.ToUpper()</small>
<h5>@Model.User.UserName</h5>
@if (Model.User.WebSite != null)
{
<small>@L["PersonalWebsite"].Value.ToUpper()</small>
<h5>
<a href="@Model.User.WebSite">@Model.User.WebSite</a>
</h5>
}
@if (Model.User.Twitter != null || Model.User.Github != null || Model.User.Linkedin != null)
{
<small>@L["Social"].Value.ToUpper()</small>
<ul class="d-flex justify-content-center">
@if (Model.User.Twitter != null)
{
<li class="mx-3">
<a href="https://twitter.com/@Model.User.Twitter">
<div class="icon-twitter-v1"></div>
</a>
</li>
}
@if (Model.User.Github != null)
{
<li class="mx-3">
<a href="https://github.com/@Model.User.Github">
<div class="icon-github large bg-dark"></div>
</a>
</li>
}
@if (Model.User.Linkedin != null)
{
<li class="mx-3">
<a href="@Model.User.Linkedin">
<div class="icon-linkedin-v1"></div>
</a>
</li>
}
</ul>
}
@if (Model.User.Biography != null)
{
<div class="m-2 mt-4">
<small>@L["Biography"].Value.ToUpper()</small>
<p>@Model.User.Biography</p>
<div class="text-center">
<div class="position-relative d-inline-block">
<img gravatar-email="@Model.User.Email" default-image="Identicon" id="profile-photo" class="post-member-img rounded-circle d-block mx-auto" />
</div>
}
</div>
<div class="d-inline-block align-top text-left ml-3">
@if (Model.User.Name != null && Model.User.Surname != null)
{
<h2 class="m-0 custom-heading">
@Model.User.Name @Model.User.Surname
</h2>}
@if (Model.User.Company != null)
{
<h4 class="m-0 company-jobtitle">@Model.User.Company</h4>
}
@if (Model.User.JobTitle != null)
{
<h4 class="company-jobtitle">@Model.User.JobTitle</h4>
}
<small class="d-block custom-small">@L["UserName"].Value.ToUpper()</small>
<h5 class="username-website">@Model.User.UserName</h5>
@if (Model.User.WebSite != null)
{
<small class="custom-small">@L["PersonalWebsite"].Value.ToUpper()</small>
<h5 class="username-website">
<a href="@Model.User.WebSite">@Model.User.WebSite</a>
</h5>
}
@if (Model.User.Twitter != null || Model.User.Github != null || Model.User.Linkedin != null)
{
<small>@L["Social"].Value.ToUpper()</small>
<ul class="d-flex list-unstyled mb-0">
@if (Model.User.Twitter != null)
{
<li class="mx-3">
<a href="https://twitter.com/@Model.User.Twitter">
<div class="icon-twitter-v1"></div>
</a>
</li>
}
@if (Model.User.Github != null)
{
<li class="mx-3">
<a href="https://github.com/@Model.User.Github">
<div class="icon-github large bg-dark"></div>
</a>
</li>
}
@if (Model.User.Linkedin != null)
{
<li class="mx-3">
<a href="@Model.User.Linkedin">
<div class="icon-linkedin-v1"></div>
</a>
</li>
}
</ul>
}
@if (Model.User.Biography != null)
{
<div class="m-0 mt-4">
<small>@L["Biography"].Value.ToUpper()</small>
<p>@Model.User.Biography</p>
</div>
}
</div>
</div>
</div>
</div>
<div class="col-md-8">
@ -106,16 +114,13 @@
@foreach (var post in Model.Posts)
{
<div class="post-item">
<div class="post-type-cont">
<div class="post-type-cont" style="text-align: center;">
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
<img gravatar-email="@Model.User.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
<img gravatar-email="@Model.User.Email" default-image="Identicon" id="gravatar" class="post-member-img rounded-circle d-block" />
</a>
<span class="post-type">
<i class="fas fa-pen-nib"></i>
@L["Blog"].Value.ToUpper()
</span>
</div>
<div class="post-detail-cont">
<div class="post-info fs-12 mb-2">
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
@ -203,10 +208,6 @@
<a href="@Model.GetMemberProfileUrl(Model.User)" class="text-decoration-none">
<img gravatar-email="@Model.User.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
</a>
<span class="post-type">
<i class="fas fa-pen-nib"></i>
@L["Blog"].Value.ToUpper()
</span>
</div>
<div class="post-detail-cont">
<div class="post-info fs-12 mb-2">

31
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css

@ -1,3 +1,32 @@
.post-desc {
.post-desc {
overflow-wrap: break-word;
}
#gravatar {
margin: 10px;
}
#profile-photo {
margin-bottom: 10px;
}
.custom-heading {
margin-bottom: 20px !important;
font-size: 28px !important;
}
.company-jobtitle {
font-size: 16px !important;
font-weight: 300 !important;
margin-bottom: 20px;
}
.username-website {
font-size: 16px !important;
font-weight: 400 !important;
margin-bottom: 20px;
}
.custom-small {
display: block;
}

1
modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs

@ -140,6 +140,7 @@ public class IdentityUserAppService : IdentityAppServiceBase, IIdentityUserAppSe
[Authorize(IdentityPermissions.Users.Update)]
public virtual async Task UpdateRolesAsync(Guid id, IdentityUserUpdateRolesDto input)
{
await IdentityOptions.SetAsync();
var user = await UserManager.GetByIdAsync(id);
(await UserManager.SetRolesAsync(user, input.RoleNames)).CheckErrors();
await UserRepository.UpdateAsync(user);

2
modules/openiddict/app/angular/package.json

@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~8.0.0",
"@abp/ng.tenant-management": "~8.0.0",
"@abp/ng.theme.shared": "~8.0.0",
"@abp/ng.theme.lepton-x": "~3.0.0-rc.1",
"@abp/ng.theme.lepton-x": "~3.0.0",
"@angular/animations": "^15.0.1",
"@angular/common": "^15.0.1",
"@angular/compiler": "^15.0.1",

2
npm/ng-packs/package.json

@ -44,7 +44,7 @@
},
"private": true,
"devDependencies": {
"@abp/ng.theme.lepton-x": "~3.0.0-rc.1",
"@abp/ng.theme.lepton-x": "~3.0.0",
"@abp/utils": "~8.0.0",
"@angular-devkit/build-angular": "~17.0.0",
"@angular-devkit/core": "~17.0.0",

40
npm/ng-packs/packages/core/src/lib/abstracts/auth-error-filter.ts

@ -0,0 +1,40 @@
import { AuthErrorEvent, AuthErrorFilter } from '../models';
export abstract class AbstractAuthErrorFilter<T, E> {
abstract get(id: string): T;
abstract add(filter: T): void;
abstract patch(item: Partial<T>): void;
abstract remove(id: string): void;
abstract run(event: E): boolean;
}
export class AuthErrorFilterService<
T = AuthErrorFilter,
E = AuthErrorEvent,
> extends AbstractAuthErrorFilter<T, E> {
private warningMessage() {
console.error('You should add @abp/ng-oauth packages or create your own auth packages.');
}
get(id: string): T {
this.warningMessage();
throw new Error('not implemented');
}
add(filter: T): void {
this.warningMessage();
}
patch(item: Partial<T>): void {
this.warningMessage();
}
remove(id: string): void {
this.warningMessage();
}
run(event: E): boolean {
this.warningMessage();
throw new Error('not implemented');
}
}

3
npm/ng-packs/packages/core/src/lib/abstracts/auth.service.ts

@ -33,9 +33,8 @@ export class AuthService implements IAuthService {
navigateToLogin(queryParams?: Params): void {}
get isInternalAuth() {
get isInternalAuth(): boolean {
throw new Error('not implemented');
return false;
}
get isAuthenticated(): boolean {

1
npm/ng-packs/packages/core/src/lib/abstracts/index.ts

@ -3,3 +3,4 @@ export * from './ng-model.component';
export * from './auth.guard';
export * from './auth.service';
export * from './auth-response.model';
export * from './auth-error-filter';

1
npm/ng-packs/packages/core/src/lib/core.module.ts

@ -187,6 +187,7 @@ export class CoreModule {
provide: OTHERS_GROUP,
useValue: options.othersGroup || 'AbpUi::OthersGroup',
},
AuthErrorFilterService,
IncludeLocalizationResourcesProvider,
{
provide: DYNAMIC_LAYOUTS_TOKEN,

54
npm/ng-packs/packages/core/src/lib/models/auth-events.ts

@ -0,0 +1,54 @@
export type EventType =
| 'discovery_document_loaded'
| 'jwks_load_error'
| 'invalid_nonce_in_state'
| 'discovery_document_load_error'
| 'discovery_document_validation_error'
| 'user_profile_loaded'
| 'user_profile_load_error'
| 'token_received'
| 'token_error'
| 'code_error'
| 'token_refreshed'
| 'token_refresh_error'
| 'silent_refresh_error'
| 'silently_refreshed'
| 'silent_refresh_timeout'
| 'token_validation_error'
| 'token_expires'
| 'session_changed'
| 'session_error'
| 'session_terminated'
| 'session_unchanged'
| 'logout'
| 'popup_closed'
| 'popup_blocked'
| 'token_revoke_error';
export abstract class AuthEvent {
constructor(public readonly type: EventType) {
this.type = type;
}
}
export class AuthSuccessEvent extends AuthEvent {
constructor(public readonly type: EventType, public readonly info?: any) {
super(type);
}
}
export class AuthInfoEvent extends AuthEvent {
constructor(public readonly type: EventType, public readonly info?: any) {
super(type);
}
}
export class AuthErrorEvent extends AuthEvent {
constructor(
public readonly type: EventType,
public readonly reason: object,
public readonly params?: object,
) {
super(type);
}
}

11
npm/ng-packs/packages/core/src/lib/models/auth.ts

@ -1,5 +1,6 @@
import { UnaryFunction } from 'rxjs';
import { Injector } from '@angular/core';
import { UnaryFunction } from 'rxjs';
import { AuthErrorEvent } from './auth-events';
export interface LoginParams {
username: string;
@ -13,7 +14,13 @@ export type PipeToLoginFn = (
injector: Injector,
) => UnaryFunction<any, any>;
/**
* @deprecated The interface should not be used anymore.
* @deprecated The interface should not be used anymore.
*/
export type SetTokenResponseToStorageFn<T = any> = (tokenRes: T) => void;
export type CheckAuthenticationStateFn = (injector: Injector) => void;
export interface AuthErrorFilter<T = AuthErrorEvent> {
id: string;
executable: boolean;
execute: (event: T) => boolean;
}

1
npm/ng-packs/packages/core/src/lib/models/index.ts

@ -7,3 +7,4 @@ export * from './rest';
export * from './session';
export * from './utility';
export * from './auth';
export * from './auth-events';

6
npm/ng-packs/packages/oauth/src/lib/oauth.module.ts

@ -1,9 +1,11 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc';
import {
AbpLocalStorageService,
ApiInterceptor,
AuthErrorFilterService,
AuthGuard,
authGuard,
AuthService,
@ -11,9 +13,8 @@ import {
noop,
PIPE_TO_LOGIN_FN_KEY,
} from '@abp/ng.core';
import { AbpOAuthService } from './services';
import { AbpOAuthService, OAuthErrorFilterService } from './services';
import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { OAuthApiInterceptor } from './interceptors/api.interceptor';
import { AbpOAuthGuard, abpOAuthGuard } from './guards/oauth.guard';
import { NavigateToManageProfileProvider } from './providers';
@ -65,6 +66,7 @@ export class AbpOAuthModule {
},
OAuthModule.forRoot().providers as Provider[],
{ provide: OAuthStorage, useClass: AbpLocalStorageService },
{ provide: AuthErrorFilterService, useExisting: OAuthErrorFilterService },
],
};
}

1
npm/ng-packs/packages/oauth/src/lib/services/index.ts

@ -1 +1,2 @@
export * from './oauth.service';
export * from './oauth-error-filter.service';

45
npm/ng-packs/packages/oauth/src/lib/services/oauth-error-filter.service.ts

@ -0,0 +1,45 @@
import { Injectable, signal } from '@angular/core';
import { OAuthErrorEvent } from 'angular-oauth2-oidc';
import { AbstractAuthErrorFilter, AuthErrorFilter } from '@abp/ng.core';
@Injectable({ providedIn: 'root' })
export class OAuthErrorFilterService extends AbstractAuthErrorFilter<
AuthErrorFilter<OAuthErrorEvent>,
OAuthErrorEvent
> {
protected readonly _filters = signal<Array<AuthErrorFilter<OAuthErrorEvent>>>([]);
readonly filters = this._filters.asReadonly();
get(id: string): AuthErrorFilter<OAuthErrorEvent> {
return this._filters().find(({ id: _id }) => _id === id);
}
add(filter: AuthErrorFilter<OAuthErrorEvent>): void {
this._filters.update(items => [...items, filter]);
}
patch(item: Partial<AuthErrorFilter<OAuthErrorEvent>>): void {
const _item = this.filters().find(({ id }) => id === item.id);
if (!_item) {
return;
}
Object.assign(_item, item);
}
remove(id: string): void {
const item = this.filters().find(({ id: _id }) => _id === id);
if (!item) {
return;
}
this._filters.update(items => items.filter(({ id: _id }) => _id !== id));
}
run(event: OAuthErrorEvent): boolean {
return this.filters()
.filter(({ executable }) => !!executable)
.map(({ execute }) => execute(event))
.some(item => item);
}
}

6
npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts

@ -44,10 +44,10 @@ export class AbpOAuthService implements IAuthService {
}
logout(queryParams?: Params): Observable<any> {
if(!this.strategy){
return EMPTY
if (!this.strategy) {
return EMPTY;
}
return this.strategy.logout(queryParams);
}

21
npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts

@ -1,13 +1,16 @@
import { Injector } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { Params, Router } from '@angular/router';
import { Observable, of } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import {
AuthConfig,
OAuthErrorEvent,
OAuthService as OAuthService2,
OAuthStorage,
} from 'angular-oauth2-oidc';
import { Observable, of } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import {
AbpLocalStorageService,
ConfigStateService,
@ -17,9 +20,10 @@ import {
SessionStateService,
TENANT_KEY,
} from '@abp/ng.core';
import { clearOAuthStorage } from '../utils/clear-o-auth-storage';
import { oAuthStorage } from '../utils/oauth-storage';
import { HttpErrorResponse } from '@angular/common/http';
import { OAuthErrorFilterService } from '../services';
export abstract class AuthFlowStrategy {
abstract readonly isInternalAuth: boolean;
@ -34,6 +38,8 @@ export abstract class AuthFlowStrategy {
protected tenantKey: string;
protected router: Router;
protected readonly oAuthErrorFilterService: OAuthErrorFilterService;
abstract checkIfInternalAuth(queryParams?: Params): boolean;
abstract navigateToLogin(queryParams?: Params): void;
abstract logout(queryParams?: Params): Observable<any>;
@ -54,6 +60,7 @@ export abstract class AuthFlowStrategy {
this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {};
this.tenantKey = injector.get(TENANT_KEY);
this.router = injector.get(Router);
this.oAuthErrorFilterService = injector.get(OAuthErrorFilterService);
this.listenToOauthErrors();
}
@ -97,6 +104,7 @@ export abstract class AuthFlowStrategy {
if (redirect_uri && redirect_uri !== '/') {
return redirect_uri;
}
return '/';
}),
switchMap(redirectUri =>
@ -118,7 +126,12 @@ export abstract class AuthFlowStrategy {
this.oAuthService.events
.pipe(
filter(event => event instanceof OAuthErrorEvent),
tap(() => clearOAuthStorage()),
tap((err: OAuthErrorEvent) => {
const shouldSkip = this.oAuthErrorFilterService.run(err);
if (!shouldSkip) {
clearOAuthStorage();
}
}),
switchMap(() => this.configState.refreshAppState()),
)
.subscribe();

3
npm/ng-packs/packages/theme-shared/src/lib/constants/validation.ts

@ -18,4 +18,5 @@ export const DEFAULT_VALIDATION_BLUEPRINTS = {
passwordRequiresDigit: 'AbpIdentity::Volo.Abp.Identity:PasswordRequiresDigit',
passwordRequiresNonAlphanumeric: 'AbpIdentity::Volo.Abp.Identity:PasswordRequiresNonAlphanumeric',
usernamePattern: 'AbpIdentity::Volo.Abp.Identity:InvalidUserName[{{ actualValue }}]',
};
customMessage: '{{ customMessage }}'
};

100
npm/scripts/change-package-version.ts

@ -0,0 +1,100 @@
import glob from "glob";
import fse from "fs-extra";
import {program} from "commander";
(function findPackageJsonFiles() {
setupCommander();
const options = {
ignore: [
"../../**/node_modules/**",
"../../**/dist/**",
"../../**/build/**",
"../../**/scripts/**",
"../../**/wwwroot/**"
]
};
const workingDir = "../../";
glob(`${workingDir}**/package.json`, options, (err, files) => {
if (err) throw err;
const {packageName,targetVersion}= program.opts();
for (const file of files) {
readPackageJsonFile(file, packageName, targetVersion);
}
});
})();
function readPackageJsonFile(path, key, newVersion) {
const replace = (block, key, newVersion) => {
const founded = Object.keys(block).filter(x => x === key);
if (founded.length > 0) {
let value = block[key];
value = value.replace(semverRegex, newVersion);
return [true, {
...block,
[key]:value
}];
}
return [false, block];
};
fse.readJson(path, (err, packageObj) => {
if (err) throw err;
const { dependencies, peerDependencies, devDependencies } = packageObj;
const results = [];
let result = { ...packageObj };
if (dependencies) {
const [founded, d] = replace(dependencies, key, newVersion);
results.push(founded);
result = {
...result, dependencies: d
};
}
if (peerDependencies) {
const [founded, p] = replace(peerDependencies, key, newVersion);
results.push(founded);
result = {
...result, peerDependencies: p
};
}
if (devDependencies) {
const [founded, d] = replace(devDependencies, key, newVersion);
results.push(founded);
result = {
...result, devDependencies: d
};
}
const anyChanges = !results.some(x => x);
if (anyChanges) {
return;
}
console.log("changed", path);
writeFile(path, result);
}
)
;
}
export const semverRegex =
/\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+(?:\.[a-zA-Z0-9-]+)*)?(?:\+[a-zA-Z0-9]+(?:\.[a-zA-Z0-9-]+)*)?$/;
function writeFile(path, result) {
return fse.writeJson(path, result, { spaces: 2 });
}
function setupCommander() {
program
.option(
"-n, --packageName <packageName>",
"Package name"
)
.option(
"-v, --targetVersion <targetVersion>",
"Version number of the package"
);
program.parse(process.argv);
}

5
npm/scripts/package.json

@ -4,12 +4,13 @@
"description": "",
"scripts": {
"remove-lock-files": "yarn && ts-node -r tsconfig-paths/register remove-lock-files.ts",
"validate-versions": "yarn && ts-node -r tsconfig-paths/register validate-versions.ts"
"validate-versions": "yarn && ts-node -r tsconfig-paths/register validate-versions.ts",
"change-package-version": "ts-node -r tsconfig-paths/register change-package-version.ts -n @abp/ng.theme.lepton-x -v 3.0.0"
},
"dependencies": {
"axios": "^0.24.0",
"chalk": "^4.1.0",
"commander": "^8.3.0",
"commander": "^11.0.0",
"execa": "^5.1.1",
"fs-extra": "^9.0.1",
"glob": "^7.1.6",

10
npm/scripts/yarn.lock

@ -417,16 +417,16 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^11.0.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==
commander@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc"
integrity sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==
commander@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"

6
templates/app-nolayers/angular/angular.json

@ -147,10 +147,10 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "MyProjectName:build:production"
"buildTarget": "MyProjectName:build:production"
},
"development": {
"browserTarget": "MyProjectName:build:development"
"buildTarget": "MyProjectName:build:development"
}
},
"defaultConfiguration": "development"
@ -158,7 +158,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "MyProjectName:build"
"buildTarget": "MyProjectName:build"
}
},
"test": {

2
templates/app-nolayers/angular/package.json

@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~8.0.0",
"@abp/ng.tenant-management": "~8.0.0",
"@abp/ng.theme.shared": "~8.0.0",
"@abp/ng.theme.lepton-x": "~3.0.0-rc.1",
"@abp/ng.theme.lepton-x": "~3.0.0",
"@angular/animations": "~17.0.0",
"@angular/common": "~17.0.0",
"@angular/compiler": "~17.0.0",

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/Program.cs

@ -40,11 +40,11 @@ public class Program
builder.Host.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<MyProjectNameHostModule>();
if (IsMigrateDatabase(args))
{
builder.Services.AddDataMigrationEnvironment();
}
await builder.AddApplicationAsync<MyProjectNameHostModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/Program.cs

@ -40,11 +40,11 @@ public class Program
builder.Host.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<MyProjectNameHostModule>();
if (IsMigrateDatabase(args))
{
builder.Services.AddDataMigrationEnvironment();
}
await builder.AddApplicationAsync<MyProjectNameHostModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();

6
templates/app/angular/angular.json

@ -147,10 +147,10 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "MyProjectName:build:production"
"buildTarget": "MyProjectName:build:production"
},
"development": {
"browserTarget": "MyProjectName:build:development"
"buildTarget": "MyProjectName:build:development"
}
},
"defaultConfiguration": "development"
@ -158,7 +158,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "MyProjectName:build"
"buildTarget": "MyProjectName:build"
}
},
"test": {

2
templates/app/angular/package.json

@ -19,7 +19,7 @@
"@abp/ng.oauth": "~8.0.0",
"@abp/ng.setting-management": "~8.0.0",
"@abp/ng.tenant-management": "~8.0.0",
"@abp/ng.theme.lepton-x": "~3.0.0-rc.1",
"@abp/ng.theme.lepton-x": "~3.0.0",
"@abp/ng.theme.shared": "~8.0.0",
"@angular/animations": "~17.0.0",
"@angular/common": "~17.0.0",

6
templates/module/angular/angular.json

@ -145,10 +145,10 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "dev-app:build:production"
"buildTarget": "dev-app:build:production"
},
"development": {
"browserTarget": "dev-app:build:development"
"buildTarget": "dev-app:build:development"
}
},
"defaultConfiguration": "development"
@ -156,7 +156,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "dev-app:build"
"buildTarget": "dev-app:build"
}
},
"test": {

Loading…
Cancel
Save