diff --git a/.github/workflows/angular.yml b/.github/workflows/angular.yml index e42f3e58dd..ee66fbcf2c 100644 --- a/.github/workflows/angular.yml +++ b/.github/workflows/angular.yml @@ -10,11 +10,17 @@ on: branches: - 'rel-*' - 'dev' + types: + - opened + - synchronize + - reopened + - ready_for_review permissions: contents: read jobs: build-test-lint: + if: ${{ !github.event.pull_request.draft }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bc7364a7e5..dda9340d7d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -31,12 +31,18 @@ on: - 'templates/**/*.cshtml' - 'templates/**/*.csproj' - 'templates/**/*.razor' + types: + - opened + - synchronize + - reopened + - ready_for_review permissions: contents: read jobs: build-test: runs-on: windows-latest + if: ${{ !github.event.pull_request.draft }} steps: - uses: actions/checkout@v2 - uses: actions/setup-dotnet@master diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e3127f21b1..d1f6c0c503 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,26 +9,32 @@ on: push: branches: [dev, rel-*] paths: - - 'abp/**/*.js' - - 'abp/**/*.cs' - - 'abp/**/*.cshtml' - - 'abp/**/*.csproj' - - 'abp/**/*.razor' + - "abp/**/*.js" + - "abp/**/*.cs" + - "abp/**/*.cshtml" + - "abp/**/*.csproj" + - "abp/**/*.razor" pull_request: # The branches below must be a subset of the branches above branches: [dev] paths: - - 'abp/**/*.js' - - 'abp/**/*.cs' - - 'abp/**/*.cshtml' - - 'abp/**/*.csproj' - - 'abp/**/*.razor' + - "abp/**/*.js" + - "abp/**/*.cs" + - "abp/**/*.cshtml" + - "abp/**/*.csproj" + - "abp/**/*.razor" + types: + - opened + - synchronize + - reopened + - ready_for_review permissions: contents: read jobs: analyze: + if: ${{ !github.event.pull_request.draft }} permissions: actions: read # for github/codeql-action/init to get workflow details contents: read # for actions/checkout to fetch code @@ -41,48 +47,48 @@ jobs: matrix: # Override automatic language detection by changing the below list # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['csharp', 'javascript'] + language: ["csharp", "javascript"] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/image-compression.yml b/.github/workflows/image-compression.yml index 9cbaa00d90..4556622e4a 100644 --- a/.github/workflows/image-compression.yml +++ b/.github/workflows/image-compression.yml @@ -1,21 +1,26 @@ -name: Compress Images -on: - pull_request: - paths: - - '**.jpg' - - '**.jpeg' - - '**.png' - - '**.webp' -jobs: - build: - if: github.event.pull_request.head.repo.full_name == github.repository - name: calibreapp/image-actions - runs-on: ubuntu-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v2 - - - name: Compress Images - uses: calibreapp/image-actions@main - with: - githubToken: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file +name: Compress Images +on: + pull_request: + paths: + - "**.jpg" + - "**.jpeg" + - "**.png" + - "**.webp" + types: + - opened + - synchronize + - reopened + - ready_for_review +jobs: + build: + if: github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.draft + name: calibreapp/image-actions + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v2 + + - name: Compress Images + uses: calibreapp/image-actions@main + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 6583ae731f..e90d5b3897 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -73,6 +73,7 @@ "DeveloperFocused": "Developer Focused", "ShareYourExperiences": "Share your experiences with the ABP Framework", "LatestPosts": "Latest Posts", + "LatestVideos": "Latest Videos", "Views": "Views", "LearnLatestNewsAboutABPFramework": "Get information about happenings in ABP like new releases, free sources, posts, and more.", "DeveloperTools": "Developer Tools", @@ -98,6 +99,7 @@ "Logout": "Logout", "Home": "Home", "Posts": "Posts", + "Videos": "Videos", "JoinTheABPCommunity": "Join the ABP Community", "SubmitYourPost": "Submit Your Post", "Modules": "Modules", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json index c4aa5f4926..0711a49836 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json @@ -73,6 +73,7 @@ "DeveloperFocused": "以开发者为中心", "ShareYourExperiences": "分享您使用 ABP 框架的经验", "LatestPosts": "最新的帖子", + "LatestVideos": "最新的视频", "Views": "意见", "LearnLatestNewsAboutABPFramework": "获取有关 ABP 的最新相关信息,例如新版本、免费资源、帖子等。", "DeveloperTools": "开发者工具", @@ -98,6 +99,7 @@ "Logout": "登出", "Home": "主页", "Posts": "帖子", + "Videos": "视频", "JoinTheABPCommunity": "加入 ABP 社区", "SubmitYourPost": "提交您的帖子", "Modules": "模块", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index b8e8d9b135..34853aa258 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -185,6 +185,7 @@ "Layout_Title": "{0} | ABP Community", "Layout_MetaDescription": "ABP Community is an environment where people can share posts about ABP framework and follows the projects.", "Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community.", - "TagsInArticle": "Tags in article" + "TagsInArticle": "Tags in article", + "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "Explore the contents created by the core ABP team and the ABP community." } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index 2a5f9a2584..ac1619271b 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -378,6 +378,13 @@ "IntroducingTheSolution": "Introducing the eShopOnAbp Solution", "RunningTheSolution": "Running the Solution", "UnderstandingTheAuthenticationSystem": "Understanding the Authentication System", + "ExploringTheApplications": "Exploring the Applications", + "UnderstandingTheAPIGateways": "Understanding the API Gateways", + "DevelopingTheMicroservices": "Developing the Microservices", + "UnderstandingTheInfrastructure": "Understanding the Infrastructure", + "DiggingInTheUseCases": "Digging in the Use Cases", + "DeployingTheSolution": "Deploying the Solution", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "This book is in draft stage and is not completed yet.", "Authors": "Authors", "MicroserviceEBook": "Microservice E-Book", "SelectUITheme": "Select UI Theme", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json index 01fe9f8b7b..a4a6e142a9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json @@ -279,6 +279,7 @@ "SubscribeToNewsletter": "ABP.IO Platform'u ile ilgili yeni haberler, makaleler, teklifler ve daha fazlası gibi gelişmeler hakkında bilgi almak için bültene abone olun.", "FirstEdition": "İlk Baskı", "ThankYou": "Teşekkürler!", - "CheckboxMandatory": "Devam etmek için bunu kontrol etmeniz gerekiyor!" + "CheckboxMandatory": "Devam etmek için bunu kontrol etmeniz gerekiyor!", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "Bu kitap taslak aşamasındadır ve henüz tamamlanmamıştır." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index 9a1373f76b..d787594039 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -372,6 +372,7 @@ "MasteringAbpFramework_Book_What_You_Will_Learn_8": "使用 ABP 框架编写单元、集成和 UI 测试。", "MasteringAbpFramework_Book_WhoIsThisBookFor": "这本书是给谁看的", "MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "本书适用于希望学习软件架构和最佳实践的 Web 开发人员,以使用 Microsoft 技术和 ABP 框架构建\n 可维护的基于 Web 的解决方案。 C#\n 和 ASP.NET Core 的基本知识是开始阅读本书所必需的。", - "ComputersAndTechnology": "计算机与技术" + "ComputersAndTechnology": "计算机与技术", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "这本书正在草案阶段,还没有完成。" } } \ No newline at end of file diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 8dc6d425dc..7a5e59a62a 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -124,7 +124,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `--separate-auth-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side. * `--mobile` or `-m`: Specifies the mobile application framework. If not specified, no mobile application will be created. Available options: * `react-native`: React Native. - * `maui`: MAUI. + * `maui`: MAUI. This mobile option is only available for ABP Commercial. * `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers: * `ef`: Entity Framework Core. * `mongodb`: MongoDB. @@ -145,7 +145,8 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `mongodb`: MongoDB. * `--theme`: Specifes the theme. Default theme is `leptonx-lite`. Available themes: * `leptonx-lite`: [LeptonX Lite Theme](/Themes/LeptonXLite/mvc.md). - * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md). + * `basic`: [Basic Theme](/UI/AspNetCore/Basic-Theme.md). + * **`maui`**: .NET MAUI. A minimalist .NET MAUI application will be created if you specify this option. * `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory. * `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version. * `--preview`: Use latest preview version. @@ -161,6 +162,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample * `PostgreSQL` * `--local-framework-ref --abp-path`: Uses local projects references to the ABP framework instead of using the NuGet packages. This can be useful if you download the ABP Framework source code and have a local reference to the framework from your application. * `--no-random-port`: Uses template's default ports. +* `--skip-installing-libs` or `-sib`: Skip installing client side packages. See some [examples for the new command](CLI-New-Command-Samples.md) here. @@ -244,7 +246,7 @@ It can also create a new module for your solution and add it to your solution. S > A business module generally consists of several packages (because of layering, different database provider options or other reasons). Using `add-module` command dramatically simplifies adding a module to a solution. However, each module may require some additional configurations which is generally indicated in the documentation of the related module. -Usage +Usage: ````bash abp add-module [options] @@ -278,7 +280,7 @@ abp add-module ProductManagement --new --add-to-solution-file Lists names of open-source application modules. -Usage +Usage: ````bash abp list-modules [options] @@ -294,11 +296,21 @@ abp list-modules * `--include-pro-modules`: Includes commercial (pro) modules in the output. +### list-templates + +Lists all available templates to create a solution. + +Usage: + +```bash +abp list-templates +``` + ### get-source Downloads the source code of a module to your computer. -Usage +Usage: ````bash abp get-source [options] diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md new file mode 100644 index 0000000000..2c4b860c95 --- /dev/null +++ b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md @@ -0,0 +1,690 @@ +# How to Design Multi-Lingual Entity + +## Introduction + +If you want to open up to the global market these days, end-to-end localization is a must. ABP provides an already established infrastructure for static texts. However, this may not be sufficient for many applications. You may need to fully customize your app for a particular language and region. + +Let's take a look at a few quotes from Christian Arno's article "[How Foreign-Language Internet Strategies Boost Sales](https://www.mediapost.com/publications/article/155250/how-foreign-language-internet-strategies-boost-sal.html)" to better understand the impact of this: + +- 82% of European consumers are less likely to buy online if the site is not in their native tongue ([Eurobarometer survey](http://europa.eu/rapid/pressReleasesAction.do?reference=IP/11/556)). +- 72.4% of global consumers are more likely to buy a product if the information is available in their own language ([Common Sense Advisory](http://www.commonsenseadvisory.com/)). +- The English language currently only accounts for 31% of all online use, and more than half of all searches are in languages other than English. +- Today, 42% of all Internet users are in Asia, while almost one-quarter are in Europe and just over 10% are in Latin America. + +- Foreign languages have experienced exponential growth in online usage in the past decade -- with Chinese now officially the [second-most-prominent-language](http://english.peopledaily.com.cn/90001/90776/90882/7438489.html) on the Web. [Arabic](http://www.internetworldstats.com/stats7.htm) has increased by a whopping 2500%, while English has only risen by 204% + +If you are looking for ways to expand your market share by fully customizing your application for a particular language and region, in this article I will explain how you can do it with ABP framework. + +### Source Code + +You can find the source code of the application at [abpframework/abp-samples](https://github.com/abpframework/abp-samples/tree/master/AcmeBookStoreMultiLingual). + +### Demo of the Final Application + +At the end of this article, we will have created an application same as in the gif below. + +![data-model](./result.gif) + +## Development + +In order to keep the article short and get rid of unrelated information in the article (like defining entities etc.), we'll be using the [BookStore](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) example, which is used in the "[Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF)" documentation of ABP Framework and we will make the Book entity as multi-lingual. If you do not want to finish this tutorial, you can find the application [here](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore). + +### Determining the data model + +We need a robust, maintainable, and efficient data model to store content in multiple languages. + +> I read many articles to determine the data model correctly, and as a result, I decided to use one of the many approaches that suit us. +> However, as in everything, there is a trade-off here. If you are wondering about the advantages and disadvantages of the model we will implement compared to other models, I recommend you to read [this article](https://vertabelo.com/blog/data-modeling-for-multiple-languages-how-to-design-a-localization-ready-system/). + +![data-model](./data-model.png) + +As a result of the tutorial, we already have the `Book` and `Author` entities, as an extra, we will just add the `BookTranslation`. + +> In the article, we will make the Name property of the Book entity multi-lingual, but the article is independent of the Book entity, you can make the entity you want multi-lingual with similar codes according to your requirements. + +#### Acme.BookStore.Domain.Shared + +Create a folder named `MultiLingualObjects` and create the following interfaces in its contents. + +We will use the `IObjectTranslation` interface to mark the translation of a multi-lingual entity: + +```csharp +public interface IObjectTranslation +{ + string Language { get; set; } +} +``` + +We will use the `IMultiLingualObject` interface to mark multi-lingual entities: + +```csharp +public interface IMultiLingualObject + where TTranslation : class, IObjectTranslation +{ + ICollection Translations { get; set; } +} +``` + +#### Acme.BookStore.Domain + +In the `Books` folder, create the `BookTranslation` class as follows: + +```csharp +public class BookTranslation : Entity, IObjectTranslation +{ + public Guid BookId { get; set; } + + public string Name { get; set; } + + public string Language { get; set; } + + public override object[] GetKeys() + { + return new object[] {BookId, Language}; + } +} +``` + +`BookTranslation` contains the `Language` property, which contains a language code for translation and a reference to the multi-lingual entity. We also have the `BookId` foreign key to help us know which book is translated. + +Implement `IMultiLingualObject` in the `Book` class as follows: + +```csharp +public class Book : AuditedAggregateRoot, IMultiLingualObject +{ + public Guid AuthorId { get; set; } + + public string Name { get; set; } + + public BookType Type { get; set; } + + public DateTime PublishDate { get; set; } + + public float Price { get; set; } + + public ICollection Translations { get; set; } +} +``` + +Create a folder named `MultiLingualObjects` and add the following class inside of this folder: + +```csharp +public class MultiLingualObjectManager : ITransientDependency +{ + protected const int MaxCultureFallbackDepth = 5; + + public async Task FindTranslationAsync( + TMultiLingual multiLingual, + string culture = null, + bool fallbackToParentCultures = true) + where TMultiLingual : IMultiLingualObject + where TTranslation : class, IObjectTranslation + { + culture ??= CultureInfo.CurrentUICulture.Name; + + if (multiLingual.Translations.IsNullOrEmpty()) + { + return null; + } + + var translation = multiLingual.Translations.FirstOrDefault(pt => pt.Language == culture); + if (translation != null) + { + return translation; + } + + if (fallbackToParentCultures) + { + translation = GetTranslationBasedOnCulturalRecursive( + CultureInfo.CurrentUICulture.Parent, + multiLingual.Translations, + 0 + ); + + if (translation != null) + { + return translation; + } + } + + return null; + } + + protected TTranslation GetTranslationBasedOnCulturalRecursive( + CultureInfo culture, ICollection translations, int currentDepth) + where TTranslation : class, IObjectTranslation + { + if (culture == null || + culture.Name.IsNullOrWhiteSpace() || + translations.IsNullOrEmpty() || + currentDepth > MaxCultureFallbackDepth) + { + return null; + } + + var translation = translations.FirstOrDefault(pt => pt.Language.Equals(culture.Name, StringComparison.OrdinalIgnoreCase)); + return translation ?? GetTranslationBasedOnCulturalRecursive(culture.Parent, translations, currentDepth + 1); + } +} +``` + +With `MultiLingualObjectManager`'s `FindTranslationAsync` method, we get the translated version of the book according to `CurrentUICulture`. If no translation of culture is found, we return null. + +> Every thread in .NET has `CurrentCulture` and `CurrentUICulture` objects. + +#### Acme.BookStore.EntityFrameworkCore + +In the `OnModelCreating` method of the `BookStoreDbContext` class, configure the `BookTranslation` as follows: + +```csharp +builder.Entity(b => +{ + b.ToTable(BookStoreConsts.DbTablePrefix + "BookTranslations", + BookStoreConsts.DbSchema); + + b.ConfigureByConvention(); + + b.HasKey(x => new {x.BookId, x.Language}); +}); +``` + +> I haven't explicitly set up a one-to-many relationship between `Book` and `BookTranslation` here, but the entity framework will do it for us. + +After that, you can just run the following command in a command-line terminal to add a new database migration (in the directory of the `EntityFrameworkCore` project): + +```bash +dotnet ef migrations add Added_BookTranslation +``` + +This will add a new migration class to your project. You can then run the following command (or run the `.DbMigrator` application) to apply changes to the database: + +```bash +dotnet ef database update +``` + +Add the following code to the `ConfigureServices` method of the `BookStoreEntityFrameworkCoreModule`: + +```csharp + Configure(options => + { + options.Entity(bookOptions => + { + bookOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Translations); + }); +}); +``` + +Now we can use `WithDetailsAsync` without any parameters on `BookAppService` knowing that `Translations` will be included. + +#### Acme.BookStore.Application.Contracts + +Implement `IObjectTranslation` in the `BookDto` class as follows: + +```csharp +public class BookDto : AuditedEntityDto, IObjectTranslation +{ + public Guid AuthorId { get; set; } + + public string AuthorName { get; set; } + + public string Name { get; set; } + + public BookType Type { get; set; } + + public DateTime PublishDate { get; set; } + + public float Price { get; set; } + + public string Language { get; set; } +} +``` + +`Language` property is required to understand which language the translated book name belongs to in the UI. + +Create the `AddBookTranslationDto` class in the `Books` folder as follows: + +```csharp +public class AddBookTranslationDto : IObjectTranslation +{ + [Required] + public string Language { get; set; } + + [Required] + public string Name { get; set; } +} +``` + +Add the `AddTranslationsAsync` method to the `IBookAppService` as follows: + +```csharp +public interface IBookAppService : + ICrudAppService< + BookDto, + Guid, + PagedAndSortedResultRequestDto, + CreateUpdateBookDto> +{ + Task> GetAuthorLookupAsync(); + + Task AddTranslationsAsync(Guid id, AddBookTranslationDto input); // added this line +} +``` + +#### Acme.BookStore.Application + +Now, we need to implement the `AddTranslationsAsync` method in `BookAppService` and include `Translations` in the `Book` entity, for this you can change the `BookAppService` as follows: + +```csharp +[Authorize(BookStorePermissions.Books.Default)] +public class BookAppService : + CrudAppService< + Book, //The Book entity + BookDto, //Used to show books + Guid, //Primary key of the book entity + PagedAndSortedResultRequestDto, //Used for paging/sorting + CreateUpdateBookDto>, //Used to create/update a book + IBookAppService //implement the IBookAppService +{ + private readonly IAuthorRepository _authorRepository; + + public BookAppService( + IRepository repository, + IAuthorRepository authorRepository) + : base(repository) + { + _authorRepository = authorRepository; + GetPolicyName = BookStorePermissions.Books.Default; + GetListPolicyName = BookStorePermissions.Books.Default; + CreatePolicyName = BookStorePermissions.Books.Create; + UpdatePolicyName = BookStorePermissions.Books.Edit; + DeletePolicyName = BookStorePermissions.Books.Create; + } + + public override async Task GetAsync(Guid id) + { + //Get the IQueryable from the repository + var queryable = await Repository.WithDetailsAsync(); // this line changed + + //Prepare a query to join books and authors + var query = from book in queryable + join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id + where book.Id == id + select new { book, author }; + + //Execute the query and get the book with author + var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); + if (queryResult == null) + { + throw new EntityNotFoundException(typeof(Book), id); + } + + var bookDto = ObjectMapper.Map(queryResult.book); + bookDto.AuthorName = queryResult.author.Name; + return bookDto; + } + + public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) + { + //Get the IQueryable from the repository + var queryable = await Repository.WithDetailsAsync(); // this line changed + + //Prepare a query to join books and authors + var query = from book in queryable + join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id + select new {book, author}; + + //Paging + query = query + .OrderBy(NormalizeSorting(input.Sorting)) + .Skip(input.SkipCount) + .Take(input.MaxResultCount); + + //Execute the query and get a list + var queryResult = await AsyncExecuter.ToListAsync(query); + + //Convert the query result to a list of BookDto objects + var bookDtos = queryResult.Select(x => + { + var bookDto = ObjectMapper.Map(x.book); + bookDto.AuthorName = x.author.Name; + return bookDto; + }).ToList(); + + //Get the total count with another query + var totalCount = await Repository.GetCountAsync(); + + return new PagedResultDto( + totalCount, + bookDtos + ); + } + + public async Task> GetAuthorLookupAsync() + { + var authors = await _authorRepository.GetListAsync(); + + return new ListResultDto( + ObjectMapper.Map, List>(authors) + ); + } + + public async Task AddTranslationsAsync(Guid id, AddBookTranslationDto input) + { + var queryable = await Repository.WithDetailsAsync(); + + var book = await AsyncExecuter.FirstOrDefaultAsync(queryable, x => x.Id == id); + + if (book.Translations.Any(x => x.Language == input.Language)) + { + throw new UserFriendlyException($"Translation already available for {input.Language}"); + } + + book.Translations.Add(new BookTranslation + { + BookId = book.Id, + Name = input.Name, + Language = input.Language + }); + + await Repository.UpdateAsync(book); + } + + private static string NormalizeSorting(string sorting) + { + if (sorting.IsNullOrEmpty()) + { + return $"book.{nameof(Book.Name)}"; + } + + if (sorting.Contains("authorName", StringComparison.OrdinalIgnoreCase)) + { + return sorting.Replace( + "authorName", + "author.Name", + StringComparison.OrdinalIgnoreCase + ); + } + + return $"book.{sorting}"; + } +} +``` + +Create the `MultiLingualBookObjectMapper` class as follows: + +```csharp +public class MultiLingualBookObjectMapper : IObjectMapper, ITransientDependency +{ + private readonly MultiLingualObjectManager _multiLingualObjectManager; + + private readonly ISettingProvider _settingProvider; + + public MultiLingualBookObjectMapper( + MultiLingualObjectManager multiLingualObjectManager, + ISettingProvider settingProvider) + { + _multiLingualObjectManager = multiLingualObjectManager; + _settingProvider = settingProvider; + } + + public BookDto Map(Book source) + { + var translation = AsyncHelper.RunSync(() => + _multiLingualObjectManager.FindTranslationAsync(source)); + + return new BookDto + { + Id = source.Id, + AuthorId = source.AuthorId, + Type = source.Type, + Name = translation?.Name ?? source.Name, + PublishDate = source.PublishDate, + Price = source.Price, + Language = translation?.Language ?? AsyncHelper.RunSync(() => _settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage)), + CreationTime = source.CreationTime, + CreatorId = source.CreatorId, + LastModificationTime = source.LastModificationTime, + LastModifierId = source.LastModifierId + }; + } + + public BookDto Map(Book source, BookDto destination) + { + return default; + } +} +``` + +To map the multi-lingual `Book` entity to `BookDto`, we implement custom mapping using the `IObjectMapper` interface. If no translation is found, default values are returned. + +So far we have created the entire infrastructure. We don't need to change anything in the UI, if there is a translation according to the language chosen by the user, the list view will change. However, I want to create a simple modal where we can add new translations to an existing book in order to see what we have done. + +#### Acme.BookStore.Web + +Create a new razor page named `AddTranslationModal` in the `Books` folder as below. + +**View** + +```html +@page +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@model Acme.BookStore.Web.Pages.Books.AddTranslationModal + +@{ + Layout = null; +} + +
+ + Translations + + + + + + + + + +
+``` + +**Model** + +```csharp +public class AddTranslationModal : BookStorePageModel +{ + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + public List Languages { get; set; } + + [BindProperty] + public BookTranslationViewModel TranslationViewModel { get; set; } + + private readonly IBookAppService _bookAppService; + private readonly ILanguageProvider _languageProvider; + + public AddTranslationModal( + IBookAppService bookAppService, + ILanguageProvider languageProvider) + { + _bookAppService = bookAppService; + _languageProvider = languageProvider; + } + + public async Task OnGetAsync() + { + Languages = await GetLanguagesSelectItem(); + + TranslationViewModel = new BookTranslationViewModel(); + } + + public async Task OnPostAsync() + { + await _bookAppService.AddTranslationsAsync(Id, ObjectMapper.Map(TranslationViewModel)); + + return NoContent(); + } + + private async Task> GetLanguagesSelectItem() + { + var result = await _languageProvider.GetLanguagesAsync(); + + return result.Select( + languageInfo => new SelectListItem + { + Value = languageInfo.CultureName, + Text = languageInfo.DisplayName + " (" + languageInfo.CultureName + ")" + } + ).ToList(); + } + + public class BookTranslationViewModel + { + [Required] + [SelectItems(nameof(Languages))] + public string Language { get; set; } + + [Required] + public string Name { get; set; } + + } +} +``` + +Then, we can open the `BookStoreWebAutoMapperProfile` class and define the required mapping as follows: + +```csharp +CreateMap(); +``` + +Finally, change the content of `index.js` in the `Books` folder as follows: + +```javascript +$(function () { + var l = abp.localization.getResource('BookStore'); + var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal'); + var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal'); + var addTranslationModal = new abp.ModalManager(abp.appPath + 'Books/AddTranslationModal'); // added this line + + var dataTable = $('#BooksTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + serverSide: true, + paging: true, + order: [[1, "asc"]], + searching: false, + scrollX: true, + ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList), + columnDefs: [ + { + title: l('Actions'), + rowAction: { + items: + [ + { + text: l('Edit'), + visible: abp.auth.isGranted('BookStore.Books.Edit'), + action: function (data) { + editModal.open({ id: data.record.id }); + } + }, + { + text: l('Add Translation'), // added this action + visible: abp.auth.isGranted('BookStore.Books.Edit'), + action: function (data) { + addTranslationModal.open({ id: data.record.id }); + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('BookStore.Books.Delete'), + confirmMessage: function (data) { + return l( + 'BookDeletionConfirmationMessage', + data.record.name + ); + }, + action: function (data) { + acme.bookStore.books.book + .delete(data.record.id) + .then(function() { + abp.notify.info( + l('SuccessfullyDeleted') + ); + dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l('Name'), + data: "name" + }, + { + title: l('Author'), + data: "authorName" + }, + { + title: l('Type'), + data: "type", + render: function (data) { + return l('Enum:BookType:' + data); + } + }, + { + title: l('PublishDate'), + data: "publishDate", + render: function (data) { + return luxon + .DateTime + .fromISO(data, { + locale: abp.localization.currentCulture.name + }).toLocaleString(); + } + }, + { + title: l('Price'), + data: "price" + }, + { + title: l('CreationTime'), + data: "creationTime", + render: function (data) { + return luxon + .DateTime + .fromISO(data, { + locale: abp.localization.currentCulture.name + }).toLocaleString(luxon.DateTime.DATETIME_SHORT); + } + } + ] + }) + ); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + editModal.onResult(function () { + dataTable.ajax.reload(); + }); + + $('#NewBookButton').click(function (e) { + e.preventDefault(); + createModal.open(); + }); +}); +``` + +## Conclusion + +With a multi-lingual application, you can expand your market share, but if not designed well, may your application will be unusable. So, I've tried to explain how to design a sustainable multi-lingual entity in this article. + +### Source Code + +You can find source code of the example solution used in this article [here](https://github.com/abpframework/abp-samples/tree/master/AcmeBookStoreMultiLingual). diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png new file mode 100644 index 0000000000..c7e02bc2cd Binary files /dev/null and b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png differ diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif new file mode 100644 index 0000000000..0bc41cb8f1 Binary files /dev/null and b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif differ diff --git a/docs/en/Modules/OpenIddict.md b/docs/en/Modules/OpenIddict.md index 9e603f76a8..6dc1224e59 100644 --- a/docs/en/Modules/OpenIddict.md +++ b/docs/en/Modules/OpenIddict.md @@ -4,6 +4,14 @@ This module implements the domain logic and database integrations, but not provides any UI. Management UI is useful if you need to add applications and scopes on the fly. In this case, you may build the management UI yourself or consider to purchase the [ABP Commercial](https://commercial.abp.io/) which provides the management UI for this module. +## How to Install + +This module comes as pre-installed (as NuGet/NPM packages) when you [create a new solution](https://abp.io/get-started) with the ABP Framework. You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module. + +### The Source Code + +The source code of this module can be accessed [here](https://github.com/abpframework/abp/tree/dev/modules/openiddict). The source code is licensed with [MIT](https://choosealicense.com/licenses/mit/), so you can freely use and customize it. + ## Relations to Other Modules This module is based on the [Identity Module](Identity.md) and have an [integration package](https://www.nuget.org/packages/Volo.Abp.Account.Web.OpenIddict) with the [Account Module](Account.md). @@ -206,6 +214,10 @@ If you need to customize OpenIddict, you need to replace/delete/add new handlers Please refer to: https://documentation.openiddict.com/guides/index.html#events-model +## Migrating Guide + +[Migrating from IdentityServer to OpenIddict Step by Step Guide ](../Migration-Guides/OpenIddict-Step-by-Step.md) + ## Sponsor Please consider sponsoring this project: https://github.com/sponsors/kevinchalet diff --git a/docs/en/Modules/Setting-Management.md b/docs/en/Modules/Setting-Management.md index e54993cf79..354fbdd539 100644 --- a/docs/en/Modules/Setting-Management.md +++ b/docs/en/Modules/Setting-Management.md @@ -118,7 +118,13 @@ The order of the providers are important. Providers are executed in the reverse ## Setting Management UI -Setting Mangement module provided the email setting UI by default, and it is extensible; You can add your tabs to this page for your application settings. +Setting Mangement module provided the email setting UI by default. + +![EmailSettingUi](../images/setting-management-email-ui.png) + +> You can click the Send test email button to send a test email to check your email settings. + +Setting it is extensible; You can add your tabs to this page for your application settings. ### MVC UI @@ -302,5 +308,4 @@ export class AppComponent { Navigate to `/setting-management` route to see the changes: -![Custom Settings Tab](../images/custom-settings.png) - +![Custom Settings Tab](../images/custom-settings.png) \ No newline at end of file diff --git a/docs/en/UI/Angular/Theming.md b/docs/en/UI/Angular/Theming.md index c7f303763d..435acc6930 100644 --- a/docs/en/UI/Angular/Theming.md +++ b/docs/en/UI/Angular/Theming.md @@ -16,10 +16,11 @@ In order to accomplish these goals, ABP Framework; ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/angular) and [lite](../../Themes/LeptonXLite/Angular.md) choices. ## Overall diff --git a/docs/en/UI/AspNetCore/Overall.md b/docs/en/UI/AspNetCore/Overall.md index 8cd9dd3f5e..bc24c56fb8 100644 --- a/docs/en/UI/AspNetCore/Overall.md +++ b/docs/en/UI/AspNetCore/Overall.md @@ -32,10 +32,11 @@ ABP Framework provides a complete [Theming](Theming.md) system with the followin ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/mvc) and [lite](../../Themes/LeptonXLite/AspNetCore.md) choices. There are also some community-driven themes for the ABP Framework (you can search on the web). diff --git a/docs/en/UI/AspNetCore/Page-Header.md b/docs/en/UI/AspNetCore/Page-Header.md index f6ec3074de..8b045c89ab 100644 --- a/docs/en/UI/AspNetCore/Page-Header.md +++ b/docs/en/UI/AspNetCore/Page-Header.md @@ -23,6 +23,8 @@ Page Title can be set as shown in the example below: ### Breadcrumb > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the breadcrumbs.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) supports breadcrumbs. Breadcrumb items can be added to the `PageLayout.Content.BreadCrumb`. @@ -48,11 +50,13 @@ Any item that you add is inserted between Home and Current Page items. You can a ### The Selected Menu Item > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the selected menu item since it is not applicable to the top menu which is the only option for the Basic Theme for now.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) supports selected menu item. You can set the Menu Item name related to this page: -````csharp +```csharp PageLayout.Content.MenuItemName = "BookStore.Books"; -```` +``` Menu item name should match a unique menu item name defined using the [Navigation / Menu](Navigation-Menu.md) system. In this case, it is expected from the theme to make the menu item "active" in the main menu. \ No newline at end of file diff --git a/docs/en/UI/AspNetCore/Toolbars.md b/docs/en/UI/AspNetCore/Toolbars.md index d82150b47e..975157151f 100644 --- a/docs/en/UI/AspNetCore/Toolbars.md +++ b/docs/en/UI/AspNetCore/Toolbars.md @@ -8,6 +8,12 @@ There is only one **standard toolbar** named "Main" (defined as a constant: `Sta In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. +Also, [LeptonX Lite Theme](../../Themes/LeptonXLite/AspNetCore.md) has 2 different toolbars for desktop and mobile views which defined as constants: `LeptonXLiteToolbars.Main`, `LeptonXLiteToolbars.MainMobile`. + +| LeptonXLiteToolbars.Main | LeptonXLiteToolbars.MainMobile | +| :---: | :---: | +| ![leptonx](../../images/leptonxlite-toolbar-main-example.png) | ![leptonx](../../images/leptonxlite-toolbar-mainmobile-example.png) | + ## Example: Add a Notification Icon In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **view component**. So, first, create a new view component in your project: diff --git a/docs/en/UI/Blazor/Overall.md b/docs/en/UI/Blazor/Overall.md index ff361d6784..402d61acb0 100644 --- a/docs/en/UI/Blazor/Overall.md +++ b/docs/en/UI/Blazor/Overall.md @@ -75,10 +75,11 @@ ABP Framework provides a complete [Theming](Theming.md) system with the followin ### Current Themes -Currently, two themes are **officially provided**: +Currently, three themes are **officially provided**: * The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. * The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. +* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has both [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/blazor) and [lite](../../Themes/LeptonXLite/Blazor.md) choices. ### Base Libraries diff --git a/docs/en/UI/Blazor/Page-Header.md b/docs/en/UI/Blazor/Page-Header.md index 29cb006bd3..1bdc9c93c0 100644 --- a/docs/en/UI/Blazor/Page-Header.md +++ b/docs/en/UI/Blazor/Page-Header.md @@ -16,6 +16,8 @@ Once you add the `PageHeader` component to your page, you can control the relate ## Breadcrumb > **The [Basic Theme](Basic-Theme.md) currently doesn't implement the breadcrumbs.** +> +> The [LeptonX Lite Theme](../../Themes/LeptonXLite/Blazor.md) supports breadcrumbs. Breadcrumbs can be added using the `BreadcrumbItems` property. diff --git a/docs/en/UI/Blazor/Page-Layout.md b/docs/en/UI/Blazor/Page-Layout.md index 49ed1659f4..c6f3d62000 100644 --- a/docs/en/UI/Blazor/Page-Layout.md +++ b/docs/en/UI/Blazor/Page-Layout.md @@ -42,6 +42,10 @@ Menu item name can be set on runtime too. } ``` + +![leptonx selected menu item](../../images/leptonx-selected-menu-item-example.gif) + + > Be aware, The [Basic Theme](../Blazor/Basic-Theme.md) currently doesn't support the selected menu item since it is not applicable to the top menu. ## BreadCrumbs diff --git a/docs/en/UI/Blazor/Toolbars.md b/docs/en/UI/Blazor/Toolbars.md index 3ff1b7f135..c0878f080a 100644 --- a/docs/en/UI/Blazor/Toolbars.md +++ b/docs/en/UI/Blazor/Toolbars.md @@ -8,6 +8,12 @@ There is only one **standard toolbar** named "Main" (defined as a constant: `Sta In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. +Also, [LeptonX Lite Theme](../../Themes/LeptonXLite/Blazor.md) has 2 different toolbars for desktop and mobile views which defined as constants: `LeptonXLiteToolbars.Main`, `LeptonXLiteToolbars.MainMobile`. + +| LeptonXLiteToolbars.Main | LeptonXLiteToolbars.MainMobile | +| :---: | :---: | +| ![leptonx](../../images/leptonxlite-toolbar-main-example.png) | ![leptonx](../../images/leptonxlite-toolbar-mainmobile-example.png) | + ## Example: Add a Notification Icon In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **Razor Component**. So, first, create a new razor component in your project (the location of the component doesn't matter): diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index db63a7136b..f764ca0bf2 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -43,6 +43,10 @@ "text": "WPF Application", "path": "Startup-Templates/WPF.md" }, + { + "text": "MAUI", + "path": "Startup-Templates/MAUI.md" + }, { "text": "Empty Web Project", "path": "Getting-Started-AspNetCore-Application.md" diff --git a/docs/en/images/breadcrumbs-example.png b/docs/en/images/breadcrumbs-example.png index 17ae5f8ba5..8b4bbc62d7 100644 Binary files a/docs/en/images/breadcrumbs-example.png and b/docs/en/images/breadcrumbs-example.png differ diff --git a/docs/en/images/leptonx-selected-menu-item-example.gif b/docs/en/images/leptonx-selected-menu-item-example.gif new file mode 100644 index 0000000000..8f1170cd55 Binary files /dev/null and b/docs/en/images/leptonx-selected-menu-item-example.gif differ diff --git a/docs/en/images/leptonxlite-toolbar-main-example.png b/docs/en/images/leptonxlite-toolbar-main-example.png new file mode 100644 index 0000000000..30edcf547b Binary files /dev/null and b/docs/en/images/leptonxlite-toolbar-main-example.png differ diff --git a/docs/en/images/leptonxlite-toolbar-mainmobile-example.png b/docs/en/images/leptonxlite-toolbar-mainmobile-example.png new file mode 100644 index 0000000000..95815b5843 Binary files /dev/null and b/docs/en/images/leptonxlite-toolbar-mainmobile-example.png differ diff --git a/docs/en/images/setting-management-email-ui.png b/docs/en/images/setting-management-email-ui.png new file mode 100644 index 0000000000..f8f1270c15 Binary files /dev/null and b/docs/en/images/setting-management-email-ui.png differ diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index f890534795..f108bbcfec 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -123,6 +123,7 @@ abp new Acme.BookStore * `module`: [Module template](Startup-Templates/Module.md). 其他选项: * `--no-ui`: 不包含UI.仅创建服务模块(也称为微服务 - 没有UI). * **`console`**: [Console template](Startup-Templates/Console.md). + * **`maui`**: [Maui template](Startup-Templates/MAUI.md). * **`app-nolayers`**: 应用程序单层模板 * `--ui` 或者 `-u`: 指定ui框架.默认`mvc`框架.其他选项: * `mvc`: ASP.NET Core MVC. diff --git a/docs/zh-Hans/Modules/Setting-Management.md b/docs/zh-Hans/Modules/Setting-Management.md index c99397e4b4..242553c2c9 100644 --- a/docs/zh-Hans/Modules/Setting-Management.md +++ b/docs/zh-Hans/Modules/Setting-Management.md @@ -87,7 +87,13 @@ namespace Demo ## Setting Management UI. -设置管理模块默认提供了邮件设置页面并且它是可扩展的; 你可以为你的应用程序设置添加设置标签到设置页面. +设置管理模块默认提供了邮件设置页面. + +![EmailSettingUi](../images/setting-management-email-ui.png) + +> 你可以点击发送测试邮件按钮发送一封测试邮件来检查你的邮件设置. + +设置UI是可扩展的; 你可以为你的应用程序设置添加设置标签到设置页面. ### MVC UI diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 203000c6c6..be30753fb3 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -61,6 +61,10 @@ { "text": "WPF", "path": "Startup-Templates/WPF.md" + }, + { + "text": "MAUI", + "path": "Startup-Templates/MAUI.md" } ] }, diff --git a/docs/zh-Hans/images/setting-management-email-ui.png b/docs/zh-Hans/images/setting-management-email-ui.png new file mode 100644 index 0000000000..f8f1270c15 Binary files /dev/null and b/docs/zh-Hans/images/setting-management-email-ui.png differ diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 1cffbfe407..cc64d73ff2 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -85,7 +85,13 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien ConfigureNpmPackagesForTheme(projectArgs); await RunGraphBuildForMicroserviceServiceTemplate(projectArgs); await CreateInitialMigrationsAsync(projectArgs); - await RunInstallLibsForWebTemplateAsync(projectArgs); + + var skipInstallLibs = commandLineArgs.Options.ContainsKey(Options.SkipInstallingLibs.Long) || commandLineArgs.Options.ContainsKey(Options.SkipInstallingLibs.Short); + if (!skipInstallLibs) + { + await RunInstallLibsForWebTemplateAsync(projectArgs); + } + await ConfigurePwaSupportForAngular(projectArgs); OpenRelatedWebPage(projectArgs, template, isTiered, commandLineArgs); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs index b3064146fc..6bd8a78cc8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs @@ -709,6 +709,12 @@ public abstract class ProjectCreationCommandBase public const string Long = "create-solution-folder"; } + public static class SkipInstallingLibs + { + public const string Short = "sib"; + public const string Long = "skip-installing-libs"; + } + public static class Tiered { public const string Long = "tiered"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs index 916f861460..33ecad0719 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs @@ -285,14 +285,12 @@ public class ChangeThemeStep : ProjectBuildPipelineStep {"Domain.Shared", "MyCompanyName.MyProjectName.Domain.Shared.csproj"}, {"Application", "MyCompanyName.MyProjectName.Application.csproj"}, {"Application.Contracts", "MyCompanyName.MyProjectName.Application.Contracts.csproj"}, - {"Blazor.WebAssembly", "MyCompanyName.MyProjectName.Blazor.csproj"}, - {"Blazor.Server", "MyCompanyName.MyProjectName.Blazor.Server.csproj"}, {"HttpApi", "MyCompanyName.MyProjectName.HttpApi.csproj"}, - {"HttpApi.Client", "MyCompanyName.MyProjectName.HttpApi.Client.csproj"}, - {"Web.Host", "MyCompanyName.MyProjectName.Web.Host.csproj"}, - {"Web", "MyCompanyName.MyProjectName.Web.csproj"}, + {"HttpApi.Client", "MyCompanyName.MyProjectName.HttpApi.Client.csproj"} }; - + + AddUiProjectToProjects(projects, context); + foreach (var project in projects) { AddLeptonThemeManagementReference(context, project); @@ -314,6 +312,28 @@ public class ChangeThemeStep : ProjectBuildPipelineStep AddLeptonThemeManagementReference(context, microserviceServiceProject); } } + + private void AddUiProjectToProjects(Dictionary projects, ProjectBuildContext context) + { + if (projects.IsNullOrEmpty()) + { + return; + } + + switch (context.BuildArgs.UiFramework) + { + case UiFramework.Mvc: + projects["Web.Host"] = "MyCompanyName.MyProjectName.Web.Host.csproj"; + projects["Web"] = "MyCompanyName.MyProjectName.Web.csproj"; + break; + case UiFramework.Blazor: + projects["Blazor.WebAssembly"] = "MyCompanyName.MyProjectName.Blazor.csproj"; + break; + case UiFramework.BlazorServer: + projects["Blazor.Server"] = "MyCompanyName.MyProjectName.Blazor.csproj"; + break; + } + } private void AddLeptonThemeManagementReference(ProjectBuildContext context, KeyValuePair projectInfo) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs index 44f6d3e0bd..ce61d9775f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs @@ -14,6 +14,8 @@ public class TemplateCodeDeleteStep : ProjectBuildPipelineStep file.Name.EndsWith(".json") || file.Name.EndsWith(".gitignore") || file.Name.EndsWith(".yml") || + file.Name.EndsWith(".yaml") || + file.Name.EndsWith(".md") || file.Name.EndsWith(".ps1") || file.Name.EndsWith(".html") || file.Name.EndsWith(".ts") || diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs index 71f090a576..c6a15389ef 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs @@ -130,6 +130,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new RemoveFolderStep("/apps/blazor")); steps.Add(new RemoveProjectFromTyeStep("blazor")); steps.Add(new RemoveProjectFromTyeStep("blazor-server")); + + context.Symbols.Add("ui:angular"); break; case UiFramework.Blazor: @@ -147,7 +149,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo null, "/apps/blazor/src/MyCompanyName.MyProjectName.Blazor.Server")); steps.Add(new RemoveProjectFromTyeStep("blazor-server")); - + + context.Symbols.Add("ui:blazor"); break; case UiFramework.BlazorServer: @@ -169,7 +172,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.Blazor.Server", "MyCompanyName.MyProjectName.Blazor")); steps.Add(new RenameProjectInTyeStep("blazor-server", "blazor")); - + + context.Symbols.Add("ui:blazor-server"); break; case UiFramework.Mvc: @@ -186,6 +190,8 @@ public abstract class MicroserviceTemplateBase : TemplateInfo steps.Add(new RemoveProjectFromTyeStep("blazor-server")); steps.Add(new RemoveFolderStep("/apps/angular")); + + context.Symbols.Add("ui:mvc"); break; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index e6c21544b3..7f2831351a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -489,6 +489,7 @@ public class SolutionModuleAdder : ITransientDependency args.Options.Add("t", newProTemplate ? ModuleProTemplate.TemplateName : ModuleTemplate.TemplateName); args.Options.Add("v", version); args.Options.Add("o", Path.Combine(modulesFolderInSolution, module.Name)); + args.Options.Add("sib", true.ToString()); await NewCommand.ExecuteAsync(args); } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs index 363c3b3885..3aff8a78ad 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/AbpLazyServiceProvider.cs @@ -1,19 +1,13 @@ using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; namespace Volo.Abp.DependencyInjection; -public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDependency +[ExposeServices(typeof(IAbpLazyServiceProvider))] +public class AbpLazyServiceProvider : CachedServiceProviderBase, IAbpLazyServiceProvider, ITransientDependency { - protected IDictionary CachedServices { get; set; } - - protected IServiceProvider ServiceProvider { get; set; } - public AbpLazyServiceProvider(IServiceProvider serviceProvider) + : base(serviceProvider) { - ServiceProvider = serviceProvider; - CachedServices = new Dictionary(); } public virtual T LazyGetRequiredService() @@ -23,7 +17,7 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetRequiredService(Type serviceType) { - return CachedServices.GetOrAdd(serviceType, () => ServiceProvider.GetRequiredService(serviceType)); + return GetService(serviceType); } public virtual T LazyGetService() @@ -33,7 +27,7 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetService(Type serviceType) { - return CachedServices.GetOrAdd(serviceType, () => ServiceProvider.GetService(serviceType)); + return GetService(serviceType); } public virtual T LazyGetService(T defaultValue) @@ -53,6 +47,9 @@ public class AbpLazyServiceProvider : IAbpLazyServiceProvider, ITransientDepende public virtual object LazyGetService(Type serviceType, Func factory) { - return CachedServices.GetOrAdd(serviceType, () => factory(ServiceProvider)); + return CachedServices.GetOrAdd( + serviceType, + _ => new Lazy(() => factory(ServiceProvider)) + ).Value; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs index d543493ce9..c261d3a3bb 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/CachedServiceProviderBase.cs @@ -5,21 +5,21 @@ namespace Volo.Abp.DependencyInjection; public abstract class CachedServiceProviderBase { - private readonly IServiceProvider _serviceProvider; - private readonly ConcurrentDictionary> _cachedServices; + protected IServiceProvider ServiceProvider { get; } + protected ConcurrentDictionary> CachedServices { get; } protected CachedServiceProviderBase(IServiceProvider serviceProvider) { - _serviceProvider = serviceProvider; - _cachedServices = new ConcurrentDictionary>(); - _cachedServices.TryAdd(typeof(IServiceProvider), new Lazy(() => _serviceProvider)); + ServiceProvider = serviceProvider; + CachedServices = new ConcurrentDictionary>(); + CachedServices.TryAdd(typeof(IServiceProvider), new Lazy(() => ServiceProvider)); } public virtual object GetService(Type serviceType) { - return _cachedServices.GetOrAdd( + return CachedServices.GetOrAdd( serviceType, - _ => new Lazy(() => _serviceProvider.GetService(serviceType)) + _ => new Lazy(() => ServiceProvider.GetService(serviceType)) ).Value; } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs new file mode 100644 index 0000000000..c78dc9c989 --- /dev/null +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/AbpLazyServiceProvider_Tests.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Modularity; +using Volo.Abp.Testing.Utils; +using Xunit; + +namespace Volo.Abp.DependencyInjection; + +public class AbpLazyServiceProvider_Tests +{ + [Fact] + public void LazyServiceProvider_Should_Cache_Services() + { + using (var application = AbpApplicationFactory.Create()) + { + application.Initialize(); + + var lazyServiceProvider = application.ServiceProvider.GetRequiredService(); + + var transientTestService1 = lazyServiceProvider.LazyGetRequiredService(); + var transientTestService2 = lazyServiceProvider.LazyGetRequiredService(); + transientTestService1.ShouldBeSameAs(transientTestService2); + + var testCounter = application.ServiceProvider.GetRequiredService(); + testCounter.GetValue(nameof(TransientTestService)).ShouldBe(1); + } + } + + [DependsOn(typeof(AbpTestBaseModule))] + private class TestModule : AbpModule + { + public TestModule() + { + SkipAutoServiceRegistration = true; + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddType(); + } + } + + private class TransientTestService : ITransientDependency + { + public TransientTestService(ITestCounter counter) + { + counter.Increment(nameof(TransientTestService)); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs index 7cd17b7696..5736048076 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.Blogs.Default)] public class BlogAdminAppService : CmsKitAdminAppServiceBase, IBlogAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs index 823f569bed..774f28634d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.Blogs.Features)] public class BlogFeatureAdminAppService : CmsKitAdminAppServiceBase, IBlogFeatureAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs index 9d8fcfd917..297e70344f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs @@ -1,19 +1,22 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; using Volo.CmsKit.Admin.MediaDescriptors; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Users; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.BlogPosts.Default)] public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppService @@ -66,18 +69,18 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe public virtual async Task UpdateAsync(Guid id, UpdateBlogPostDto input) { var blogPost = await BlogPostRepository.GetAsync(id); - + blogPost.SetTitle(input.Title); blogPost.SetShortDescription(input.ShortDescription); blogPost.SetContent(input.Content); blogPost.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp); - + if (blogPost.CoverImageMediaId != null && input.CoverImageMediaId == null) { await MediaDescriptorAdminAppService.DeleteAsync(blogPost.CoverImageMediaId.Value); } blogPost.CoverImageMediaId = input.CoverImageMediaId; - + if (blogPost.Slug != input.Slug) { await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug); @@ -146,12 +149,12 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe { var blogPost = await CreateAsync(input); await CurrentUnitOfWork.SaveChangesAsync(); - + await PublishAsync(blogPost.Id); blogPost.Status = BlogPostStatus.Published; return blogPost; } - + [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] public virtual async Task SendToReviewAsync(Guid id) { @@ -159,13 +162,13 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe blogPost.SetWaitingForReview(); await BlogPostRepository.UpdateAsync(blogPost); } - + [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] public virtual async Task CreateAndSendToReviewAsync(CreateBlogPostDto input) { var blogPost = await CreateAsync(input); await CurrentUnitOfWork.SaveChangesAsync(); - + await SendToReviewAsync(blogPost.Id); blogPost.Status = BlogPostStatus.WaitingForReview; return blogPost; diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs index 5295557860..973a74b58e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs @@ -3,14 +3,17 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Comments; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Users; namespace Volo.CmsKit.Admin.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] [Authorize(CmsKitAdminPermissions.Comments.Default)] public class CommentAdminAppService : CmsKitAdminAppServiceBase, ICommentAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs index a78a21de41..c5b63db6c3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs @@ -1,13 +1,16 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Services; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalResources; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [Authorize(CmsKitAdminPermissions.GlobalResources.Default)] public class GlobalResourceAdminAppService : ApplicationService, IGlobalResourceAdminAppService @@ -18,10 +21,11 @@ public class GlobalResourceAdminAppService : ApplicationService, IGlobalResource { GlobalResourceManager = globalResourceManager; } - + public async Task GetAsync() { - return new GlobalResourcesDto { + return new GlobalResourcesDto + { StyleContent = (await GlobalResourceManager.GetGlobalStyleAsync()).Value, ScriptContent = (await GlobalResourceManager.GetGlobalScriptAsync()).Value }; diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs index cc785adac0..af347bcc55 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs @@ -1,12 +1,15 @@ using System; using System.Threading.Tasks; using Volo.Abp.BlobStoring; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.MediaDescriptors; namespace Volo.CmsKit.Admin.MediaDescriptors; +[RequiresFeature(CmsKitFeatures.MediaEnable)] [RequiresGlobalFeature(typeof(MediaFeature))] public class MediaDescriptorAdminAppService : CmsKitAdminAppServiceBase, IMediaDescriptorAdminAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs index 8ef6ce0346..3ba2a4b5b9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs @@ -1,12 +1,12 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; using Volo.CmsKit.Pages; @@ -14,6 +14,7 @@ using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] [Authorize(CmsKitAdminPermissions.Menus.Default)] public class MenuItemAdminAppService : CmsKitAdminAppServiceBase, IMenuItemAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs index 68f0690555..647568e561 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs @@ -1,18 +1,19 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using AutoMapper; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Menus; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pages; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [Authorize(CmsKitAdminPermissions.Pages.Default)] public class PageAdminAppService : CmsKitAdminAppServiceBase, IPageAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs index 8d106b70e0..3cdc4dc093 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs @@ -1,10 +1,13 @@ using System.Threading.Tasks; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs index f6de1ac5b9..46324937cc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs @@ -1,18 +1,21 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Localization; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Localization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [Authorize(CmsKitAdminPermissions.Tags.Default)] [RequiresGlobalFeature(typeof(TagsFeature))] public class TagAdminAppService : CmsKitAppServiceBase, ITagAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs index 094c1b1b5a..e7d59ddbcd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs index e3cc3c5e73..93bdced888 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs index 563d90c254..923f9a4036 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] @@ -61,7 +64,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.UpdateAsync(id, input); } - + [HttpPost] [Route("{id}/publish")] [Authorize(CmsKitAdminPermissions.BlogPosts.Publish)] @@ -69,7 +72,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.PublishAsync(id); } - + [HttpPost] [Route("{id}/draft")] [Authorize(CmsKitAdminPermissions.BlogPosts.Update)] @@ -86,7 +89,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.CreateAndPublishAsync(input); } - + [HttpPost] [Route("{id}/send-to-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] @@ -94,7 +97,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.SendToReviewAsync(id); } - + [HttpPost] [Route("create-and-send-to-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] @@ -102,7 +105,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.CreateAndSendToReviewAsync(input); } - + [HttpGet] [Route("has-blogpost-waiting-for-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Publish)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs index 6082ad3794..f4813f61ad 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs @@ -4,12 +4,15 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [Authorize(CmsKitAdminPermissions.Comments.Default)] [RequiresGlobalFeature(typeof(CommentsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs index 3bfe51a600..b1ae9b3f2e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs @@ -2,18 +2,21 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] [Authorize(CmsKitAdminPermissions.Menus.Default)] [Route("api/cms-kit-admin/global-resources")] -public class GlobalResourceAdminController: CmsKitAdminController, IGlobalResourceAdminAppService +public class GlobalResourceAdminController : CmsKitAdminController, IGlobalResourceAdminAppService { private readonly IGlobalResourceAdminAppService _globalResourceAdminAppService; @@ -21,7 +24,7 @@ public class GlobalResourceAdminController: CmsKitAdminController, IGlobalResour { _globalResourceAdminAppService = globalResourceAdminAppService; } - + [HttpGet] public Task GetAsync() { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs index f95d2a86b2..c304c5c684 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs @@ -1,16 +1,15 @@ using System; -using System.Net; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; -using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.MediaDescriptors; +[RequiresFeature(CmsKitFeatures.MediaEnable)] [RequiresGlobalFeature(typeof(MediaFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs index de36883ff7..a0325f4f27 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs index 7936b206e6..5acccb07aa 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs @@ -4,13 +4,15 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Menus; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs index 9df9394fdd..c57e7bb0a7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs @@ -1,13 +1,14 @@ -using Microsoft.AspNetCore.Authorization; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; -using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs index c34107b742..db0131ba2f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs @@ -1,18 +1,20 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Tags; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs index bc9bbfb310..9cc76c080c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs @@ -2,8 +2,10 @@ using System.Linq; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.UI.Navigation; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Localization; using Volo.CmsKit.Permissions; @@ -36,6 +38,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Pages"].Value, "/Cms/Pages", "fa fa-file-alt") + .RequireFeatures(CmsKitFeatures.PageEnable) .RequireGlobalFeatures(typeof(PagesFeature)) .RequirePermissions(CmsKitAdminPermissions.Pages.Default)); @@ -44,6 +47,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Blogs"], "/Cms/Blogs", "fa fa-blog") + .RequireFeatures(CmsKitFeatures.BlogEnable) .RequireGlobalFeatures(typeof(BlogsFeature)) .RequirePermissions(CmsKitAdminPermissions.Blogs.Default)); @@ -52,6 +56,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["BlogPosts"], "/Cms/BlogPosts", "fa fa-file-signature") + .RequireFeatures(CmsKitFeatures.BlogEnable) .RequireGlobalFeatures(typeof(BlogsFeature)) .RequirePermissions(CmsKitAdminPermissions.BlogPosts.Default)); @@ -60,6 +65,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Tags"].Value, "/Cms/Tags", "fa fa-tags") + .RequireFeatures(CmsKitFeatures.TagEnable) .RequireGlobalFeatures(typeof(TagsFeature)) .RequirePermissions(CmsKitAdminPermissions.Tags.Default)); @@ -68,6 +74,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Comments"].Value, "/Cms/Comments", "fa fa-comments") + .RequireFeatures(CmsKitFeatures.CommentEnable) .RequireGlobalFeatures(typeof(CommentsFeature)) .RequirePermissions(CmsKitAdminPermissions.Comments.Default)); @@ -76,6 +83,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Menus"], "/Cms/Menus/Items", "fa fa-stream") + .RequireFeatures(CmsKitFeatures.MenuEnable) .RequireGlobalFeatures(typeof(MenuFeature)) .RequirePermissions(CmsKitAdminPermissions.Menus.Default)); @@ -84,6 +92,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["GlobalResources"], "/Cms/GlobalResources", "fa fa-newspaper") + .RequireFeatures(CmsKitFeatures.GlobalResourceEnable) .RequireGlobalFeatures(typeof(GlobalResourcesFeature)) .RequirePermissions(CmsKitAdminPermissions.GlobalResources.Default)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj index 107aa14452..d117a4e080 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs new file mode 100644 index 0000000000..597e5240e8 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs @@ -0,0 +1,73 @@ +using Volo.Abp.Features; +using Volo.Abp.Localization; +using Volo.Abp.Validation.StringValues; +using Volo.CmsKit.Localization; + +namespace Volo.CmsKit.Features; +public class CmsKitFeatureDefinitionProvider : FeatureDefinitionProvider +{ + public override void Define(IFeatureDefinitionContext context) + { + var group = context.AddGroup(CmsKitFeatures.GroupName, + L("Feature:CmsKitGroup")); + + group.AddFeature(CmsKitFeatures.BlogEnable, + "true", + L("Feature:BlogEnable"), + L("Feature:BlogEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.CommentEnable, + "true", + L("Feature:CommentEnable"), + L("Feature:CommentEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.GlobalResourceEnable, + "true", + L("Feature:GlobalResourceEnable"), + L("Feature:GlobalResourceEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.MediaEnable, + "true", + L("Feature:MediaEnable"), + L("Feature:MediaEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.MenuEnable, + "true", + L("Feature:MenuEnable"), + L("Feature:MenuEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.PageEnable, + "true", + L("Feature:PageEnable"), + L("Feature:PageEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.RatingEnable, + "true", + L("Feature:RatingEnable"), + L("Feature:RatingEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.ReactionEnable, + "true", + L("Feature:ReactionEnable"), + L("Feature:ReactionEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.TagEnable, + "true", + L("Feature:TagEnable"), + L("Feature:TagEnableDescription"), + new ToggleStringValueType()); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs new file mode 100644 index 0000000000..1dbf642755 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs @@ -0,0 +1,15 @@ +namespace Volo.CmsKit.Features; +public static class CmsKitFeatures +{ + public const string GroupName = "CmsKit"; + + public const string BlogEnable = GroupName + ".BlogEnable"; + public const string CommentEnable = GroupName + ".CommentEnable"; + public const string GlobalResourceEnable = GroupName + ".GlobalResourceEnable"; + public const string MediaEnable = GroupName + ".MediaEnable"; + public const string MenuEnable = GroupName + ".MenuEnable"; + public const string PageEnable = GroupName + ".PageEnable"; + public const string RatingEnable = GroupName + ".RatingEnable"; + public const string ReactionEnable = GroupName + ".ReactionEnable"; + public const string TagEnable = GroupName + ".TagEnable"; +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs index 47f20e1d72..7787d0c69d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalResources/GlobalResourceConsts.cs @@ -1,6 +1,6 @@ namespace Volo.CmsKit.GlobalResources; -public class GlobalResourceConsts +public static class GlobalResourceConsts { public const string GlobalStyleName = "GlobalStyle"; diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 8da6be8bd5..6057b5dc5e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -185,8 +185,27 @@ "Add": "Add", "AddWidget": "Add Widget", "PleaseConfigureWidgets": "Please configure widgets", - "SelectAnAuthor":"Select an Author", - "InThisDocument":"In This Document", - "GoToTop":"Go To Top" + "SelectAnAuthor": "Select an Author", + "InThisDocument": "In This Document", + "GoToTop": "Go To Top", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Enabled blog page", + "Feature:BlogEnableDescription": "Enable blog page in the application.", + "Feature:CommentEnable": "Enabled commenting", + "Feature:CommentEnableDescription": "Enable comment in the application.", + "Feature:GlobalResourceEnable": "Enabled global resourcing", + "Feature:GlobalResourceEnableDescription": "Enable global resource in the application.", + "Feature:MediaEnable": "Enabled media", + "Feature:MediaEnableDescription": "Enable media in the application.", + "Feature:MenuEnable": "Enabled menu", + "Feature:MenuEnableDescription": "Enable menu in the application.", + "Feature:PageEnable": "Enabled paging page", + "Feature:PageEnableDescription": "Enable paging page in the application.", + "Feature:RatingEnable": "Enabled rating", + "Feature:RatingEnableDescription": "Enable rating in the application.", + "Feature:ReactionEnable": "Enabled reaction", + "Feature:ReactionEnableDescription": "Enable reaction in the application.", + "Feature:TagEnable": "Enabled taging", + "Feature:TagEnableDescription": "Enable taging in the application." } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index 431c50596c..c8865aa648 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -190,6 +190,25 @@ "CmsKit.BlogPost.ScrollIndex": "Blog yazılarında hızlı gezinme çubuğu", "Add": "Ekle", "AddWidget": "Widget Ekle", - "PleaseConfigureWidgets": "Lütfen widget'leri yapılandırın" + "PleaseConfigureWidgets": "Lütfen widget'leri yapılandırın", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Blog sayfasını etkinleştirin", + "Feature:BlogEnableDescription": "Uygulamınızdaki blog sayfasını etkinleştirir.", + "Feature:CommentEnable": "Yorum özelliğini etkinleştirin", + "Feature:CommentEnableDescription": "Uygulamınızdaki yorum özelliğini etkinleştirir.", + "Feature:GlobalResourceEnable": "Blog global kaynakları etkinleştirin", + "Feature:GlobalResourceEnableDescription": "Uygulamınızdaki global kaynakları etkinleştirir.", + "Feature:MediaEnable": "Medyayı etkinleştirin", + "Feature:MediaEnableDescription": "Uygulamınızdaki medyayı etkinleştirir.", + "Feature:MenuEnable": "Menüyü etkinleştirin", + "Feature:MenuEnableDescription": "Uygulamınızdaki menüyü etkinleştirir.", + "Feature:PageEnable": "Sayfa özelliğini etkinleştirin", + "Feature:PageEnableDescription": "Uygulamınızdaki sayfa özelliğini etkinleştirir.", + "Feature:RatingEnable": "Oylamayı etkinleştirin", + "Feature:RatingEnableDescription": "Uygulamınızdaki oylamayı etkinleştirir.", + "Feature:ReactionEnable": "Reaksiyonları etkinleştirin", + "Feature:ReactionEnableDescription": "Uygulamınızdaki reaksiyonları etkinleştirir.", + "Feature:TagEnable": "Etkiketleri etkinleştirin", + "Feature:TagEnableDescription": "Uygulamınızdaki etiketleri etkinleştirir." } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs index 16e0575288..5d1ba87fe0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/GlobalResources/GlobalResourceDto.cs @@ -1,8 +1,12 @@ -namespace Volo.CmsKit.Public.GlobalResources; +using System; +using Volo.Abp.Application.Dtos; -public class GlobalResourceDto +namespace Volo.CmsKit.Public.GlobalResources; + +[Serializable] +public class GlobalResourceDto : AuditedEntityDto { public string Name { get; set; } - + public string Value { get; set; } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs index 80185f7bea..87e851431d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs @@ -1,16 +1,19 @@ -using JetBrains.Annotations; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using JetBrains.Annotations; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPublicAppService { @@ -38,7 +41,7 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub var blogPostDto = ObjectMapper.Map(blogPost); blogPostDto.ContentFragments = await ContentParser.ParseAsync(blogPost.Content); - + return blogPostDto; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs index b1fae564d2..ef7e6be9fd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs @@ -1,20 +1,23 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization; using Volo.Abp.Data; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; using Volo.CmsKit.Comments; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs index 2debf10ed5..af0d1fbf39 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs @@ -1,11 +1,14 @@ using System.Threading.Tasks; using Volo.Abp.Application.Services; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalResources; namespace Volo.CmsKit.Public.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] public class GlobalResourcePublicAppService : ApplicationService, IGlobalResourcePublicAppService { @@ -15,18 +18,18 @@ public class GlobalResourcePublicAppService : ApplicationService, IGlobalResourc { GlobalResourceManager = globalResourceManager; } - + public async Task GetGlobalScriptAsync() { var globalScript = await GlobalResourceManager.GetGlobalScriptAsync(); - + return ObjectMapper.Map(globalScript); } - + public async Task GetGlobalStyleAsync() { var globalStyle = await GlobalResourceManager.GetGlobalStyleAsync(); - + return ObjectMapper.Map(globalStyle); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs index 1e9503006c..d16e271e4e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/Handlers/GlobalResourceEventHandler.cs @@ -5,11 +5,10 @@ using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EventBus; using Volo.Abp.ObjectMapping; using Volo.CmsKit.GlobalResources; -using Volo.CmsKit.Public.GlobalResources; namespace Volo.CmsKit.Public.GlobalResources.Handlers; -public class GlobalResourceEventHandler: +public class GlobalResourceEventHandler : ILocalEventHandler>, ITransientDependency { @@ -23,11 +22,11 @@ public class GlobalResourceEventHandler: ObjectMapper = objectMapper; _resourceCache = resourceCache; } - + public async Task HandleEventAsync(EntityUpdatedEventData eventData) { await _resourceCache.SetAsync( - eventData.Entity.Name, + eventData.Entity.Name, ObjectMapper.Map(eventData.Entity)); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs index 11a58d5935..0e9062d9af 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Caching; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; namespace Volo.CmsKit.Public.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] public class MenuItemPublicAppService : CmsKitPublicAppServiceBase, IMenuItemPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs index 2bae7c350f..f20a181e9b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs @@ -1,11 +1,14 @@ using System.Threading.Tasks; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pages; namespace Volo.CmsKit.Public.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] public class PagePublicAppService : CmsKitPublicAppServiceBase, IPagePublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs index 87ea0531db..f3b46c518b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Authorization; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Ratings; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Ratings; +[RequiresFeature(CmsKitFeatures.RatingEnable)] [RequiresGlobalFeature(typeof(RatingsFeature))] public class RatingPublicAppService : CmsKitPublicAppServiceBase, IRatingPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs index b12f659d23..1151578d57 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs @@ -1,17 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; -using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Reactions; namespace Volo.CmsKit.Public.Reactions; +[RequiresFeature(CmsKitFeatures.ReactionEnable)] [RequiresGlobalFeature(typeof(ReactionsFeature))] public class ReactionPublicAppService : CmsKitPublicAppServiceBase, IReactionPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs index be28afa6a4..e5d2570e21 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs @@ -3,13 +3,16 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs index afbf11e843..f77444431e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs @@ -3,11 +3,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs index 8b58a00f9a..635e228e0b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs @@ -1,16 +1,19 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] [Route("api/cms-kit-public/global-resources")] -public class GlobalResourcePublicController: CmsKitPublicControllerBase, IGlobalResourcePublicAppService +public class GlobalResourcePublicController : CmsKitPublicControllerBase, IGlobalResourcePublicAppService { private readonly IGlobalResourcePublicAppService _globalResourcePublicAppService; @@ -18,14 +21,14 @@ public class GlobalResourcePublicController: CmsKitPublicControllerBase, IGlobal { _globalResourcePublicAppService = globalResourcePublicAppService; } - + [HttpGet] [Route("script")] public Task GetGlobalScriptAsync() { return _globalResourcePublicAppService.GetGlobalScriptAsync(); } - + [HttpGet] [Route("style")] public Task GetGlobalStyleAsync() diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs index fc8820c1b2..3eb00439fb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; namespace Volo.CmsKit.Public.Menus; -[RequiresGlobalFeature(typeof(BlogsFeature))] +[RequiresFeature(CmsKitFeatures.MenuEnable)] +[RequiresGlobalFeature(typeof(MenuFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] [Route("api/cms-kit-public/menu-items")] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs index cd65f84c26..22f2bd75bd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs @@ -1,12 +1,15 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs index 11e8d22a69..f793aaefc4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs @@ -2,11 +2,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Ratings; +[RequiresFeature(CmsKitFeatures.RatingEnable)] [RequiresGlobalFeature(typeof(RatingsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs index 4a9df74df7..6242e253a2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs @@ -2,11 +2,14 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Reactions; +[RequiresFeature(CmsKitFeatures.ReactionEnable)] [RequiresGlobalFeature(typeof(ReactionsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs index ec45901118..1620f136da 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs @@ -1,13 +1,16 @@ -using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Public.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml index 11929dec03..fdcfb382bb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml @@ -1 +1,3 @@ - +@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style.GlobalStyleModel + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs new file mode 100644 index 0000000000..869f768987 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleModel.cs @@ -0,0 +1,6 @@ +namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style; + +public class GlobalStyleModel +{ + public long LastModificationTimeTimestamp { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs index 3d9bc010c4..49062bdb06 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/GlobalResources/Style/GlobalStyleViewComponent.cs @@ -1,13 +1,33 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Public.GlobalResources; namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.GlobalResources.Style; public class GlobalStyleViewComponent : AbpViewComponent { + protected IGlobalResourcePublicAppService GlobalResourcePublicAppService { get; } + + public GlobalStyleViewComponent(IGlobalResourcePublicAppService globalResourcePublicAppService) + { + GlobalResourcePublicAppService = globalResourcePublicAppService; + } + + [BindProperty(SupportsGet = true)] + public DateTime? LastModificationTime { get; set; } + public async Task InvokeAsync() { - return View("~/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml"); + var lastModificationTime = (await GlobalResourcePublicAppService.GetGlobalStyleAsync())?.LastModificationTime; + var lastModificationTimeTimestamp = (long)(lastModificationTime.HasValue ? lastModificationTime.Value.Subtract(DateTime.UnixEpoch).TotalSeconds : 0); + + return View("~/Pages/CmsKit/Shared/Components/GlobalResources/Style/Default.cshtml", + new GlobalStyleModel() + { + LastModificationTimeTimestamp = lastModificationTimeTimestamp + }); } + } \ No newline at end of file diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs index 1927c21746..66a15fd051 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs @@ -27,4 +27,10 @@ public class AbpIdentityServerBuilderOptions /// Set false to suppress AddDeveloperSigningCredential() call on the IIdentityServerBuilder. /// public bool AddDeveloperSigningCredential { get; set; } = true; + + /// + /// Adds the default cookie handlers and corresponding configuration + /// Default: true, Set false to suppress AddCookieAuthentication() call on the IIdentityServerBuilder. + /// + public bool AddIdentityServerCookieAuthentication { get; set; } = true; } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index 96ab4abd89..9b9dde5c96 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using IdentityServer4.Configuration; using IdentityServer4.Services; using IdentityServer4.Stores; using Microsoft.Extensions.DependencyInjection; @@ -71,13 +72,7 @@ public class AbpIdentityServerDomainModule : AbpModule var configuration = services.GetConfiguration(); var builderOptions = services.ExecutePreConfiguredActions(); - var identityServerBuilder = services.AddIdentityServer(options => - { - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseSuccessEvents = true; - }); + var identityServerBuilder = AddIdentityServer(services, builderOptions); if (builderOptions.AddDeveloperSigningCredential) { @@ -110,6 +105,37 @@ public class AbpIdentityServerDomainModule : AbpModule } } + private static IIdentityServerBuilder AddIdentityServer(IServiceCollection services, AbpIdentityServerBuilderOptions abpIdentityServerBuilderOptions) + { + services.Configure(options => + { + options.Events.RaiseErrorEvents = true; + options.Events.RaiseInformationEvents = true; + options.Events.RaiseFailureEvents = true; + options.Events.RaiseSuccessEvents = true; + }); + + var identityServerBuilder = services.AddIdentityServerBuilder() + .AddRequiredPlatformServices() + .AddCoreServices() + .AddDefaultEndpoints() + .AddPluggableServices() + .AddValidators() + .AddResponseGenerators() + .AddDefaultSecretParsers() + .AddDefaultSecretValidators(); + + if (abpIdentityServerBuilderOptions.AddIdentityServerCookieAuthentication) + { + identityServerBuilder.AddCookieAuthentication(); + } + + // provide default in-memory implementation, not suitable for most production scenarios + identityServerBuilder.AddInMemoryPersistedGrants(); + + return identityServerBuilder; + } + public override void PostConfigureServices(ServiceConfigurationContext context) { OneTimeRunner.Run(() => diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs index e0ce655235..5b388d9078 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/AbpTenantManagementDomainSharedModule.cs @@ -1,6 +1,7 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.TenantManagement.Localization; +using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Validation; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -25,5 +26,10 @@ public class AbpTenantManagementDomainSharedModule : AbpModule typeof(AbpValidationResource) ).AddVirtualJson("/Volo/Abp/TenantManagement/Localization/Resources"); }); + + Configure(options => + { + options.MapCodeNamespace("Volo.Abp.TenantManagement", typeof(AbpTenantManagementResource)); + }); } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json index 267165038c..8146974400 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json @@ -1,6 +1,7 @@ { "culture": "ar", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "اسم المستأجر موجود بالفعل: {Name}", "Menu:TenantManagement": "إدارة الجهات", "Tenants": "الجهات", "NewTenant": "جهة جديدة", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json index c744619234..58d71c9252 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json @@ -1,6 +1,7 @@ { "culture": "de-DE", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Der Name des Mandanten ist bereits vorhanden: {Name}", "Menu:TenantManagement": "Mandantenverwaltung", "Tenants": "Mandanten", "NewTenant": "Neuer Mandant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json index da222e994d..e639feb5f3 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json @@ -1,6 +1,7 @@ { "culture": "en", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Tenant name already exist: {Name}", "Menu:TenantManagement": "Tenant management", "Tenants": "Tenants", "NewTenant": "New tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json index a570c4a84e..bcbfc98852 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json @@ -1,6 +1,7 @@ { "culture": "es", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "El nombre del inquilino ya existe: {Name}", "Menu:TenantManagement": "Gestión de tenants", "Tenants": "Inquilinos", "NewTenant": "Nuevo inquilino", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json index 3bd039ffcf..179ec3c1d6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json @@ -1,6 +1,7 @@ { "culture": "fi", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Vuokralaisen nimi on jo olemassa: {Name}", "Menu:TenantManagement": "Vuokralaisten hallinta", "Tenants": "Vuokralaiset", "NewTenant": "Uusi vuokralainen", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json index 771a1e1fd5..3537ca8ca6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json @@ -1,6 +1,7 @@ { "culture": "fr", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Le nom du locataire existe déjà: {Name}", "Menu:TenantManagement": "Gestion des locataires", "Tenants": "Locataires", "NewTenant": "Nouveau locataire", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json index 45e5de55c0..70367305a9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json @@ -1,6 +1,7 @@ { "culture": "hi", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "किरायेदार नाम पहले से मौजूद है: {Name}", "Menu:TenantManagement": "किरायेदार प्रबंधन", "Tenants": "किरायेदारों", "NewTenant": "नया किरायेदार", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json index efc7cb2f6b..5d95e2039c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json @@ -1,6 +1,7 @@ { "culture": "it", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Il nome del tenant esiste già: {Name}", "Menu:TenantManagement": "Gestione tenants", "Tenants": "Tenants", "NewTenant": "Nuovo Tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json index 9d0771ed9e..d9f6b14a69 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json @@ -1,6 +1,7 @@ { "culture": "pt-BR", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "O nome do ambiente já existe: {Name}", "Menu:TenantManagement": "Gerencimento de Inquilinos", "Tenants": "Inquilinos", "NewTenant": "Novo Inquilino", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json index b737b7ee24..2204cf35cf 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json @@ -1,6 +1,7 @@ { "culture": "ru", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Имя арендатора уже существует: {Name}", "Menu:TenantManagement": "Управление арендаторами", "Tenants": "Арендаторы", "NewTenant": "Новый арендатор", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json index 0689dee0e2..1aff65e71c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json @@ -1,6 +1,7 @@ { "culture": "sk", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Názov tenanta už existuje: {Name}", "Menu:TenantManagement": "Správa tenantov", "Tenants": "Tentanti", "NewTenant": "Nový tenant", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json index bc2d857331..a21cfa702a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json @@ -1,6 +1,7 @@ { "culture": "sl", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Ime najemnika že obstaja: {Name}", "Menu:TenantManagement": "Upravljanje najemnikov", "Tenants": "Najemniki", "NewTenant": "Nov najemnik", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json index 933f4a4650..409aa40795 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json @@ -1,6 +1,7 @@ { "culture": "tr", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "Müşteri ismi zaten mevcut: {Name}", "Menu:TenantManagement": "Müşteri yönetimi", "Tenants": "Müşteriler", "NewTenant": "Yeni müşteri", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json index 1e8e98412a..0367489a5a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json @@ -1,6 +1,7 @@ { "culture": "zh-Hans", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "租户名称已存在: {Name}", "Menu:TenantManagement": "租户管理", "Tenants": "租户", "NewTenant": "新租户", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json index 200dde595f..59519aff67 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json @@ -1,6 +1,7 @@ { "culture": "zh-Hant", "texts": { + "Volo.Abp.TenantManagement:DuplicateTenantName": "租戶名稱已存在: {Name}", "Menu:TenantManagement": "租戶管理", "Tenants": "租戶", "NewTenant": "新租戶", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs index 8fc75d2ecb..fa388426d9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs @@ -36,7 +36,7 @@ public class TenantManager : DomainService, ITenantManager var tenant = await TenantRepository.FindByNameAsync(name); if (tenant != null && tenant.Id != expectedId) { - throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..? + throw new BusinessException("Volo.Abp.TenantManagement:DuplicateTenantName").WithData("Name", name); } } } diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs index 6b86c8503c..b797e05566 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs @@ -66,7 +66,7 @@ public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase [Fact] public async Task CreateAsync_Should_Not_Allow_Duplicate_Names() { - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme", AdminEmailAddress = "admin@admin.com", AdminPassword = "123456" }); }); @@ -90,7 +90,7 @@ public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase { var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme")); - await Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" }); }); diff --git a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs index fcacb22e37..161882e412 100644 --- a/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs +++ b/modules/tenant-management/test/Volo.Abp.TenantManagement.Domain.Tests/Volo/Abp/TenantManagement/TenantManager_Tests.cs @@ -26,7 +26,7 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase [Fact] public async Task Create_Tenant_Name_Can_Not_Duplicate() { - await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.CreateAsync("volosoft")); } [Fact] @@ -46,6 +46,6 @@ public class TenantManager_Tests : AbpTenantManagementDomainTestBase var tenant = await _tenantRepository.FindByNameAsync("acme"); tenant.ShouldNotBeNull(); - await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); + await Assert.ThrowsAsync(async () => await _tenantManager.ChangeNameAsync(tenant, "volosoft")); } } diff --git a/npm/ng-packs/.gitignore b/npm/ng-packs/.gitignore index 326e29324e..b542c2b12d 100644 --- a/npm/ng-packs/.gitignore +++ b/npm/ng-packs/.gitignore @@ -54,3 +54,5 @@ Thumbs.db !**/[Pp]ackages/* *.internal.* + +.angular diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 953d2d5f93..ae2b77443e 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -34,7 +34,9 @@ "dev:schematics": "tsc -p packages/schematics/tsconfig.json -w", "ci": "yarn affected:lint && yarn affected:build && yarn affected:test", "lerna": "lerna", - "migrate-nx": "yarn nx migrate --run-migrations" + "migrate-nx": "yarn nx migrate --run-migrations", + "mock:schematics": "cd scripts/mock-schematic && yarn && yarn start", + "debug:schematics": "./node_modules/.bin/ng g ./packages/schematics/src/collection.json:proxy-add --module __default --apiName __default --source __default --target __default --url http://localhost:4300" }, "private": true, "devDependencies": { diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 7873adf6ea..99d435c891 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -39,7 +39,7 @@ >
-
+