diff --git a/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/cover.png b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/cover.png new file mode 100644 index 0000000000..69116d7961 Binary files /dev/null and b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/cover.png differ diff --git a/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/images/sitemap-architecture.svg b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/images/sitemap-architecture.svg new file mode 100644 index 0000000000..57721c4550 --- /dev/null +++ b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/images/sitemap-architecture.svg @@ -0,0 +1,122 @@ + + + + + + + + + + Sitemap Module Architecture + + + 1. Discovery Layer + + RazorPageDiscoveryService + + • Scans assemblies + • Finds PageModel classes + • Extracts route metadata + + + + + + 2. Source Layer + + + + IStaticPageSitemapSource + + Processes attributes: + [IncludeSitemapXml] + Returns static page + sitemap items + + + + IGroupedSitemapSource + + Queries repositories: + Books, Articles, Products + Returns dynamic + sitemap items + + + + Custom Sources + + Implement + ISitemapItemSource + for custom logic + + + + + + + + 3. Collection Layer + + SitemapItemCollector + + • Aggregates items from all sources + • Groups by category (Main, Blog, Products) + • Removes duplicates + • Returns Dictionary<Group, Items> + + + + + + 4. Generation Layer + + SitemapXmlGenerator + + • Converts items to XML format + • Adds <loc>, <lastmod>, <priority> + • Validates against sitemap protocol + • Returns XML string + + + + + + 5. Management Layer + + + + SitemapFileGenerator + + • Orchestrates collection + • Calls XML generator + • Writes files to disk: + Sitemaps/ + + + + SitemapRegenerationWorker + + • Runs periodically (e.g., hourly) + • Triggers SitemapFileGenerator + • Non-blocking background execution + + + + + + 📄 sitemap.xml + 📄 sitemap-Blog.xml + 📄 sitemap-Products.xml + + + + diff --git a/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/post.md b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/post.md new file mode 100644 index 0000000000..fd9d10756e --- /dev/null +++ b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/post.md @@ -0,0 +1,475 @@ +# Building Dynamic XML Sitemaps with ABP Framework + +Search Engine Optimization (SEO) is crucial for any web application that wants to be discovered by users. One of the most fundamental SEO practices is providing a comprehensive XML sitemap that helps search engines crawl and index your website efficiently. In this article, we'll use a reusable ABP module that automatically generates dynamic XML sitemaps for both static Razor Pages and dynamic content from your database. + +By the end of this tutorial, you'll have a production-ready sitemap solution that discovers your pages automatically, includes dynamic content like blog posts or products, and regenerates sitemaps in the background without impacting performance. + +## What is an XML Sitemap? + +An XML sitemap is a file that lists all important pages of your website in a structured format that search engines can easily read. It acts as a roadmap for crawlers like Google, Bing, and others, telling them which pages exist, when they were last updated, and how they relate to each other. + +For modern web applications with dynamic content, manually maintaining sitemap files quickly becomes impractical. A dynamic sitemap solution that automatically discovers and updates URLs is essential for: + +- **Large content sites** with frequently changing blog posts, articles, or products +- **Multi-tenant applications** where each tenant may have different content +- **Enterprise applications** with complex page hierarchies +- **E-commerce platforms** with thousands of product pages + +## Why Build a Custom Sitemap Module? + +While there are general-purpose sitemap libraries available, building a custom module for ABP Framework provides several advantages: + +✅ **Deep ABP Integration**: Leverages ABP's dependency injection, background workers, and module system +✅ **Automatic Discovery**: Uses ASP.NET Core's Razor Page infrastructure to automatically find pages +✅ **Type-Safe Configuration**: Strongly-typed attributes and options for configuration +✅ **Multi-Group Support**: Organize sitemaps by logical groups (main, blog, products, etc.) +✅ **Background Generation**: Non-blocking sitemap regeneration using ABP's background worker system +✅ **Repository Integration**: Direct integration with ABP repositories for database entities + +## Project Architecture Overview + +Before using the module, let's understand its architecture: + +![Architecture Diagram](./images/sitemap-architecture.svg) + +The sitemap module consists of several key components: + +1. **Discovery Layer**: Discovers Razor Pages and their metadata using reflection +2. **Source Layer**: Defines contracts for providing sitemap items (static pages and dynamic content) +3. **Collection Layer**: Collects items from all registered sources +4. **Generation Layer**: Transforms collected items into XML format +5. **Management Layer**: Orchestrates file generation and background workers + +## Installation + +To get started, clone the demo repository which includes the sitemap module: + +```bash +git clone https://github.com/salihozkara/AbpSitemapDemo +cd AbpSitemapDemo +``` + +The repository contains the sitemap module in the `Modules/abp.sitemap/` directory. To use it in your own project, add a project reference: + +```xml + +``` + +## Module Configuration + +After installing the package, add the module to your ABP application's module class: + +```csharp +using Abp.Sitemap.Web; + +[DependsOn( + typeof(SitemapWebModule), // 👈 Add sitemap module + // ... other dependencies +)] +public class YourProjectWebModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // Configure sitemap options + Configure(options => + { + options.BaseUrl = "https://yourdomain.com"; // 👈 Your website URL + options.FolderPath = "Sitemaps"; // 👈 Where XML files are stored + options.WorkerPeriod = 3600000; // 👈 Regenerate every hour (in milliseconds) + }); + } +} +``` + +> **Note:** In ABP applications, BaseUrl can be resolved from AppUrlOptions to stay consistent with environment configuration. + +That's it! The module is now integrated and will automatically: +- Discover your Razor Pages +- Generate sitemap XML files on application startup +- Regenerate sitemaps in the background every hour + +## Usage Examples + +Let's explore practical examples of using the sitemap module. You can see complete working examples in the [AbpSitemapDemo repository](https://github.com/salihozkara/AbpSitemapDemo). + +### Example 1: Mark Static Pages + +The simplest way to include pages in your sitemap is using attributes: + +```csharp +using Abp.Sitemap.Web.Sitemap.Sources.Page.Attributes; + +namespace YourProject.Pages; + +[IncludeSitemapXml] // 👈 Include in default "Main" group +public class IndexModel : PageModel +{ + public void OnGet() + { + // Your page logic + } +} + +[IncludeSitemapXml(Group = "Help")] +public class FaqModel : PageModel +{ + public void OnGet() + { + // Your page logic + } +} +``` + +These pages will be automatically discovered and included in the sitemap XML files. + +### Example 2: Add Dynamic Content from Database + +For dynamic content like blog posts, products, or articles, create a custom sitemap source. Here's a complete example using a Book entity: + +```csharp +using Abp.Sitemap.Web.Sitemap.Core; +using Abp.Sitemap.Web.Sitemap.Sources.Group; +using Volo.Abp.DependencyInjection; + +namespace YourProject.Sitemaps; + +public class BookSitemapSource : GroupedSitemapItemSource, ITransientDependency +{ + public BookSitemapSource( + IReadOnlyRepository repository, + IAsyncQueryableExecuter executer) + : base(repository, executer, group: "Books") // 👈 Creates sitemap-Books.xml + { + Filter = x => x.IsPublished; // 👈 Only published books + } + + protected override Expression> Selector => + book => new SitemapItem( + book.Id.ToString(), // 👈 Unique identifier + $"/Books/Detail/{book.Id}", // 👈 URL pattern matching your route + book.LastModificationTime ?? book.CreationTime // 👈 Last modified date + ) + { + ChangeFrequency = "weekly", + Priority = 0.7 + }; +} +``` + +Key points: +- Inherits from `GroupedSitemapItemSource` +- Specifies the entity type (`Book`) +- Defines a group name ("Books") which creates `sitemap-Books.xml` +- Uses `Filter` to include only published books +- Maps entity properties to sitemap URLs using `Selector` +- Automatically registered via `ITransientDependency` + +### Example 3: Category-Based Dynamic Content + +For content with categories, you can build more complex URL patterns: + +```csharp +using Abp.Sitemap.Web.Sitemap.Core; +using Abp.Sitemap.Web.Sitemap.Sources.Group; + +namespace YourProject.Sitemaps; + +public class ArticleSitemapSource : GroupedSitemapItemSource
, ITransientDependency +{ + public ArticleSitemapSource( + IReadOnlyRepository
repository, + IAsyncQueryableExecuter executer) + : base(repository, executer, "Articles") + { + // Multiple filter conditions + Filter = x => x.IsPublished && + !x.IsDeleted && + x.PublishDate <= DateTime.Now; + } + + protected override Expression> Selector => + article => new SitemapItem( + article.Id.ToString(), + $"/blog/{article.Category.Slug}/{article.Slug}", // 👈 Category-based URL + article.LastModificationTime ?? article.CreationTime + ); +} +``` + +This example demonstrates: +- Multiple filter conditions for complex business logic +- Building URLs with category slugs + +## Testing Your Sitemaps + +After configuring the module, test your sitemap generation: + +### 1. Run Your Application + +```bash +dotnet run +``` + +The sitemaps are automatically generated on application startup. + +### 2. Check Generated Files + +Navigate to `{WebProject}/Sitemaps/` directory (at the root of your web project): + +``` +{WebProject} +└── Sitemaps/ + ├── sitemap.xml # Main group (static pages) + ├── sitemap-Books.xml # Books from database + ├── sitemap-Articles.xml # Articles from database + └── sitemap-Help.xml # Help pages +``` + +### 3. Verify XML Content + +Open `sitemap-Books.xml` and verify the structure: + +```xml + + + + https://yourdomain.com/Books/Detail/3a071e39-12c9-48d7-8c1e-3b4f5c6d7e8f + 2025-12-13 + + + https://yourdomain.com/Books/Detail/7b8c9d0e-1f2a-3b4c-5d6e-7f8g9h0i1j2k + 2025-12-10 + + +``` + +### 4. Test in Browser + +Visit the sitemap URLs directly (the module serves them from the root path): +- Main sitemap: `https://localhost:5001/sitemap.xml` +- Books sitemap: `https://localhost:5001/sitemap-Books.xml` + +> **Note:** The sitemaps are stored in `{WebProject}/Sitemaps/` directory and served directly from the root URL. + +## Advanced Configuration + +### Custom Regeneration Schedule + +Control when sitemaps are regenerated using cron expressions: + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + Configure(options => + { + options.BaseUrl = "https://yourdomain.com"; + options.WorkerCronExpression = "0 0 2 * * ?"; // 👈 Every day at 2 AM + // Or use period in milliseconds: + // options.WorkerPeriod = 7200000; // 2 hours + }); +} +``` + +### Environment-Specific Configuration + +Use different settings for development and production: + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + var configuration = context.Services.GetConfiguration(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); + + Configure(options => + { + if (hostingEnvironment.IsDevelopment()) + { + options.BaseUrl = "https://localhost:5001"; + options.WorkerPeriod = 300000; // 5 minutes for testing + } + else + { + options.BaseUrl = configuration["App:SelfUrl"]!; + options.WorkerPeriod = 3600000; // 1 hour in production + } + + options.FolderPath = "Sitemaps"; + }); +} +``` + +### Manual Sitemap Generation + +Trigger sitemap generation manually (useful for admin panels): + +```csharp +using Abp.Sitemap.Web.Sitemap.Management; + +public class SitemapManagementService : ITransientDependency +{ + private readonly SitemapFileGenerator _generator; + + public SitemapManagementService(SitemapFileGenerator generator) + { + _generator = generator; + } + + [Authorize("Admin")] + public async Task RegenerateSitemapsAsync() + { + await _generator.GenerateAsync(); // 👈 Manual regeneration + } +} +``` + +## Real-World Use Cases + +Here are practical scenarios where the sitemap module excels: + +### E-Commerce Platform +```csharp +// Products grouped by category +public class ProductSitemapSource : GroupedSitemapItemSource +{ + // Automatically includes all active products with stock +} + +// Separate sitemap for categories +public class CategorySitemapSource : GroupedSitemapItemSource +{ + // All browsable categories +} + +// Brand pages +public class BrandSitemapSource : GroupedSitemapItemSource +{ + // All active brands +} +``` + +Result: `sitemap-Products.xml`, `sitemap-Categories.xml`, `sitemap-Brands.xml` + +### Content Management System +```csharp +// Blog posts by date +public class BlogPostSitemapSource : GroupedSitemapItemSource +{ + // Filter by published date, priority based on view count +} + +// Static CMS pages +[IncludeSitemapXml] +public class AboutUsModel : PageModel { } +``` + +## Best Practices + +### 1. Group Related Content +Organize your sitemaps logically: +```csharp +// ✅ Good: Logical grouping +"Products", "Categories", "Brands", "Blog", "Help" + +// ❌ Bad: Everything in one group +"Main" // Contains 50,000 mixed URLs +``` + +### 2. Use Filters Wisely +```csharp +// ✅ Good: Only published, non-deleted content +Filter = x => x.IsPublished && + !x.IsDeleted && + x.PublishDate <= DateTime.Now + +// ❌ Bad: Including draft content +Filter = x => true // Everything included +``` + +### 3. Keep URLs Clean +```csharp +// ✅ Good: SEO-friendly URLs +$"/products/{product.Slug}" +$"/blog/{year}/{month}/{article.Slug}" + +// ❌ Bad: Technical IDs exposed +$"/product-detail?id={product.Id}" +``` + +## Troubleshooting + +### Sitemap Not Generated +**Problem:** No XML files in `{WebProject}/Sitemaps/` + +**Solutions:** +1. Check module is added to dependencies +2. Verify `SitemapOptions.BaseUrl` is configured +3. Check application logs for errors +4. Ensure the web project directory has write permissions + +### Pages Not Appearing +**Problem:** Some pages missing from sitemap + +**Solutions:** +1. Verify `[IncludeSitemapXml]` attribute is present +2. Check namespace imports: `using Abp.Sitemap.Web.Sitemap.Sources.Page.Attributes;` +3. Ensure PageModel classes are public +4. Check filter conditions in custom sources + +### Background Worker Not Running +**Problem:** Sitemaps not regenerating automatically + +**Solutions:** +1. Check `SitemapOptions.WorkerPeriod` is set +2. Verify background workers are enabled in ABP configuration +3. Check application logs for worker errors + +## Performance Considerations + +### Caching Strategy +Consider adding caching for frequently accessed sitemaps: + +```csharp +public class CachedSitemapFileGenerator : ITransientDependency +{ + private readonly SitemapFileGenerator _generator; + private readonly IDistributedCache _cache; + + public async Task GetOrGenerateAsync(string group) + { + var cacheKey = $"Sitemap:{group}"; + var cached = await _cache.GetStringAsync(cacheKey); + + if (cached != null) + return cached; + + await _generator.GenerateAsync(); + // Read and cache... + } +} +``` + +## Conclusion + +The ABP Sitemap module provides a production-ready solution for dynamic sitemap generation in ABP Framework applications. By leveraging ABP's architecture—dependency injection, repository pattern, and background workers—the module automatically discovers pages, includes dynamic content, and regenerates sitemaps without manual intervention. + +Key benefits: +✅ **Zero Configuration** for basic scenarios +✅ **Type-Safe** attribute-based configuration +✅ **Extensible** for complex business logic +✅ **Performance** optimized with background processing +✅ **SEO-Friendly** following XML sitemap standards + +Whether you're building a blog, e-commerce platform, or enterprise application, this module provides a solid foundation for search engine optimization. + +## Additional Resources + +### Documentation +- [ABP Framework Documentation](https://abp.io/docs/latest/) +- [ABP Background Workers](https://abp.io/docs/latest/framework/infrastructure/background-workers) +- [ABP Repository Pattern](https://abp.io/docs/latest/framework/architecture/domain-driven-design/repositories) +- [ABP Dependency Injection](https://abp.io/docs/latest/framework/fundamentals/dependency-injection) + +### Source Code +- [Complete Working Demo](https://github.com/salihozkara/AbpSitemapDemo) - Full implementation with examples + - [BookSitemapSource](https://github.com/salihozkara/AbpSitemapDemo/blob/master/AbpSitemapDemo/Pages/Books/Index.cshtml.cs#L23) - Entity-based source example + - [Index.cshtml](https://github.com/salihozkara/AbpSitemapDemo/blob/master/AbpSitemapDemo/Pages/Index.cshtml#L9) - Page attribute usage diff --git a/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/summary.md b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/summary.md new file mode 100644 index 0000000000..0c20291c95 --- /dev/null +++ b/docs/en/Community-Articles/2025-12-13-Building-Dynamic-XML-Sitemaps-With-ABP-Framework/summary.md @@ -0,0 +1 @@ +Learn how to use the ABP Sitemap module for automatic XML sitemap generation in your ABP Framework applications. \ No newline at end of file diff --git a/docs/en/studio/release-notes.md b/docs/en/studio/release-notes.md index c3f57deaaf..d2eba88e0f 100644 --- a/docs/en/studio/release-notes.md +++ b/docs/en/studio/release-notes.md @@ -9,6 +9,77 @@ This document contains **brief release notes** for each ABP Studio release. Release notes only include **major features** and **visible enhancements**. Therefore, they don't include all the development done in the related version. +## 2.1.3 (2025-12-15) Latest + +* Updated `createCommand` and CLI help for multi-tenancy. +* Fixed `BookController` templating problem. + +## 2.1.2 (2025-12-11) + +* Fixed `SLNX` files in templates for macOS. +* Fixed `DbMigrator` problem on nolayers template. + +## 2.1.1 (2025-12-11) + +* Fixed duplicate workspace seeding issue. +* Fixed books sample problems when solution is tiered. +* Added AI Management module to `abpmdl` file. +* Improved skip running initial tasks text. +* Fixed unit test failures. +* Added `LanguageManagementDbContext` table creation in tests. +* Removed `ConfigureHttpClientProxies` method. +* Fixed issue with adding new services to existing Microservices. +* Fixed AI Management template issues. +* Reverted browser notification overlay fix. + +## 2.1.0 (2025-12-08) + +* Enhanced Module Installation UI with improved user experience. +* Added `AI Management` option to Startup Templates (app-nolayers, app). +* Added support for new `SLNX` solution file format. +* Enhanced modularity step in solution creation process. +* Fixed Swagger authorization issues when projects run via .NET Aspire. +* Fixed browser notification overlay problems. +* Added missing `Unit of Work` namespace in solution templates. +* Fixed JSON file formatting issues. +* Updated ABP Framework to `10.0.1` and LeptonX to `5.0.1`. +* Added MySQL compatibility warnings. +* Fixed initial tasks problems. +* Improved AI Assistant control UI with better margins and borders. + +## 2.0.2 (2025-11-26) + +* Fixed `.NET 10` installation problems. +* Added custom styles for code blocks in **Markdown** view. +* Fixed `OpenIddictCoreOptions` injection to use `IOptions`. +* Added IdentityModel package after KubernetesClient. + +## 2.0.1 (2025-11-21) + +* Added build step before adding EF Core migration. +* Updated `KubernetesClient` to version `18.0.5`. + +## 2.0.0 (2025-11-20) + +* Major upgrade to `.NET 10.0` and `ABP Framework 10.0` +* Replaced `IdentityModel` with `Duende.IdentityModel`. +* Added "Open on Start in Browser" option for .NET applications in Solution Runner. +* Added `Mapperly` configuration. +* Enabled user and tenant impersonation in Blazor client modules. +* Enhanced notification system to allow text copying. +* Added environment variable support for DesignTime DbContext. +* Used C# instead of JSON for Aspire AppHost project configuration. +* Fixed MongoDB image pulling problems. +* Improved AI Assistant with better code block visibility across themes. +* Added different cache paths for each browser instance. +* Fixed various UI issues including mouse pointer problems in trees and horizontal scrolling. +* Added `FileManagement` download URL configuration for tiered projects. +* Added chat SignalR configuration to Microservice Blazor apps. +* Updated `Blazorise` packages to version `1.8.6`. +* Fixed `BackToImpersonator` button in Microservice Template. +* Added log recording while crashing for better debugging. +* Enhanced tab headers for **Solution Runner** and **Kubernetes**. + ## 1.4.2 (2025-10-30) * Upgraded template dependencies for ABP Framework and LeptonX. (targeting ABP `9.3.6`) diff --git a/docs/en/studio/version-mapping.md b/docs/en/studio/version-mapping.md index ba51cfb17d..f399c97390 100644 --- a/docs/en/studio/version-mapping.md +++ b/docs/en/studio/version-mapping.md @@ -11,6 +11,8 @@ This document provides a general overview of the relationship between various ve | **ABP Studio Version** | **ABP Version of Startup Template** | |------------------------|---------------------------| +| 2.1.0 - 2.1.3 | 10.0.1 | +| 2.0.0 to 2.0.2 | 10.0.0 | | 1.4.2 | 9.3.6 | | 1.3.3 to 1.4.1 | 9.3.5 | | 1.3.0 - 1.3.2 | 9.3.4 | @@ -19,8 +21,7 @@ This document provides a general overview of the relationship between various ve | 1.1.2 | 9.2.3 | | 1.1.0 - 1.1.1 | 9.2.2 | | 1.0.2 | 9.2.1 | -| 1.0.1 | 9.2.0 | -| 1.0.0 | 9.2.0 | +| 1.0.0 - 1.0.1 | 9.2.0 | | 0.9.26 | 9.1.1 | | 0.9.24 - 0.9.25 | 9.1.0 | | 0.9.22 - 0.9.23 | 9.0.4 | diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/AbpPermissionOptions.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/AbpPermissionOptions.cs index 4bdd7c0bb8..c240e1ac07 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/AbpPermissionOptions.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/AbpPermissionOptions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.Collections; namespace Volo.Abp.Authorization.Permissions; @@ -9,6 +10,8 @@ public class AbpPermissionOptions public ITypeList ValueProviders { get; } + public ITypeList ResourceValueProviders { get; } + public HashSet DeletedPermissions { get; } public HashSet DeletedPermissionGroups { get; } @@ -17,6 +20,7 @@ public class AbpPermissionOptions { DefinitionProviders = new TypeList(); ValueProviders = new TypeList(); + ResourceValueProviders = new TypeList(); DeletedPermissions = new HashSet(); DeletedPermissionGroups = new HashSet(); diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs index 828e4cbd01..2bcf9ba10d 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs @@ -11,4 +11,4 @@ public interface ICanAddChildPermission ILocalizableString? displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true); -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs index 7ff890bac7..5a1bef8e1d 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs @@ -1,5 +1,7 @@ using System; +using JetBrains.Annotations; using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Authorization.Permissions; @@ -46,4 +48,16 @@ public interface IPermissionDefinitionContext /// Name of the permission /// PermissionDefinition? GetPermissionOrNull(string name); + + PermissionDefinition AddResourcePermission( + string name, + string resourceName, + string managementPermissionName, + ILocalizableString? displayName = null, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + bool isEnabled = true); + + PermissionDefinition? GetResourcePermissionOrNull([NotNull] string resourceName, [NotNull] string name); + + void RemoveResourcePermission([NotNull] string resourceName, [NotNull] string name); } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs index ca04b110f7..d9411d54fa 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs @@ -11,7 +11,14 @@ public interface IPermissionDefinitionManager Task GetOrNullAsync([NotNull] string name); + [ItemNotNull] + Task GetResourcePermissionAsync([NotNull]string resourceName, [NotNull] string name); + + Task GetResourcePermissionOrNullAsync([NotNull]string resourceName, [NotNull] string name); + Task> GetPermissionsAsync(); + Task> GetResourcePermissionsAsync(); + Task> GetGroupsAsync(); } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs index ae9252632d..683f513cf4 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs @@ -6,7 +6,6 @@ public interface IPermissionValueProvider { string Name { get; } - //TODO: Rename to GetResult? (CheckAsync throws exception by naming convention) Task CheckAsync(PermissionValueCheckContext context); Task CheckAsync(PermissionValuesCheckContext context); diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs index 0f5d713e2b..c93992ed49 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs @@ -7,7 +7,7 @@ using Volo.Abp.SimpleStateChecking; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinition : +public class PermissionDefinition : IHasSimpleStateCheckers, ICanAddChildPermission { @@ -16,6 +16,16 @@ public class PermissionDefinition : /// public string Name { get; } + /// + /// Resource name of the permission. + /// + public string? ResourceName { get; set; } + + /// + /// Management permission of the resource permission. + /// + public string? ManagementPermissionName { get; set; } + /// /// Parent of this permission if one exists. /// If set, this permission can be granted only if parent is granted. @@ -76,6 +86,19 @@ public class PermissionDefinition : set => Properties[name] = value; } + protected internal PermissionDefinition( + [NotNull] string name, + string resourceName, + string managementPermissionName, + ILocalizableString? displayName = null, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + bool isEnabled = true) + : this(name, displayName, multiTenancySide, isEnabled) + { + ResourceName = Check.NotNull(resourceName, nameof(resourceName)); + ManagementPermissionName = Check.NotNull(managementPermissionName, nameof(managementPermissionName)); + } + protected internal PermissionDefinition( [NotNull] string name, ILocalizableString? displayName = null, @@ -99,6 +122,11 @@ public class PermissionDefinition : MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) { + if (ResourceName != null) + { + throw new AbpException($"Resource permission cannot have child permissions. Resource: {ResourceName}"); + } + var child = new PermissionDefinition( name, displayName, @@ -109,12 +137,12 @@ public class PermissionDefinition : }; child[PermissionDefinitionContext.KnownPropertyNames.CurrentProviderName] = this[PermissionDefinitionContext.KnownPropertyNames.CurrentProviderName]; - + _children.Add(child); return child; } - + PermissionDefinition ICanAddChildPermission.AddPermission( string name, ILocalizableString? displayName = null, @@ -124,7 +152,6 @@ public class PermissionDefinition : return this.AddChild(name, displayName, multiTenancySide, isEnabled); } - /// /// Sets a property in the dictionary. /// This is a shortcut for nested calls on this object. diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs index 394cdb9d82..c13f53866a 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; using JetBrains.Annotations; using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; namespace Volo.Abp.Authorization.Permissions; @@ -11,17 +13,20 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext public Dictionary Groups { get; } + public List ResourcePermissions { get; } + internal IPermissionDefinitionProvider? CurrentProvider { get; set; } public static class KnownPropertyNames { public const string CurrentProviderName = "_CurrentProviderName"; } - + public PermissionDefinitionContext(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; Groups = new Dictionary(); + ResourcePermissions = new List(); } public virtual PermissionGroupDefinition AddGroup( @@ -43,7 +48,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext } Groups[name] = group; - + return group; } @@ -51,37 +56,23 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext public virtual PermissionGroupDefinition GetGroup([NotNull] string name) { var group = GetGroupOrNull(name); - - if (group == null) - { - throw new AbpException($"Could not find a permission definition group with the given name: {name}"); - } - - return group; + return group ?? throw new AbpException($"Could not find a permission definition group with the given name: {name}"); } public virtual PermissionGroupDefinition? GetGroupOrNull([NotNull] string name) { Check.NotNull(name, nameof(name)); - - if (!Groups.ContainsKey(name)) - { - return null; - } - - return Groups[name]; + return Groups.GetOrDefault(name); } public virtual void RemoveGroup(string name) { Check.NotNull(name, nameof(name)); - if (!Groups.ContainsKey(name)) + if (!Groups.Remove(name)) { throw new AbpException($"Not found permission group with name: {name}"); } - - Groups.Remove(name); } public virtual PermissionDefinition? GetPermissionOrNull([NotNull] string name) @@ -100,4 +91,58 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext return null; } + + public virtual PermissionDefinition AddResourcePermission( + string name, + string resourceName, + string managementPermissionName, + ILocalizableString? displayName = null, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + bool isEnabled = true) + { + Check.NotNull(name, nameof(name)); + Check.NotNull(resourceName, nameof(resourceName)); + Check.NotNull(managementPermissionName, nameof(managementPermissionName)); + + if (ResourcePermissions.Any(x => x.ResourceName == resourceName && x.Name == name)) + { + throw new AbpException($"There is already an existing resource permission with name: {name} for resource: {resourceName}"); + } + + var permission = new PermissionDefinition( + name, + resourceName, + managementPermissionName, + displayName, + multiTenancySide, + isEnabled) + { + [KnownPropertyNames.CurrentProviderName] = CurrentProvider?.GetType().FullName + }; + + ResourcePermissions.Add(permission); + + return permission; + } + + public virtual PermissionDefinition? GetResourcePermissionOrNull([NotNull] string resourceName, [NotNull] string name) + { + Check.NotNull(resourceName, nameof(resourceName)); + Check.NotNull(name, nameof(name)); + + return ResourcePermissions.FirstOrDefault(p => p.ResourceName == resourceName && p.Name == name); + } + + public virtual void RemoveResourcePermission([NotNull] string resourceName, [NotNull] string name) + { + Check.NotNull(resourceName, nameof(resourceName)); + Check.NotNull(name, nameof(name)); + + var resourcePermission = GetResourcePermissionOrNull(resourceName, name); + if (resourcePermission == null) + { + throw new AbpException($"Not found resource permission with name: {name} for resource: {resourceName}"); + } + ResourcePermissions.Remove(resourcePermission); + } } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IHasResourcePermissions.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IHasResourcePermissions.cs new file mode 100644 index 0000000000..903f6bd2d6 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IHasResourcePermissions.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public interface IHasResourcePermissions : IKeyedObject +{ + Dictionary ResourcePermissions { get; } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionChecker.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionChecker.cs new file mode 100644 index 0000000000..0270d2c96b --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionChecker.cs @@ -0,0 +1,33 @@ +using System.Security.Claims; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public interface IResourcePermissionChecker +{ + Task IsGrantedAsync( + string name, + string resourceName, + string resourceKey + ); + + Task IsGrantedAsync( + ClaimsPrincipal? claimsPrincipal, + string name, + string resourceName, + string resourceKey + ); + + Task IsGrantedAsync( + string[] names, + string resourceName, + string resourceKey + ); + + Task IsGrantedAsync( + ClaimsPrincipal? claimsPrincipal, + string[] names, + string resourceName, + string resourceKey + ); +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionStore.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionStore.cs new file mode 100644 index 0000000000..42f751b4c5 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionStore.cs @@ -0,0 +1,83 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public interface IResourcePermissionStore +{ + /// + /// Checks if the given permission is granted for the given resource. + /// + /// The name of the permission. + /// The name of the resource. + /// Resource key + /// The name of the provider. + /// The key of the provider. + /// + /// True if the permission is granted. + /// + Task IsGrantedAsync( + string name, + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + /// + /// Checks if the given permissions are granted for the given resource. + /// + /// The name of the permissions. + /// The name of the resource. + /// Resource key + /// The name of the provider. + /// The key of the provider. + /// + /// A object containing the grant results for each permission. + /// + Task IsGrantedAsync( + string[] names, + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + /// + /// Gets all permissions for the given resource. + /// + /// Resource name + /// Resource key + /// + /// A object containing the grant results for each permission. + /// + Task GetPermissionsAsync( + string resourceName, + string resourceKey + ); + + /// + /// Gets all granted permissions for the given resource. + /// + /// Resource name + /// Resource key + /// + /// An array of granted permission names. + /// + Task GetGrantedPermissionsAsync( + string resourceName, + string resourceKey + ); + + /// + /// Retrieves the keys of resources for which the specified permission is granted. + /// + /// The name of the resource. + /// The name of the permission. + /// + /// An array of resource keys where the specified permission is granted. + /// + Task GetGrantedResourceKeysAsync( + string resourceName, + string name + ); +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..288b878e5d --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProvider.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public interface IResourcePermissionValueProvider +{ + string Name { get; } + + Task CheckAsync(ResourcePermissionValueCheckContext context); + + Task CheckAsync(ResourcePermissionValuesCheckContext context); +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProviderManager.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProviderManager.cs new file mode 100644 index 0000000000..e07e63d06a --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/IResourcePermissionValueProviderManager.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public interface IResourcePermissionValueProviderManager +{ + IReadOnlyList ValueProviders { get; } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/NullResourcePermissionStore.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/NullResourcePermissionStore.cs new file mode 100644 index 0000000000..84bf38ef42 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/NullResourcePermissionStore.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class NullResourcePermissionStore : IResourcePermissionStore, ISingletonDependency +{ + public ILogger Logger { get; set; } + + public NullResourcePermissionStore() + { + Logger = NullLogger.Instance; + } + + public Task IsGrantedAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return TaskCache.FalseResult; + } + + public Task IsGrantedAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + return Task.FromResult(new MultiplePermissionGrantResult(names, PermissionGrantResult.Prohibited)); + } + + public Task GetPermissionsAsync(string resourceName, string resourceKey) + { + return Task.FromResult(new MultiplePermissionGrantResult()); + } + + public Task GetGrantedPermissionsAsync(string resourceName, string resourceKey) + { + return Task.FromResult(Array.Empty()); + } + + public Task GetGrantedResourceKeysAsync(string resourceName, string name) + { + return Task.FromResult(Array.Empty()); + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionCheckerExtensions.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionCheckerExtensions.cs new file mode 100644 index 0000000000..c1d153b246 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionCheckerExtensions.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public static class ResourcePermissionCheckerExtensions +{ + /// + /// Checks if a specific permission is granted for a resource with a given key. + /// + /// The type of the resource. + /// The resource permission checker instance. + /// The name of the permission to check. + /// The resource instance to check permission for. + /// The unique key identifying the resource instance. + /// A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the permission is granted. + public static Task IsGrantedAsync( + this IResourcePermissionChecker resourcePermissionChecker, + string permissionName, + TResource resource, + object resourceKey + ) + { + Check.NotNull(resourcePermissionChecker, nameof(resourcePermissionChecker)); + Check.NotNullOrWhiteSpace(permissionName, nameof(permissionName)); + Check.NotNull(resource, nameof(resource)); + Check.NotNull(resourceKey, nameof(resourceKey)); + + return resourcePermissionChecker.IsGrantedAsync( + permissionName, + typeof(TResource).FullName!, + resourceKey.ToString()! + ); + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionGrantInfo.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionGrantInfo.cs new file mode 100644 index 0000000000..4eb9604454 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionGrantInfo.cs @@ -0,0 +1,21 @@ +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionGrantInfo : PermissionGrantInfo +{ + public string ResourceName { get; } + + public string ResourceKey { get; } + + public ResourcePermissionGrantInfo( + string name, + bool isGranted, + string resourceName, + string resourceKey, + string? providerName = null, + string? providerKey = null) + : base(name, isGranted, providerName, providerKey) + { + ResourceName = resourceName; + ResourceKey = resourceKey; + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionStoreExtensions.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionStoreExtensions.cs new file mode 100644 index 0000000000..f5604a7683 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionStoreExtensions.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public static class ResourcePermissionStoreExtensions +{ + /// + /// Retrieves the list of granted permissions for a specific resource with a given key. + /// + /// The type of the resource. + /// The resource permission store instance. + /// The resource instance to retrieve permissions for. + /// The unique key identifying the resource instance. + /// A task that represents the asynchronous operation. The task result contains an array of strings representing the granted permissions. + public static async Task GetGrantedPermissionsAsync( + this IResourcePermissionStore resourcePermissionStore, + TResource resource, + object resourceKey + ) + { + return (await GetPermissionsAsync(resourcePermissionStore, resource, resourceKey)).Where(x => x.Value).Select(x => x.Key).ToArray(); + } + + /// + /// Retrieves a dictionary of permissions and their granted status for the specified entity. + /// + /// The type of the resource. + /// The resource permission store instance. + /// The resource for which the permissions are being retrieved. + /// The unique key identifying the resource instance. + /// A dictionary where the keys are permission names and the values are booleans indicating whether the permission is granted. + public static async Task> GetPermissionsAsync( + this IResourcePermissionStore resourcePermissionStore, + TResource resource, + object resourceKey + ) + { + Check.NotNull(resourcePermissionStore, nameof(resourcePermissionStore)); + Check.NotNull(resource, nameof(resource)); + Check.NotNull(resourceKey, nameof(resourceKey)); + + var result = await resourcePermissionStore.GetPermissionsAsync( + typeof(TResource).FullName!, + resourceKey.ToString()! + ); + + return result.Result.ToDictionary(x => x.Key, x => x.Value == PermissionGrantResult.Granted); + } + + /// + /// Retrieves the keys of the resources granted a specific permission. + /// + /// The type of the resource. + /// The resource permission store instance. + /// The resource instance to check granted permissions for. + /// The name of the permission to check. + /// A task that represents the asynchronous operation. The task result contains an array of strings representing the granted resource keys. + public static Task GetGrantedResourceKeysAsync( + this IResourcePermissionStore resourcePermissionStore, + TResource resource, + string permissionName + ) + { + Check.NotNull(resourcePermissionStore, nameof(resourcePermissionStore)); + Check.NotNull(resource, nameof(resource)); + Check.NotNullOrWhiteSpace(permissionName, nameof(permissionName)); + + return resourcePermissionStore.GetGrantedResourceKeysAsync( + typeof(TResource).FullName!, + permissionName + ); + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueCheckContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueCheckContext.cs new file mode 100644 index 0000000000..dc8c78be64 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueCheckContext.cs @@ -0,0 +1,22 @@ +using System.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionValueCheckContext : PermissionValueCheckContext +{ + public string ResourceName { get; } + + public string ResourceKey { get; } + + public ResourcePermissionValueCheckContext(PermissionDefinition permission, string resourceName, string resourceKey) + : this(permission, null, resourceName, resourceKey) + { + } + + public ResourcePermissionValueCheckContext(PermissionDefinition permission, ClaimsPrincipal? principal, string resourceName, string resourceKey) + : base(permission, principal) + { + ResourceName = resourceName; + ResourceKey = resourceKey; + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..ff53f274ad --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public abstract class ResourcePermissionValueProvider : IResourcePermissionValueProvider, ITransientDependency +{ + public abstract string Name { get; } + + protected IResourcePermissionStore ResourcePermissionStore { get; } + + protected ResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) + { + ResourcePermissionStore = resourcePermissionStore; + } + + public abstract Task CheckAsync(ResourcePermissionValueCheckContext context); + + public abstract Task CheckAsync(ResourcePermissionValuesCheckContext context); +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValuesCheckContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValuesCheckContext.cs new file mode 100644 index 0000000000..239f74fc19 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValuesCheckContext.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionValuesCheckContext : PermissionValuesCheckContext +{ + public string ResourceName { get; } + + public string ResourceKey { get; } + + public ResourcePermissionValuesCheckContext(PermissionDefinition permission,string resourceName, string resourceKey) + : this([permission], null, resourceName, resourceKey) + { + + } + + + public ResourcePermissionValuesCheckContext(PermissionDefinition permission, ClaimsPrincipal? principal, string resourceName, string resourceKey) + : this([permission], principal, resourceName, resourceKey) + { + + } + + public ResourcePermissionValuesCheckContext(List permissions, string resourceName, string resourceKey) + : this(permissions, null, resourceName, resourceKey) + { + ResourceName = resourceName; + ResourceKey = resourceKey; + } + + public ResourcePermissionValuesCheckContext(List permissions, ClaimsPrincipal? principal, string resourceName, string resourceKey) + : base(permissions, principal) + { + ResourceName = resourceName; + ResourceKey = resourceKey; + } +} diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/ResourcePermissionRequirement.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/ResourcePermissionRequirement.cs new file mode 100644 index 0000000000..03658f3e90 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/ResourcePermissionRequirement.cs @@ -0,0 +1,21 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Authorization; + +namespace Volo.Abp.Authorization; + +public class ResourcePermissionRequirement : IAuthorizationRequirement +{ + public string PermissionName { get; } + + public ResourcePermissionRequirement([NotNull] string permissionName) + { + Check.NotNull(permissionName, nameof(permissionName)); + + PermissionName = permissionName; + } + + public override string ToString() + { + return $"ResourcePermissionRequirement: {PermissionName}"; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Microsoft/Extensions/DependencyInjection/KeyedObjectResourcePermissionExtenstions.cs b/framework/src/Volo.Abp.Authorization/Microsoft/Extensions/DependencyInjection/KeyedObjectResourcePermissionExtenstions.cs new file mode 100644 index 0000000000..e65d5174de --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Microsoft/Extensions/DependencyInjection/KeyedObjectResourcePermissionExtenstions.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Authorization; +using Volo.Abp.Authorization.Permissions.Resources; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class KeyedObjectResourcePermissionExtenstions +{ + public static IServiceCollection AddKeyedObjectResourcePermissionAuthorization(this IServiceCollection services) + { + services.AddSingleton(); + return services; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs index d8226bdee5..65b7e1b390 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Authorization.Localization; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; @@ -32,6 +33,7 @@ public class AbpAuthorizationModule : AbpModule { context.Services.AddAuthorizationCore(); + context.Services.AddKeyedObjectResourcePermissionAuthorization(); context.Services.AddSingleton(); context.Services.AddSingleton(); @@ -42,6 +44,9 @@ public class AbpAuthorizationModule : AbpModule options.ValueProviders.Add(); options.ValueProviders.Add(); options.ValueProviders.Add(); + + options.ResourceValueProviders.Add(); + options.ResourceValueProviders.Add(); }); Configure(options => diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs index 7958f2a979..a5bd19b539 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs @@ -40,6 +40,14 @@ public class AbpAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider return policyBuilder.Build(); } + if ((await _permissionDefinitionManager.GetResourcePermissionsAsync()).Any(x => x.Name == policyName)) + { + //TODO: Optimize & Cache! + var policyBuilder = new AuthorizationPolicyBuilder(Array.Empty()); + policyBuilder.Requirements.Add(new ResourcePermissionRequirement(policyName)); + return policyBuilder.Build(); + } + return null; } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs index 6316e38f52..6a34b21835 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/MethodInvocationAuthorizationService.cs @@ -20,7 +20,7 @@ public class MethodInvocationAuthorizationService : IMethodInvocationAuthorizati _abpAuthorizationService = abpAuthorizationService; } - public async Task CheckAsync(MethodInvocationAuthorizationContext context) + public virtual async Task CheckAsync(MethodInvocationAuthorizationContext context) { if (AllowAnonymous(context)) { diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs index 366ae2e58a..597b274035 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs @@ -8,6 +8,10 @@ public interface IDynamicPermissionDefinitionStore Task GetOrNullAsync(string name); Task> GetPermissionsAsync(); - + + Task GetResourcePermissionOrNullAsync(string resourceName, string name); + + Task> GetResourcePermissionsAsync(); + Task> GetGroupsAsync(); -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs index 4da8423dd3..da4055d771 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs @@ -8,6 +8,10 @@ public interface IStaticPermissionDefinitionStore Task GetOrNullAsync(string name); Task> GetPermissionsAsync(); - + + Task GetResourcePermissionOrNullAsync(string resourceName, string name); + + Task> GetResourcePermissionsAsync(); + Task> GetGroupsAsync(); -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs index 5b13288153..cf3a9820b4 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs @@ -9,10 +9,15 @@ namespace Volo.Abp.Authorization.Permissions; public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ISingletonDependency { private readonly static Task CachedPermissionResult = Task.FromResult((PermissionDefinition?)null); - + private readonly static Task> CachedPermissionsResult = Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + private readonly static Task CachedResourcePermissionResult = Task.FromResult((PermissionDefinition?)null); + + private readonly static Task> CachedResourcePermissionsResult = + Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + private readonly static Task> CachedGroupsResult = Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); @@ -26,8 +31,18 @@ public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinition return CachedPermissionsResult; } + public Task GetResourcePermissionOrNullAsync(string resourceName, string name) + { + return CachedResourcePermissionResult; + } + + public Task> GetResourcePermissionsAsync() + { + return CachedResourcePermissionsResult; + } + public Task> GetGroupsAsync() { return CachedGroupsResult; } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index 23f9e7883e..3dbc22fb47 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -34,17 +34,36 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi { Check.NotNull(name, nameof(name)); - return await _staticStore.GetOrNullAsync(name) ?? + return await _staticStore.GetOrNullAsync(name) ?? await _dynamicStore.GetOrNullAsync(name); } + public virtual async Task GetResourcePermissionAsync(string resourceName, string name) + { + var permission = await GetResourcePermissionOrNullAsync(resourceName, name); + if (permission == null) + { + throw new AbpException($"Undefined resource permission: {name} for resource: {resourceName}"); + } + + return permission; + } + + public virtual async Task GetResourcePermissionOrNullAsync(string resourceName, string name) + { + Check.NotNull(name, nameof(name)); + + return await _staticStore.GetResourcePermissionOrNullAsync(resourceName, name) ?? + await _dynamicStore.GetResourcePermissionOrNullAsync(resourceName, name); + } + public virtual async Task> GetPermissionsAsync() { var staticPermissions = await _staticStore.GetPermissionsAsync(); var staticPermissionNames = staticPermissions .Select(p => p.Name) .ToImmutableHashSet(); - + var dynamicPermissions = await _dynamicStore.GetPermissionsAsync(); /* We prefer static permissions over dynamics */ @@ -53,13 +72,28 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi ).ToImmutableList(); } - public async Task> GetGroupsAsync() + public virtual async Task> GetResourcePermissionsAsync() + { + var staticResourcePermissions = await _staticStore.GetResourcePermissionsAsync(); + var staticResourcePermissionNames = staticResourcePermissions + .Select(p => p.Name) + .ToImmutableHashSet(); + + var dynamicResourcePermissions = await _dynamicStore.GetResourcePermissionsAsync(); + + /* We prefer static permissions over dynamics */ + return staticResourcePermissions.Concat( + dynamicResourcePermissions.Where(d => !staticResourcePermissionNames.Contains(d.Name)) + ).ToImmutableList(); + } + + public virtual async Task> GetGroupsAsync() { var staticGroups = await _staticStore.GetGroupsAsync(); var staticGroupNames = staticGroups .Select(p => p.Name) .ToImmutableHashSet(); - + var dynamicGroups = await _dynamicStore.GetGroupsAsync(); /* We prefer static groups over dynamics */ @@ -67,4 +101,4 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)) ).ToImmutableList(); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionCheckerExtensions.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionCheckerExtensions.cs new file mode 100644 index 0000000000..e8b9e38218 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionCheckerExtensions.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public static class KeyedObjectResourcePermissionCheckerExtensions +{ + /// + /// Checks if the specified permission is granted for the given resource. + /// + /// The type of the object. + /// The resource permission checker instance. + /// The name of the permission to check. + /// The resource for which the permission is being checked. + /// A task that represents the asynchronous operation. The task result is a boolean indicating whether the permission is granted. + public static Task IsGrantedAsync(this IResourcePermissionChecker resourcePermissionChecker, string permissionName, TResource resource) + where TResource : class, IKeyedObject + { + Check.NotNull(resourcePermissionChecker, nameof(resourcePermissionChecker)); + Check.NotNullOrWhiteSpace(permissionName, nameof(permissionName)); + Check.NotNull(resource, nameof(resource)); + + return resourcePermissionChecker.IsGrantedAsync( + permissionName, + resource, + resource.GetObjectKey() ?? throw new AbpException("The resource doesn't have a key.") + ); + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionRequirementHandler.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionRequirementHandler.cs new file mode 100644 index 0000000000..e43b6d07b5 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionRequirementHandler.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class KeyedObjectResourcePermissionRequirementHandler : AuthorizationHandler +{ + protected readonly IResourcePermissionChecker PermissionChecker; + + public KeyedObjectResourcePermissionRequirementHandler(IResourcePermissionChecker permissionChecker) + { + PermissionChecker = permissionChecker; + } + + protected override async Task HandleRequirementAsync( + AuthorizationHandlerContext context, + ResourcePermissionRequirement requirement, + IKeyedObject? resource) + { + if (resource == null) + { + return; + } + + var resourceName = resource.GetType().FullName!; + var resourceKey = resource.GetObjectKey() ?? throw new AbpException("The resource doesn't have a key."); + + if (await PermissionChecker.IsGrantedAsync(context.User, requirement.PermissionName, resourceName, resourceKey)) + { + context.Succeed(requirement); + } + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionStoreExtensions.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionStoreExtensions.cs new file mode 100644 index 0000000000..3088950510 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/KeyedObjectResourcePermissionStoreExtensions.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public static class KeyedObjectResourcePermissionStoreExtensions +{ + /// + /// Retrieves an array of granted permissions for a specific entity. + /// + /// The type of the resource. + /// The resource permission store instance. + /// The resource for which the permissions are being checked. + /// An array of granted permission names as strings. + public static async Task GetGrantedPermissionsAsync( + this IResourcePermissionStore resourcePermissionStore, + TResource resource + ) + where TResource : class, IKeyedObject + { + Check.NotNull(resourcePermissionStore, nameof(resourcePermissionStore)); + Check.NotNull(resource, nameof(resource)); + + return (await GetPermissionsAsync(resourcePermissionStore, resource)).Where(x => x.Value).Select(x => x.Key).ToArray(); + } + + /// + /// Retrieves a dictionary of permissions and their granted status for the specified entity. + /// + /// The type of the entity. + /// The resource permission store instance. + /// The entity for which the permissions are being retrieved. + /// A dictionary where the keys are permission names and the values are booleans indicating whether the permission is granted. + public static async Task> GetPermissionsAsync( + this IResourcePermissionStore resourcePermissionStore, + TEntity entity + ) + where TEntity : class, IKeyedObject + { + Check.NotNull(resourcePermissionStore, nameof(resourcePermissionStore)); + Check.NotNull(entity, nameof(entity)); + + return await resourcePermissionStore.GetPermissionsAsync( + entity, + entity.GetObjectKey() ?? throw new AbpException("The entity doesn't have a key.") + ); + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionChecker.cs new file mode 100644 index 0000000000..a920c2e464 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionChecker.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Security.Claims; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionChecker : IResourcePermissionChecker, ITransientDependency +{ + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + protected ICurrentPrincipalAccessor PrincipalAccessor { get; } + protected ICurrentTenant CurrentTenant { get; } + protected IResourcePermissionValueProviderManager PermissionValueProviderManager { get; } + protected ISimpleStateCheckerManager StateCheckerManager { get; } + protected IPermissionChecker PermissionChecker { get; } + + public ResourcePermissionChecker( + ICurrentPrincipalAccessor principalAccessor, + IPermissionDefinitionManager permissionDefinitionManager, + ICurrentTenant currentTenant, + IResourcePermissionValueProviderManager permissionValueProviderManager, + ISimpleStateCheckerManager stateCheckerManager, + IPermissionChecker permissionChecker) + { + PrincipalAccessor = principalAccessor; + PermissionDefinitionManager = permissionDefinitionManager; + CurrentTenant = currentTenant; + PermissionValueProviderManager = permissionValueProviderManager; + StateCheckerManager = stateCheckerManager; + PermissionChecker = permissionChecker; + } + + public virtual async Task IsGrantedAsync(string name, string resourceName, string resourceKey) + { + return await IsGrantedAsync(PrincipalAccessor.Principal, name, resourceName, resourceKey); + } + + public virtual async Task IsGrantedAsync( + ClaimsPrincipal? claimsPrincipal, + string name, + string resourceName, + string resourceKey) + { + Check.NotNull(name, nameof(name)); + + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(resourceName, name); + if (permission == null) + { + return false; + } + + if (!permission.IsEnabled) + { + return false; + } + + if (!await StateCheckerManager.IsEnabledAsync(permission)) + { + return false; + } + + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() + ?? CurrentTenant.GetMultiTenancySide(); + + if (!permission.MultiTenancySide.HasFlag(multiTenancySide)) + { + return false; + } + + var isGranted = false; + var context = new ResourcePermissionValueCheckContext(permission, claimsPrincipal, resourceName, resourceKey); + foreach (var provider in PermissionValueProviderManager.ValueProviders) + { + if (context.Permission.Providers.Any() && + !context.Permission.Providers.Contains(provider.Name)) + { + continue; + } + + var result = await provider.CheckAsync(context); + + if (result == PermissionGrantResult.Granted) + { + isGranted = true; + } + else if (result == PermissionGrantResult.Prohibited) + { + return false; + } + } + + return isGranted; + } + + public async Task IsGrantedAsync(string[] names, string resourceName, string resourceKey) + { + return await IsGrantedAsync(PrincipalAccessor.Principal, names, resourceName, resourceKey); + } + + public async Task IsGrantedAsync(ClaimsPrincipal? claimsPrincipal, string[] names, string resourceName, string resourceKey) + { + Check.NotNull(names, nameof(names)); + + var result = new MultiplePermissionGrantResult(); + if (!names.Any()) + { + return result; + } + + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? + CurrentTenant.GetMultiTenancySide(); + + var permissionDefinitions = new List(); + foreach (var name in names) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(resourceName, name); + if (permission == null) + { + result.Result.Add(name, PermissionGrantResult.Prohibited); + continue; + } + + result.Result.Add(name, PermissionGrantResult.Undefined); + + if (permission.IsEnabled && + await StateCheckerManager.IsEnabledAsync(permission) && + permission.MultiTenancySide.HasFlag(multiTenancySide)) + { + permissionDefinitions.Add(permission); + } + } + + foreach (var provider in PermissionValueProviderManager.ValueProviders) + { + var permissions = permissionDefinitions + .Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name)) + .ToList(); + + if (permissions.IsNullOrEmpty()) + { + continue; + } + + var context = new ResourcePermissionValuesCheckContext( + permissions, + claimsPrincipal, + resourceName, + resourceKey); + + var multipleResult = await provider.CheckAsync(context); + foreach (var grantResult in multipleResult.Result.Where(grantResult => + result.Result.ContainsKey(grantResult.Key) && + result.Result[grantResult.Key] == PermissionGrantResult.Undefined && + grantResult.Value != PermissionGrantResult.Undefined)) + { + result.Result[grantResult.Key] = grantResult.Value; + permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key); + } + + if (result.AllGranted || result.AllProhibited) + { + break; + } + } + + return result; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionPopulator.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionPopulator.cs new file mode 100644 index 0000000000..91dfb509d4 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionPopulator.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionPopulator : ITransientDependency +{ + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + protected IResourcePermissionChecker ResourcePermissionChecker { get; } + protected IResourcePermissionStore ResourcePermissionStore { get; } + protected IPermissionChecker PermissionChecker { get; } + + public ResourcePermissionPopulator( + IPermissionDefinitionManager permissionDefinitionManager, + IResourcePermissionChecker resourcePermissionChecker, + IResourcePermissionStore resourcePermissionStore, + IPermissionChecker permissionChecker) + { + PermissionDefinitionManager = permissionDefinitionManager; + ResourcePermissionChecker = resourcePermissionChecker; + ResourcePermissionStore = resourcePermissionStore; + PermissionChecker = permissionChecker; + } + + public virtual async Task PopulateAsync(TResource resource, string resourceName) + where TResource : IHasResourcePermissions + { + await PopulateAsync([resource], resourceName); + } + + public virtual async Task PopulateAsync(List resources, string resourceName) + where TResource : IHasResourcePermissions + { + Check.NotNull(resources, nameof(resources)); + Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + + var resopurcePermissions = (await PermissionDefinitionManager.GetResourcePermissionsAsync()) + .Where(x => x.ResourceName == resourceName) + .ToArray(); + + foreach (var resource in resources) + { + var resourceKey = resource.GetObjectKey(); + if (resourceKey.IsNullOrEmpty()) + { + throw new AbpException("Resource key can not be null or empty."); + } + + var results = await ResourcePermissionChecker.IsGrantedAsync(resopurcePermissions.Select(x => x.Name).ToArray(), resourceName, resourceKey); + foreach (var resopurcePermission in resopurcePermissions) + { + if (resource.ResourcePermissions == null) + { + ObjectHelper.TrySetProperty(resource, x => x.ResourcePermissions, () => new Dictionary()); + } + + var hasPermission = results.Result.TryGetValue(resopurcePermission.Name, out var granted) && granted == PermissionGrantResult.Granted; + resource.ResourcePermissions![resopurcePermission.Name] = hasPermission; + } + } + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs new file mode 100644 index 0000000000..bab3180fea --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionValueProviderManager : IResourcePermissionValueProviderManager, ISingletonDependency +{ + public IReadOnlyList ValueProviders => _lazyProviders.Value; + private readonly Lazy> _lazyProviders; + + protected AbpPermissionOptions Options { get; } + protected IServiceProvider ServiceProvider { get; } + + public ResourcePermissionValueProviderManager( + IServiceProvider serviceProvider, + IOptions options) + { + Options = options.Value; + ServiceProvider = serviceProvider; + + _lazyProviders = new Lazy>(GetProviders, true); + } + + protected virtual List GetProviders() + { + var providers = Options + .ResourceValueProviders + .Select(type => (ServiceProvider.GetRequiredService(type) as IResourcePermissionValueProvider)!) + .ToList(); + + var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); + if(multipleProviders != null) + { + throw new AbpException($"Duplicate resource permission value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); + } + + return providers; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..fc8e91e794 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class RoleResourcePermissionValueProvider : ResourcePermissionValueProvider +{ + public const string ProviderName = "R"; + + public override string Name => ProviderName; + + public RoleResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) + : base(resourcePermissionStore) + { + + } + + public override async Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); + + if (roles == null || !roles.Any()) + { + return PermissionGrantResult.Undefined; + } + + foreach (var role in roles.Distinct()) + { + if (await ResourcePermissionStore.IsGrantedAsync(context.Permission.Name, context.ResourceName, context.ResourceKey, Name, role)) + { + return PermissionGrantResult.Granted; + } + } + + return PermissionGrantResult.Undefined; + } + + public override async Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToList(); + Check.NotNullOrEmpty(permissionNames, nameof(permissionNames)); + + var result = new MultiplePermissionGrantResult(permissionNames.ToArray()); + + var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); + if (roles == null || !roles.Any()) + { + return result; + } + + foreach (var role in roles.Distinct()) + { + var multipleResult = await ResourcePermissionStore.IsGrantedAsync(permissionNames.ToArray(), context.ResourceName, context.ResourceKey, Name, role); + + foreach (var grantResult in multipleResult.Result.Where(grantResult => + result.Result.ContainsKey(grantResult.Key) && + result.Result[grantResult.Key] == PermissionGrantResult.Undefined && + grantResult.Value != PermissionGrantResult.Undefined)) + { + result.Result[grantResult.Key] = grantResult.Value; + permissionNames.RemoveAll(x => x == grantResult.Key); + } + + if (result.AllGranted || result.AllProhibited) + { + break; + } + + if (permissionNames.IsNullOrEmpty()) + { + break; + } + } + + return result; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..8cfcb8ca6f --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs @@ -0,0 +1,46 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class UserResourcePermissionValueProvider : ResourcePermissionValueProvider +{ + public const string ProviderName = "U"; + + public override string Name => ProviderName; + + public UserResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) + : base(resourcePermissionStore) + { + + } + + public override async Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; + + if (userId == null) + { + return PermissionGrantResult.Undefined; + } + + return await ResourcePermissionStore.IsGrantedAsync(context.Permission.Name, context.ResourceName, context.ResourceKey, Name, userId) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined; + } + + public override async Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToArray(); + Check.NotNullOrEmpty(permissionNames, nameof(permissionNames)); + + var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; + if (userId == null) + { + return new MultiplePermissionGrantResult(permissionNames); + } + + return await ResourcePermissionStore.IsGrantedAsync(permissionNames, context.ResourceName, context.ResourceKey, Name, userId); + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs index 4e6ff0d11c..5ac2257060 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs @@ -11,12 +11,14 @@ namespace Volo.Abp.Authorization.Permissions; public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ISingletonDependency { - protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value; - private readonly Lazy> _lazyPermissionGroupDefinitions; + protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value.Item1; + private readonly Lazy<(Dictionary, List)> _lazyPermissionGroupDefinitions; protected IDictionary PermissionDefinitions => _lazyPermissionDefinitions.Value; private readonly Lazy> _lazyPermissionDefinitions; + protected IList ResourcePermissionDefinitions => _lazyPermissionGroupDefinitions.Value.Item2; + protected AbpPermissionOptions Options { get; } private readonly IServiceProvider _serviceProvider; @@ -33,12 +35,12 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, isThreadSafe: true ); - _lazyPermissionGroupDefinitions = new Lazy>( + _lazyPermissionGroupDefinitions = new Lazy<(Dictionary, List)>( CreatePermissionGroupDefinitions, isThreadSafe: true ); } - + protected virtual Dictionary CreatePermissionDefinitions() { var permissions = new Dictionary(); @@ -71,7 +73,7 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, } } - protected virtual Dictionary CreatePermissionGroupDefinitions() + protected virtual (Dictionary, List) CreatePermissionGroupDefinitions() { using (var scope = _serviceProvider.CreateScope()) { @@ -99,10 +101,10 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, context.CurrentProvider = provider; provider.PostDefine(context); } - + context.CurrentProvider = null; - return context.Groups; + return (context.Groups, context.ResourcePermissions); } } @@ -110,7 +112,7 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, { return Task.FromResult(PermissionDefinitions.GetOrDefault(name)); } - + public virtual Task> GetPermissionsAsync() { return Task.FromResult>( @@ -118,10 +120,22 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ); } + public virtual Task GetResourcePermissionOrNullAsync(string resourceName, string name) + { + return Task.FromResult(ResourcePermissionDefinitions.FirstOrDefault(p => p.ResourceName == resourceName && p.Name == name)); + } + + public virtual Task> GetResourcePermissionsAsync() + { + return Task.FromResult>( + ResourcePermissionDefinitions.ToImmutableList() + ); + } + public Task> GetGroupsAsync() { return Task.FromResult>( PermissionGroupDefinitions.Values.ToImmutableList() ); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index 7b249f0517..8ff8ad3206 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -1,5 +1,8 @@ +using System; +using System.Linq; using System.Text; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Commands.Internal; using Volo.Abp.Cli.Http; @@ -7,9 +10,12 @@ using Volo.Abp.Cli.ServiceProxying; using Volo.Abp.Cli.ServiceProxying.Angular; using Volo.Abp.Cli.ServiceProxying.CSharp; using Volo.Abp.Cli.ServiceProxying.JavaScript; +using Volo.Abp.Cli.Telemetry; using Volo.Abp.Domain; using Volo.Abp.Http; using Volo.Abp.IdentityModel; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Activity.Providers; using Volo.Abp.Json; using Volo.Abp.Localization; using Volo.Abp.Minify; @@ -27,6 +33,8 @@ namespace Volo.Abp.Cli; )] public class AbpCliCoreModule : AbpModule { + private const string EnableTelemetryVariableName = "ABP_STUDIO_ENABLE_TELEMETRY"; + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddHttpClient(CliConsts.HttpClientName) @@ -82,5 +90,23 @@ public class AbpCliCoreModule : AbpModule options.Generators[AngularServiceProxyGenerator.Name] = typeof(AngularServiceProxyGenerator); options.Generators[CSharpServiceProxyGenerator.Name] = typeof(CSharpServiceProxyGenerator); }); + + ConfigureTelemetry(context.Services); + } + + private static void ConfigureTelemetry(IServiceCollection services) + { + var enableTelemetryEnvironmentVariable = Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.Machine) + ?? Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.User) + ?? Environment.GetEnvironmentVariable(EnableTelemetryVariableName , EnvironmentVariableTarget.Process); + + if (enableTelemetryEnvironmentVariable.IsNullOrEmpty() || !enableTelemetryEnvironmentVariable.Equals("false", StringComparison.InvariantCultureIgnoreCase)) + { + services.Remove(services.First(p => p.ImplementationType == typeof(TelemetrySessionInfoEnricher))); + } + else + { + services.Replace(ServiceDescriptor.Singleton()); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index 0a0c46b6a4..063ceddebf 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -14,12 +14,15 @@ using Volo.Abp.Cli.Memory; using Volo.Abp.Cli.Version; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli; public class CliService : ITransientDependency { private readonly MemoryService _memoryService; + private readonly ITelemetryService _telemetryService; public ILogger Logger { get; set; } protected ICommandLineArgumentParser CommandLineArgumentParser { get; } protected ICommandSelector CommandSelector { get; } @@ -35,7 +38,8 @@ public class CliService : ITransientDependency PackageVersionCheckerService nugetService, ICmdHelper cmdHelper, MemoryService memoryService, - CliVersionService cliVersionService) + CliVersionService cliVersionService, + ITelemetryService telemetryService) { _memoryService = memoryService; CommandLineArgumentParser = commandLineArgumentParser; @@ -44,6 +48,7 @@ public class CliService : ITransientDependency PackageVersionCheckerService = nugetService; CmdHelper = cmdHelper; CliVersionService = cliVersionService; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -64,6 +69,7 @@ public class CliService : ITransientDependency try { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliRun); if (commandLineArgs.IsCommand("prompt")) { await RunPromptAsync(); @@ -84,9 +90,14 @@ public class CliService : ITransientDependency } catch (Exception ex) { + await _telemetryService.AddErrorActivityAsync(ex.Message); Logger.LogException(ex); throw; } + finally + { + await _telemetryService.AddActivityAsync(ActivityNameConsts.AbpCliExit); + } } private async Task RunPromptAsync() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index 4756c3f99b..38483517da 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -11,6 +11,8 @@ using Volo.Abp.Cli.ProjectBuilding.Templates.MvcModule; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -20,6 +22,8 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency public const string Name = "add-module"; private AddModuleInfoOutput _lastAddedModuleInfo; + private readonly ITelemetryService _telemetryService; + public ILogger Logger { get; set; } protected SolutionModuleAdder SolutionModuleAdder { get; } @@ -39,11 +43,13 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency public AddModuleCommand( SolutionModuleAdder solutionModuleAdder, SolutionPackageVersionFinder solutionPackageVersionFinder, - IOptions options) + IOptions options, + ITelemetryService telemetryService) { _options = options.Value; SolutionModuleAdder = solutionModuleAdder; SolutionPackageVersionFinder = solutionPackageVersionFinder; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -66,6 +72,11 @@ public class AddModuleCommand : IConsoleCommand, ITransientDependency } var newTemplate = commandLineArgs.Options.ContainsKey(Options.NewTemplate.Long); + + await using var _ = _telemetryService.TrackActivityAsync(newTemplate + ? ActivityNameConsts.AbpCliCommandsInstallLocalModule + : ActivityNameConsts.AbpCliCommandsInstallModule); + var template = commandLineArgs.Options.GetOrNull(Options.Template.Short, Options.Template.Long); var newProTemplate = !string.IsNullOrEmpty(template) && template == ModuleProTemplate.TemplateName; var withSourceCode = newTemplate || newProTemplate || commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs index e9acb7ae24..f397ef8d6e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs @@ -9,6 +9,8 @@ using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -16,16 +18,19 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency { public const string Name = "add-package"; + private readonly ITelemetryService _telemetryService; + public ILogger Logger { get; set; } protected ProjectNugetPackageAdder ProjectNugetPackageAdder { get; } public ProjectNpmPackageAdder ProjectNpmPackageAdder { get; } - public AddPackageCommand(ProjectNugetPackageAdder projectNugetPackageAdder, ProjectNpmPackageAdder projectNpmPackageAdder) + public AddPackageCommand(ProjectNugetPackageAdder projectNugetPackageAdder, ProjectNpmPackageAdder projectNpmPackageAdder, ITelemetryService telemetryService) { ProjectNugetPackageAdder = projectNugetPackageAdder; ProjectNpmPackageAdder = projectNpmPackageAdder; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } @@ -39,6 +44,9 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency GetUsageInfo() ); } + + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsNewPackage); + await using var __ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsAddPackage); var isNpmPackage = false; var isNugetPackage = true; @@ -51,11 +59,11 @@ public class AddPackageCommand : IConsoleCommand, ITransientDependency var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); var withSourceCode = commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); - + if (isNugetPackage) { var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file"); - + await ProjectNugetPackageAdder.AddAsync( GetSolutionFile(commandLineArgs), GetProjectFile(commandLineArgs), diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs index 092e996095..661cf7995b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CleanCommand.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -16,17 +18,21 @@ public class CleanCommand : IConsoleCommand, ITransientDependency public const string Name = "clean"; public ILogger Logger { get; set; } - + protected ICmdHelper CmdHelper { get; } + + private readonly ITelemetryService _telemetryService; - public CleanCommand(ICmdHelper cmdHelper) + public CleanCommand(ICmdHelper cmdHelper, ITelemetryService telemetryService) { CmdHelper = cmdHelper; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } - public Task ExecuteAsync(CommandLineArgs commandLineArgs) + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsClean); var binEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "bin", SearchOption.AllDirectories); var objEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "obj", SearchOption.AllDirectories); @@ -49,7 +55,6 @@ public class CleanCommand : IConsoleCommand, ITransientDependency Logger.LogInformation($"'bin' and 'obj' folders removed successfully!"); Logger.LogInformation("Solution cleaned successfully!"); - return Task.CompletedTask; } public string GetUsageInfo() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs index af685102d8..8a9d4fd6d1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ListModulesCommand.cs @@ -7,6 +7,8 @@ using System.Threading.Tasks; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -17,15 +19,19 @@ public class ListModulesCommand : IConsoleCommand, ITransientDependency public ModuleInfoProvider ModuleInfoProvider { get; } public ILogger Logger { get; set; } + private readonly ITelemetryService _telemetryService; - public ListModulesCommand(ModuleInfoProvider moduleInfoProvider) + public ListModulesCommand(ModuleInfoProvider moduleInfoProvider, ITelemetryService telemetryService) { ModuleInfoProvider = moduleInfoProvider; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsListModules); + var modules = await ModuleInfoProvider.GetModuleListAsync(); var freeModules = modules.Where(m => !m.IsPro).ToList(); var proModules = modules.Where(m => m.IsPro).ToList(); 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 796a8ff757..149b477d5b 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 @@ -11,11 +11,15 @@ using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.LIbs; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.ProjectBuilding.Events; +using Volo.Abp.Cli.ProjectBuilding.Templates.Module; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.Cli.Version; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Local; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; +using Volo.Abp.Internal.Telemetry.Constants.Enums; namespace Volo.Abp.Cli.Commands; @@ -26,6 +30,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien protected TemplateProjectBuilder TemplateProjectBuilder { get; } public ITemplateInfoProvider TemplateInfoProvider { get; } + private readonly ITelemetryService _telemetryService; + public NewCommand( ConnectionStringProvider connectionStringProvider, SolutionPackageVersionFinder solutionPackageVersionFinder, @@ -40,7 +46,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien ITemplateInfoProvider templateInfoProvider, TemplateProjectBuilder templateProjectBuilder, AngularThemeConfigurer angularThemeConfigurer, - CliVersionService cliVersionService) : + CliVersionService cliVersionService, + ITelemetryService telemetryService) : base(connectionStringProvider, solutionPackageVersionFinder, cmdHelper, @@ -56,6 +63,7 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien { TemplateInfoProvider = templateInfoProvider; TemplateProjectBuilder = templateProjectBuilder; + _telemetryService = telemetryService; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) @@ -94,6 +102,19 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien var result = await TemplateProjectBuilder.BuildAsync( projectArgs ); + + var activityName = ActivityNameConsts.AbpCliCommandsNewSolution; + + if (ModuleTemplateBase.IsModuleTemplate(template)) + { + activityName = ActivityNameConsts.AbpCliCommandsNewModule; + } + + await _telemetryService.AddActivityAsync(activityName, o => + { + o[ActivityPropertyNames.CreationTool] = AbpTool.OldCli; + o[ActivityPropertyNames.Template] = template; + }); ExtractProjectZip(result, projectArgs.OutputFolder); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs index ae3cda8723..68ab346064 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -9,6 +9,8 @@ using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.ProjectModification; using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Constants; namespace Volo.Abp.Cli.Commands; @@ -20,18 +22,21 @@ public class UpdateCommand : IConsoleCommand, ITransientDependency private readonly VoloNugetPackagesVersionUpdater _nugetPackagesVersionUpdater; private readonly NpmPackagesUpdater _npmPackagesUpdater; + private readonly ITelemetryService _telemetryService; public UpdateCommand(VoloNugetPackagesVersionUpdater nugetPackagesVersionUpdater, - NpmPackagesUpdater npmPackagesUpdater) + NpmPackagesUpdater npmPackagesUpdater, ITelemetryService telemetryService) { _nugetPackagesVersionUpdater = nugetPackagesVersionUpdater; _npmPackagesUpdater = npmPackagesUpdater; + _telemetryService = telemetryService; Logger = NullLogger.Instance; } public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { + await using var _ = _telemetryService.TrackActivityAsync(ActivityNameConsts.AbpCliCommandsUpdate); var updateNpm = commandLineArgs.Options.ContainsKey(Options.Packages.Npm); var updateNuget = commandLineArgs.Options.ContainsKey(Options.Packages.NuGet); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs new file mode 100644 index 0000000000..4f3c695f7d --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Telemetry/NullTelemetryService.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Internal.Telemetry; +using Volo.Abp.Internal.Telemetry.Activity; + +namespace Volo.Abp.Cli.Telemetry; + +public class NullTelemetryService : ITelemetryService +{ + public IAsyncDisposable TrackActivity(ActivityEvent activityData) + { + return NullAsyncDisposable.Instance; + } + public IAsyncDisposable TrackActivityAsync(string activityName, Action>? additionalProperties = null) + { + return NullAsyncDisposable.Instance; + } + + public Task AddActivityAsync(string activityName, Action>? additionalProperties = null) + { + return Task.CompletedTask; + } + + public Task AddErrorActivityAsync(Action> additionalProperties) + { + return Task.CompletedTask; + } + + public Task AddErrorActivityAsync(string errorMessage) + { + return Task.CompletedTask; + } + + public Task AddErrorForActivityAsync(string failingActivity, string errorMessage) + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs new file mode 100644 index 0000000000..17c340febd --- /dev/null +++ b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Telemetry/TelemetryCliSessionProvider.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Internal.Telemetry.Activity; +using Volo.Abp.Internal.Telemetry.Activity.Contracts; +using Volo.Abp.Internal.Telemetry.Activity.Providers; +using Volo.Abp.Internal.Telemetry.Constants; +using Volo.Abp.Internal.Telemetry.Constants.Enums; + +namespace Volo.Abp.Cli.Telemetry; + +[ExposeServices(typeof(ITelemetryActivityEventEnricher))] +public class TelemetryCliSessionProvider : TelemetryActivityEventEnricher +{ + public TelemetryCliSessionProvider(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override int ExecutionOrder { get; set; } = 10; + + protected override Task ExecuteAsync(ActivityContext context) + { + context.Current[ActivityPropertyNames.SessionType] = SessionType.AbpCli; + context.Current[ActivityPropertyNames.SessionId] = Guid.NewGuid(); + context.Current[ActivityPropertyNames.IsFirstSession] = !File.Exists(TelemetryPaths.ActivityStorage); + context.Current["OldCli"] = true; + + if(context.Current.TryGetValue>(ActivityPropertyNames.AdditionalProperties, out var additionalProperties)) + { + additionalProperties["OldCli"] = true; + } + else + { + context.Current[ActivityPropertyNames.AdditionalProperties] = new Dictionary + { + { "OldCli", true } + }; + } + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IKeyedObject.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IKeyedObject.cs new file mode 100644 index 0000000000..d0cbb47790 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IKeyedObject.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp; + +public interface IKeyedObject +{ + string? GetObjectKey(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/KeyedObjectHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/KeyedObjectHelper.cs new file mode 100644 index 0000000000..9757e67ecc --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/KeyedObjectHelper.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Volo.Abp; + +public static class KeyedObjectHelper +{ + public static string EncodeCompositeKey(params object?[] keys) + { + var raw = keys.JoinAsString("||"); + var bytes = Encoding.UTF8.GetBytes(raw); + var base64 = Convert.ToBase64String(bytes); + var base64Url = base64 + .Replace("+", "-") + .Replace("/", "_") + .TrimEnd('='); + + return base64Url; + } + + public static string DecodeCompositeKey(string encoded) + { + var base64 = encoded + .Replace("-", "+") + .Replace("_", "/"); + + switch (encoded.Length % 4) + { + case 2: base64 += "=="; break; + case 3: base64 += "="; break; + } + + var bytes = Convert.FromBase64String(base64); + var raw = Encoding.UTF8.GetString(bytes); + + return raw; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/EntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/EntityDto.cs index 656e63b0d5..16c81c2f92 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/EntityDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/EntityDto.cs @@ -23,4 +23,9 @@ public abstract class EntityDto : EntityDto, IEntityDto { return $"[DTO: {GetType().Name}] Id = {Id}"; } + + public virtual string? GetObjectKey() + { + return Id?.ToString(); + } } diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs index 9687af0cf7..16379f865c 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs @@ -27,6 +27,11 @@ public abstract class ExtensibleEntityDto : ExtensibleObject, IEntityDto : IEntityDto +public interface IEntityDto : IEntityDto, IKeyedObject { TKey Id { get; set; } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Entity.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Entity.cs index 9e52d1abfd..93c5555a39 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Entity.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Entity.cs @@ -18,6 +18,17 @@ public abstract class Entity : IEntity return $"[ENTITY: {GetType().Name}] Keys = {GetKeys().JoinAsString(", ")}"; } + public virtual string? GetObjectKey() + { + var keys = GetKeys(); + return keys.Length switch + { + 0 => null, + 1 when keys[0] != null => keys[0]?.ToString(), + _ => KeyedObjectHelper.EncodeCompositeKey(keys) + }; + } + public abstract object?[] GetKeys(); public bool EntityEquals(IEntity other) @@ -45,7 +56,7 @@ public abstract class Entity : Entity, IEntity public override object?[] GetKeys() { - return new object?[] { Id }; + return [Id]; } /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs index 1df1b75696..db4a144539 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IEntity.cs @@ -4,7 +4,7 @@ /// Defines an entity. It's primary key may not be "Id" or it may have a composite primary key. /// Use where possible for better integration to repositories and other structures in the framework. /// -public interface IEntity +public interface IEntity : IKeyedObject { /// /// Returns an array of ordered keys for this entity. diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 9243d4680e..f99d9130bd 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -204,6 +204,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, case "Npgsql.EntityFrameworkCore.PostgreSQL": return EfCoreDatabaseProvider.PostgreSql; case "Pomelo.EntityFrameworkCore.MySql": + case "MySql.Data.MySqlClient": return EfCoreDatabaseProvider.MySql; case "Oracle.EntityFrameworkCore": case "Devart.Data.Oracle.Entity.EFCore": diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 93cf62ab84..eb32a44fa2 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -61,6 +61,7 @@ "ProfilePicture": "الصوره الشخصيه", "Theme": "سمة", "NotAssigned": "غيرمعتمد", - "EntityActionsDisabledTooltip": "ليس لديك إذن لتنفيذ أي إجراء." + "EntityActionsDisabledTooltip": "ليس لديك إذن لتنفيذ أي إجراء.", + "ResourcePermissions": "أذونات" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json index ff2d09fdf8..27a174cb49 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/cs.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profilový obrázek", "Theme": "Téma", "NotAssigned": "Nepřiřazena", - "EntityActionsDisabledTooltip": "Nemáte oprávnění provést žádnou akci." + "EntityActionsDisabledTooltip": "Nemáte oprávnění provést žádnou akci.", + "ResourcePermissions": "Oprávnění" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json index 37c361c1e3..869d049be1 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/de.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profilbild", "Theme": "Thema", "NotAssigned": "Nicht zugeordnet", - "EntityActionsDisabledTooltip": "Sie haben keine Berechtigung, Aktionen auszuführen." + "EntityActionsDisabledTooltip": "Sie haben keine Berechtigung, Aktionen auszuführen.", + "ResourcePermissions": "Berechtigungen" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json index f7d837a361..8c2dc2be1d 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/el.json @@ -55,6 +55,7 @@ "OthersGroup": "άλλος", "Today": "Σήμερα", "Apply": "Ισχύουν", - "EntityActionsDisabledTooltip": "Δεν έχετε δικαίωμα να εκτελέσετε καμία ενέργεια." + "EntityActionsDisabledTooltip": "Δεν έχετε δικαίωμα να εκτελέσετε καμία ενέργεια.", + "ResourcePermissions": "Δικαιώματα", } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json index c5aaa5957c..ce9d962d5e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en-GB.json @@ -56,6 +56,7 @@ "NotAssigned": "Not Assigned", "Today": "Today", "Apply": "Apply", - "EntityActionsDisabledTooltip": "You do not have permission to perform any action." + "EntityActionsDisabledTooltip": "You do not have permission to perform any action.", + "ResourcePermissions": "Permissions" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 7a5a806124..f328765a39 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profile picture", "Theme": "Theme", "NotAssigned": "Not Assigned", - "EntityActionsDisabledTooltip": "You do not have permission to perform any action." + "EntityActionsDisabledTooltip": "You do not have permission to perform any action.", + "ResourcePermissions": "Permissions" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json index 132243a740..9d341cb88f 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/es.json @@ -61,6 +61,7 @@ "ProfilePicture": "Foto de perfil", "Theme": "Tema", "NotAssigned": "No asignado", - "EntityActionsDisabledTooltip": "No tienes permisos para realizar ninguna acción." + "EntityActionsDisabledTooltip": "No tienes permisos para realizar ninguna acción.", + "ResourcePermissions": "Permisos" } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json index f1738957c9..5862eab90e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fa.json @@ -55,6 +55,7 @@ "OthersGroup": "دیگر", "Today": "امروز", "Apply": "درخواست دادن", - "EntityActionsDisabledTooltip": "شما دسترسی به انجام هر گونه عملیات ندارید." + "EntityActionsDisabledTooltip": "شما دسترسی به انجام هر گونه عملیات ندارید.", + "ResourcePermissions": "مجوزها" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json index 1af59eb720..51e356559b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fi.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profiilikuva", "Theme": "Teema", "NotAssigned": "Ei määritetty", - "EntityActionsDisabledTooltip": "Sinulla ei ole oikeutta suorittaa mitään toimintoa." + "EntityActionsDisabledTooltip": "Sinulla ei ole oikeutta suorittaa mitään toimintoa.", + "ResourcePermissions": "Käyttöoikeudet" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json index 8af5661d1a..79a40c57f9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/fr.json @@ -61,6 +61,7 @@ "ProfilePicture": "Image de profil", "Theme": "Thème", "NotAssigned": "Non attribué", - "EntityActionsDisabledTooltip": "Vous n'avez pas les permissions pour effectuer une action." + "EntityActionsDisabledTooltip": "Vous n'avez pas les permissions pour effectuer une action.", + "ResourcePermissions": "Autorisations" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json index ba873b7685..10c1e426c1 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hi.json @@ -61,6 +61,7 @@ "ProfilePicture": "प्रोफ़ाइल फोटो", "Theme": "विषय", "NotAssigned": "सौंपा नहीं गया है", - "EntityActionsDisabledTooltip": "आपके पास कोई कार्रवाई नहीं है जो करने के लिए है।" + "EntityActionsDisabledTooltip": "आपके पास कोई कार्रवाई नहीं है जो करने के लिए है।", + "ResourcePermissions": "अनुमतियाँ" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json index 5b16c84963..c36751828c 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hr.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profilna slika", "Theme": "Tema", "NotAssigned": "Nije dodijeljeno", - "EntityActionsDisabledTooltip": "Nemate dozvolu za izvođenje bilo kakve akcije." + "EntityActionsDisabledTooltip": "Nemate dozvolu za izvođenje bilo kakve akcije.", + "ResourcePermissions": "Dozvole" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json index 0539276498..e162a2c6c8 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/hu.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profil kép", "Theme": "Téma", "NotAssigned": "Nem kijelölt", - "EntityActionsDisabledTooltip": "Nincs jogosultsága bármely művelethez." + "EntityActionsDisabledTooltip": "Nincs jogosultsága bármely művelethez.", + "ResourcePermissions": "Engedélyek" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json index 8a1eda9e4e..3d88d70d97 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/is.json @@ -61,6 +61,7 @@ "ProfilePicture": "Forsíðumynd", "Theme": "Þema", "NotAssigned": "Ekki skráður", - "EntityActionsDisabledTooltip": "Þú hefur ekki aðgang að þessum aðgerðum." + "EntityActionsDisabledTooltip": "Þú hefur ekki aðgang að þessum aðgerðum.", + "ResourcePermissions": "Aðgangsheimildir" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json index 77d4742680..9bfffe181e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/it.json @@ -61,6 +61,7 @@ "ProfilePicture": "Immagine del profilo", "Theme": "Tema", "NotAssigned": "Non assegnato", - "EntityActionsDisabledTooltip": "Non hai i permessi per eseguire alcuna azione." + "EntityActionsDisabledTooltip": "Non hai i permessi per eseguire alcuna azione.", + "ResourcePermissions": "Autorizzazioni" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json index 38182ec9e6..51ab0bcd31 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/nl.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profielfoto", "Theme": "Thema", "NotAssigned": "Niet toegekend", - "EntityActionsDisabledTooltip": "U hebt geen toegang tot deze acties." + "EntityActionsDisabledTooltip": "U hebt geen toegang tot deze acties.", + "ResourcePermissions": "Machtigingen" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json index d7f321f3d6..20b4daf7f0 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pl-PL.json @@ -61,6 +61,7 @@ "ProfilePicture": "Zdjęcie profilowe", "Theme": "Temat", "NotAssigned": "Nie przypisano", - "EntityActionsDisabledTooltip": "Nie masz uprawnień do wykonania żadnej akcji." + "EntityActionsDisabledTooltip": "Nie masz uprawnień do wykonania żadnej akcji.", + "ResourcePermissions": "Uprawnienia" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index 13c8380fa3..9764d99fe6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -61,6 +61,7 @@ "ProfilePicture": "Foto do perfil", "Theme": "Tema", "NotAssigned": "Não atribuído", - "EntityActionsDisabledTooltip": "Você não tem permissão para executar qualquer ação." + "EntityActionsDisabledTooltip": "Você não tem permissão para executar qualquer ação.", + "ResourcePermissions": "Permissões" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json index e03fd91f50..6b7367994c 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json @@ -61,6 +61,7 @@ "ProfilePicture": "Poză de profil", "Theme": "Temă", "NotAssigned": "Nealocat", - "EntityActionsDisabledTooltip": "Nu aveți permisiune să efectuați nicio acțiune." + "EntityActionsDisabledTooltip": "Nu aveți permisiune să efectuați nicio acțiune.", + "ResourcePermissions": "Permisiuni" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json index 57f3079cb4..d4f4acf5d6 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ru.json @@ -61,6 +61,7 @@ "ProfilePicture": "Изображение профиля", "Theme": "Тема", "NotAssigned": "Не назначен", - "EntityActionsDisabledTooltip": "У вас нет прав на выполнение каких-либо действий." + "EntityActionsDisabledTooltip": "У вас нет прав на выполнение каких-либо действий.", + "ResourcePermissions": "Разрешения" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json index eb0ba2958f..59d8aecef4 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sk.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profilový obrázok", "Theme": "Téma", "NotAssigned": "Nepridelené", - "EntityActionsDisabledTooltip": "Nemáte oprávnenie vykonávať žiadnu akciu." + "EntityActionsDisabledTooltip": "Nemáte oprávnenie vykonávať žiadnu akciu.", + "ResourcePermissions": "Oprávnenia" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json index bc3f795b34..89f2691a11 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sl.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profilna slika", "Theme": "Tema", "NotAssigned": "Ni dodeljena", - "EntityActionsDisabledTooltip": "Nimate pravic za izvajanje kakršne koli dejanje." + "EntityActionsDisabledTooltip": "Nimate pravic za izvajanje kakršne koli dejanje.", + "ResourcePermissions": "Dovoljenja" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sv.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sv.json index f0257637c1..fe4b692cdf 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sv.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/sv.json @@ -60,6 +60,7 @@ "ProfilePicture": "Profilbild", "Theme": "Tema", "NotAssigned": "Ej tilldelad", - "EntityActionsDisabledTooltip": "Du har inte tillgång till dessa åtgärder." + "EntityActionsDisabledTooltip": "Du har inte tillgång till dessa åtgärder.", + "ResourcePermissions": "Behörigheter" } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index b21adf632a..73a4bb5cb4 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -61,6 +61,7 @@ "ProfilePicture": "Profil resmi", "Theme": "Tema", "NotAssigned": "Atanmadı", - "EntityActionsDisabledTooltip": "Bu işlemi gerçekleştirmek için yeterli yetkiniz yok." + "EntityActionsDisabledTooltip": "Bu işlemi gerçekleştirmek için yeterli yetkiniz yok.", + "ResourcePermissions": "İzinler" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json index 700798895f..015ed883d3 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/vi.json @@ -61,6 +61,7 @@ "ProfilePicture": "Ảnh đại diện", "Theme": "chủ đề", "NotAssigned": "Không được chỉ định", - "EntityActionsDisabledTooltip": "Bạn không có quyền thực hiện bất kỳ hành động nào." + "EntityActionsDisabledTooltip": "Bạn không có quyền thực hiện bất kỳ hành động nào.", + "ResourcePermissions": "Quyền" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json index 60f70e1545..b0759d7da9 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hans.json @@ -61,6 +61,7 @@ "ProfilePicture": "个人资料图片", "Theme": "主题", "NotAssigned": "未分配", - "EntityActionsDisabledTooltip": "您没有权限执行任何操作。" + "EntityActionsDisabledTooltip": "您没有权限执行任何操作。", + "ResourcePermissions": "权限" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json index 0f8fdeb254..e35bae3610 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/zh-Hant.json @@ -61,6 +61,7 @@ "ProfilePicture": "個人資料圖片", "Theme": "主題", "NotAssigned": "未分配", - "EntityActionsDisabledTooltip": "您沒有權限執行任何操作。" + "EntityActionsDisabledTooltip": "您沒有權限執行任何操作。", + "ResourcePermissions": "權限" } } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs index fca3d209b0..15ec4e0641 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.TestServices; +using Volo.Abp.Authorization.TestServices.Resources; using Volo.Abp.Autofac; using Volo.Abp.DynamicProxy; using Volo.Abp.ExceptionHandling; @@ -33,6 +34,9 @@ public class AbpAuthorizationTestModule : AbpModule options.ValueProviders.Add(); options.ValueProviders.Add(); options.ValueProviders.Add(); + + options.ResourceValueProviders.Add(); + options.ResourceValueProviders.Add(); }); } } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs index 4144df2e1e..43736f0dce 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs @@ -2,12 +2,11 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; -using Volo.Abp.Authorization; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.TestServices; using Xunit; -namespace Volo.Abp; +namespace Volo.Abp.Authorization; public class PermissionValueProviderManager_Tests: AuthorizationTestBase { @@ -17,7 +16,7 @@ public class PermissionValueProviderManager_Tests: AuthorizationTestBase { _permissionValueProviderManager = GetRequiredService(); } - + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) { options.Services.Configure(permissionOptions => @@ -25,7 +24,7 @@ public class PermissionValueProviderManager_Tests: AuthorizationTestBase permissionOptions.ValueProviders.Add(); }); } - + [Fact] public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() { @@ -33,7 +32,7 @@ public class PermissionValueProviderManager_Tests: AuthorizationTestBase { var providers = _permissionValueProviderManager.ValueProviders; }); - + exception.Message.ShouldBe($"Duplicate permission value provider name detected: TestPermissionValueProvider1. Providers:{Environment.NewLine}{typeof(TestDuplicatePermissionValueProvider).FullName}{Environment.NewLine}{typeof(TestPermissionValueProvider1).FullName}"); } } @@ -55,4 +54,4 @@ public class TestDuplicatePermissionValueProvider : PermissionValueProvider { throw new NotImplementedException(); } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionChecker_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionChecker_Tests.cs new file mode 100644 index 0000000000..739968b603 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionChecker_Tests.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Authorization.TestServices.Resources; +using Xunit; + +namespace Volo.Abp.Authorization; + +public class ResourcePermissionChecker_Tests: AuthorizationTestBase +{ + private readonly IResourcePermissionChecker _resourcePermissionChecker; + + public ResourcePermissionChecker_Tests() + { + _resourcePermissionChecker = GetRequiredService(); + } + + [Fact] + public async Task IsGrantedAsync() + { + (await _resourcePermissionChecker.IsGrantedAsync("MyResourcePermission5", TestEntityResource.ResourceName, TestEntityResource.ResourceKey5)).ShouldBe(true); + (await _resourcePermissionChecker.IsGrantedAsync("UndefinedResourcePermission", TestEntityResource.ResourceName, TestEntityResource.ResourceKey5)).ShouldBe(false); + (await _resourcePermissionChecker.IsGrantedAsync("MyResourcePermission8", TestEntityResource.ResourceName, TestEntityResource.ResourceKey5)).ShouldBe(false); + } + + [Fact] + public async Task IsGranted_Multiple_Result_Async() + { + var result = await _resourcePermissionChecker.IsGrantedAsync(new [] + { + "MyResourcePermission1", + "MyResourcePermission2", + "UndefinedPermission", + "MyResourcePermission3", + "MyResourcePermission4", + "MyResourcePermission5", + "MyResourcePermission8" + }, TestEntityResource.ResourceName, TestEntityResource.ResourceKey5); + + result.Result["MyResourcePermission1"].ShouldBe(PermissionGrantResult.Undefined); + result.Result["MyResourcePermission2"].ShouldBe(PermissionGrantResult.Prohibited); + result.Result["UndefinedPermission"].ShouldBe(PermissionGrantResult.Prohibited); + result.Result["MyResourcePermission3"].ShouldBe(PermissionGrantResult.Granted); + result.Result["MyResourcePermission4"].ShouldBe(PermissionGrantResult.Prohibited); + result.Result["MyResourcePermission5"].ShouldBe(PermissionGrantResult.Granted); + result.Result["MyResourcePermission8"].ShouldBe(PermissionGrantResult.Prohibited); + + result = await _resourcePermissionChecker.IsGrantedAsync(new [] + { + "MyResourcePermission6", + }, TestEntityResource.ResourceName, TestEntityResource.ResourceKey6); + + result.Result["MyResourcePermission6"].ShouldBe(PermissionGrantResult.Granted); + + result = await _resourcePermissionChecker.IsGrantedAsync(new [] + { + "MyResourcePermission7", + }, TestEntityResource.ResourceName, TestEntityResource.ResourceKey7); + result.Result["MyResourcePermission7"].ShouldBe(PermissionGrantResult.Granted); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionPopulator_Test.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionPopulator_Test.cs new file mode 100644 index 0000000000..2cc000c30a --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionPopulator_Test.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Authorization.TestServices.Resources; +using Xunit; + +namespace Volo.Abp.Authorization; + +public class ResourcePermissionPopulator_Tests : AuthorizationTestBase +{ + private readonly ResourcePermissionPopulator _resourcePermissionPopulator; + + public ResourcePermissionPopulator_Tests() + { + _resourcePermissionPopulator = GetRequiredService(); + } + + [Fact] + public async Task PopulateAsync() + { + var testResourceObject = new TestEntityResource(TestEntityResource.ResourceKey5); + testResourceObject.ResourcePermissions.IsNullOrEmpty().ShouldBeTrue(); + + await _resourcePermissionPopulator.PopulateAsync( + testResourceObject, + TestEntityResource.ResourceName + ); + + testResourceObject.ResourcePermissions.ShouldNotBeNull(); + testResourceObject.ResourcePermissions.Count.ShouldBe(8); + testResourceObject.ResourcePermissions["MyResourcePermission1"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission2"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission3"].ShouldBe(true); + testResourceObject.ResourcePermissions["MyResourcePermission4"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission5"].ShouldBe(true); + testResourceObject.ResourcePermissions["MyResourcePermission6"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission7"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission8"].ShouldBe(false); + + testResourceObject = new TestEntityResource(TestEntityResource.ResourceKey6); + testResourceObject.ResourcePermissions.IsNullOrEmpty().ShouldBeTrue(); + + await _resourcePermissionPopulator.PopulateAsync( + testResourceObject, + TestEntityResource.ResourceName + ); + + testResourceObject.ResourcePermissions.ShouldNotBeNull(); + testResourceObject.ResourcePermissions.Count.ShouldBe(8); + testResourceObject.ResourcePermissions["MyResourcePermission1"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission2"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission3"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission4"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission5"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission6"].ShouldBe(true); + testResourceObject.ResourcePermissions["MyResourcePermission7"].ShouldBe(false); + testResourceObject.ResourcePermissions["MyResourcePermission8"].ShouldBe(false); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionValueProviderManager_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionValueProviderManager_Tests.cs new file mode 100644 index 0000000000..ceebc1ebac --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/ResourcePermissionValueProviderManager_Tests.cs @@ -0,0 +1,58 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Authorization.TestServices.Resources; +using Xunit; + +namespace Volo.Abp.Authorization; + +public class ResourcePermissionValueProviderManager_Tests: AuthorizationTestBase +{ + private readonly IResourcePermissionValueProviderManager _resourcePermissionValueProviderManager; + + public ResourcePermissionValueProviderManager_Tests() + { + _resourcePermissionValueProviderManager = GetRequiredService(); + } + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.Services.Configure(permissionOptions => + { + permissionOptions.ResourceValueProviders.Add(); + }); + } + + [Fact] + public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() + { + var exception = Assert.Throws(() => + { + var providers = _resourcePermissionValueProviderManager.ValueProviders; + }); + + exception.Message.ShouldBe($"Duplicate resource permission value provider name detected: TestResourcePermissionValueProvider1. Providers:{Environment.NewLine}{typeof(TestDuplicateResourcePermissionValueProvider).FullName}{Environment.NewLine}{typeof(TestResourcePermissionValueProvider1).FullName}"); + } +} + +public class TestDuplicateResourcePermissionValueProvider : ResourcePermissionValueProvider +{ + public TestDuplicateResourcePermissionValueProvider(IResourcePermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestResourcePermissionValueProvider1"; + + public override Task CheckAsync(ResourcePermissionValueCheckContext context) + { + throw new NotImplementedException(); + } + + public override Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + throw new NotImplementedException(); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/StaticPermissionDefinitionStore_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/StaticPermissionDefinitionStore_Tests.cs index d3a484c32f..0afaa34f10 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/StaticPermissionDefinitionStore_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/StaticPermissionDefinitionStore_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Shouldly; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.TestServices.Resources; using Xunit; namespace Volo.Abp.Authorization; @@ -44,4 +45,29 @@ public class StaticPermissionDefinitionStore_Tests : AuthorizationTestBase var groups = await _store.GetGroupsAsync(); groups.ShouldNotContain(x => x.Name == "TestGetGroup"); } + + [Fact] + public async Task GetResourcePermissionOrNullAsync() + { + var permission = await _store.GetResourcePermissionOrNullAsync(TestEntityResource.ResourceName, "MyResourcePermission1"); + permission.ShouldNotBeNull(); + permission.Name.ShouldBe("MyResourcePermission1"); + permission.StateCheckers.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionSimpleStateChecker)); + + permission = await _store.GetResourcePermissionOrNullAsync(TestEntityResource.ResourceName, "NotExists"); + permission.ShouldBeNull(); + } + + [Fact] + public async Task GetResourcePermissionsAsync() + { + var permissions = await _store.GetResourcePermissionsAsync(); + permissions.ShouldContain(x => x.Name == "MyResourcePermission1"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission2"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission3"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission4"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission5"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission6"); + permissions.ShouldContain(x => x.Name == "MyResourcePermission7"); + } } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/FakePermissionStore.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/FakePermissionStore.cs index 4582417d3b..608cf94428 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/FakePermissionStore.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/FakePermissionStore.cs @@ -8,7 +8,7 @@ public class FakePermissionStore : IPermissionStore, ITransientDependency { public Task IsGrantedAsync(string name, string providerName, string providerKey) { - return Task.FromResult(name == "MyPermission3" || name == "MyPermission5"); + return Task.FromResult(name == "MyPermission3" || name == "MyPermission5" || name == "TestEntityManagementPermission"); } public Task IsGrantedAsync(string[] names, string providerName, string providerKey) @@ -16,7 +16,7 @@ public class FakePermissionStore : IPermissionStore, ITransientDependency var result = new MultiplePermissionGrantResult(); foreach (var name in names) { - result.Result.Add(name, name == "MyPermission3" || name == "MyPermission5" + result.Result.Add(name, name == "MyPermission3" || name == "MyPermission5" || name == "TestEntityManagementPermission" ? PermissionGrantResult.Granted : PermissionGrantResult.Prohibited); } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/AuthorizationTestResourcePermissionDefinitionProvider.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/AuthorizationTestResourcePermissionDefinitionProvider.cs new file mode 100644 index 0000000000..29a597c9b3 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/AuthorizationTestResourcePermissionDefinitionProvider.cs @@ -0,0 +1,48 @@ +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Xunit; + +namespace Volo.Abp.Authorization.TestServices.Resources; + +public class AuthorizationTestResourcePermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var getGroup = context.GetGroupOrNull("TestGroup"); + if (getGroup == null) + { + getGroup = context.AddGroup("TestGroup"); + } + getGroup.AddPermission("TestEntityManagementPermission"); + getGroup.AddPermission("TestEntityManagementPermission2"); + + var permission1 = context.AddResourcePermission("MyResourcePermission1", resourceName: TestEntityResource.ResourceName, "TestEntityManagementPermission"); + Assert.Throws(() => + { + permission1.AddChild("MyResourcePermission1.ChildPermission1"); + }).Message.ShouldBe($"Resource permission cannot have child permissions. Resource: {TestEntityResource.ResourceName}"); + permission1.StateCheckers.Add(new TestRequireEditionPermissionSimpleStateChecker());; + permission1[PermissionDefinitionContext.KnownPropertyNames.CurrentProviderName].ShouldBe(typeof(AuthorizationTestResourcePermissionDefinitionProvider).FullName); + + context.AddResourcePermission("MyResourcePermission2", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission3", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission4", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission5", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission6", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission").WithProviders(nameof(TestResourcePermissionValueProvider1)); + context.AddResourcePermission("MyResourcePermission7", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission").WithProviders(nameof(TestResourcePermissionValueProvider2)); + context.AddResourcePermission("MyResourcePermission8", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission2"); + + Assert.Throws(() => + { + context.AddResourcePermission("MyResourcePermission7", resourceName: typeof(TestEntityResource).FullName!, "TestEntityManagementPermission"); + }).Message.ShouldBe($"There is already an existing resource permission with name: MyResourcePermission7 for resource: {typeof(TestEntityResource).FullName}"); + + context.AddResourcePermission("MyResourcePermission7", resourceName: typeof(TestEntityResource2).FullName!, "TestEntityManagementPermission").WithProviders(nameof(TestResourcePermissionValueProvider2)); + + context.GetResourcePermissionOrNull(TestEntityResource.ResourceName, "MyResourcePermission1").ShouldNotBeNull(); + context.GetResourcePermissionOrNull(TestEntityResource.ResourceName, "MyResourcePermission7").ShouldNotBeNull(); + context.GetResourcePermissionOrNull(TestEntityResource2.ResourceName, "MyResourcePermission7").ShouldNotBeNull(); + context.GetResourcePermissionOrNull(TestEntityResource.ResourceName, "MyResourcePermission9").ShouldBeNull(); + context.GetResourcePermissionOrNull(TestEntityResource2.ResourceName, "MyResourcePermission6").ShouldBeNull(); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/FakeResourcePermissionStore.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/FakeResourcePermissionStore.cs new file mode 100644 index 0000000000..40cd542ac7 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/FakeResourcePermissionStore.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.TestServices.Resources; + +public class FakeResourcePermissionStore : IResourcePermissionStore, ITransientDependency +{ + public Task IsGrantedAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return Task.FromResult((name == "MyResourcePermission3" || name == "MyResourcePermission5") && + resourceName == TestEntityResource.ResourceName && + (resourceKey == TestEntityResource.ResourceKey3 || resourceKey == TestEntityResource.ResourceKey5)); + } + + public Task IsGrantedAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, ((name == "MyResourcePermission3" || name == "MyResourcePermission5") && + resourceName == TestEntityResource.ResourceName && + (resourceKey == TestEntityResource.ResourceKey3 || resourceKey == TestEntityResource.ResourceKey5) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited)); + } + + return Task.FromResult(result); + } + + public Task GetPermissionsAsync(string resourceName, string resourceKey) + { + throw new System.NotImplementedException(); + } + + public Task GetGrantedPermissionsAsync(string resourceName, string resourceKey) + { + throw new System.NotImplementedException(); + } + + public Task GetGrantedResourceKeysAsync(string resourceName, string name) + { + throw new System.NotImplementedException(); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestEntityResource.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestEntityResource.cs new file mode 100644 index 0000000000..f703007633 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestEntityResource.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Authorization.Permissions.Resources; + +namespace Volo.Abp.Authorization.TestServices.Resources; + +public class TestEntityResource : IHasResourcePermissions +{ + public static readonly string ResourceName = typeof(TestEntityResource).FullName; + + public static readonly string ResourceKey1 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey2 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey3 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey4 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey5 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey6 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey7 = Guid.NewGuid().ToString(); + + private string Id { get; } + + public TestEntityResource(string id) + { + Id = id; + } + + public string GetObjectKey() + { + return Id; + } + + public Dictionary ResourcePermissions { get; set; } +} + +public class TestEntityResource2 +{ + public static readonly string ResourceName = typeof(TestEntityResource2).FullName; +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider1.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider1.cs new file mode 100644 index 0000000000..3c7dc49a83 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider1.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; + +namespace Volo.Abp.Authorization.TestServices.Resources; + +public class TestResourcePermissionValueProvider1 : ResourcePermissionValueProvider +{ + public TestResourcePermissionValueProvider1(IResourcePermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestResourcePermissionValueProvider1"; + + public override Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var result = PermissionGrantResult.Undefined; + if (context.Permission.Name == "MyResourcePermission6" && + context.ResourceName == TestEntityResource.ResourceName && + context.ResourceKey == TestEntityResource.ResourceKey6) + { + result = PermissionGrantResult.Granted; + } + + return Task.FromResult(result); + } + + public override Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in context.Permissions.Select(x => x.Name)) + { + result.Result.Add(name, name == "MyResourcePermission6" && + context.ResourceName == TestEntityResource.ResourceName && + context.ResourceKey == TestEntityResource.ResourceKey6 + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + } + + return Task.FromResult(result); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider2.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider2.cs new file mode 100644 index 0000000000..c4ac61cb2c --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/Resources/TestResourcePermissionValueProvider2.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; + +namespace Volo.Abp.Authorization.TestServices.Resources; + +public class TestResourcePermissionValueProvider2 : ResourcePermissionValueProvider +{ + public TestResourcePermissionValueProvider2(IResourcePermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestResourcePermissionValueProvider2"; + + public override Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var result = PermissionGrantResult.Undefined; + if (context.Permission.Name == "MyResourcePermission7" && + context.ResourceName == TestEntityResource.ResourceName && + context.ResourceKey == TestEntityResource.ResourceKey7) + { + result = PermissionGrantResult.Granted; + } + + return Task.FromResult(result); + } + + public override Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in context.Permissions.Select(x => x.Name)) + { + result.Result.Add(name, name == "MyResourcePermission7" && + context.ResourceName == TestEntityResource.ResourceName && + context.ResourceKey == TestEntityResource.ResourceKey7 + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + } + + return Task.FromResult(result); + } +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectWithKeyHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectWithKeyHelper_Tests.cs new file mode 100644 index 0000000000..d5f0186b3c --- /dev/null +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/ObjectWithKeyHelper_Tests.cs @@ -0,0 +1,31 @@ +using System; +using Shouldly; +using Xunit; + +namespace Volo.Abp; + +public class KeyedObjectHelper_Tests +{ + [Fact] + public void EncodeCompositeKey() + { + var encoded = KeyedObjectHelper.EncodeCompositeKey("Book", "123"); + encoded.ShouldBe("Qm9va3x8MTIz"); + } + + [Fact] + public void DecodeCompositeKey() + { + var decoded = KeyedObjectHelper.DecodeCompositeKey("Qm9va3x8MTIz"); + decoded.ShouldBe("Book||123"); + } + + [Fact] + public void Encode_Decode_CompositeKey() + { + var encoded = KeyedObjectHelper.EncodeCompositeKey("User", 42, Guid.Empty); + var decoded = KeyedObjectHelper.DecodeCompositeKey(encoded); + + decoded.ShouldBe($"User||42||{Guid.Empty}"); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Entities/EntityHelper_Tests.cs b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Entities/EntityHelper_Tests.cs index 52ab34baee..adf82d74bd 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Entities/EntityHelper_Tests.cs +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Entities/EntityHelper_Tests.cs @@ -55,6 +55,11 @@ public class EntityHelper_Tests { return new object[] { Id }; } + + public string GetObjectKey() + { + return Id.ToString(); + } } private class MyEntityDisablesIdGeneration : Entity diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index 1e5f1b1fe7..5dc1619ec8 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -62,7 +62,7 @@
- +

@BrandingProvider.AppName

diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Integration/IIdentityUserIntegrationService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Integration/IIdentityUserIntegrationService.cs index 815c1c48c9..3a61407ddf 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Integration/IIdentityUserIntegrationService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Integration/IIdentityUserIntegrationService.cs @@ -10,12 +10,20 @@ namespace Volo.Abp.Identity.Integration; public interface IIdentityUserIntegrationService : IApplicationService { Task GetRoleNamesAsync(Guid id); - + Task FindByIdAsync(Guid id); Task FindByUserNameAsync(string userName); Task> SearchAsync(UserLookupSearchInputDto input); + Task> SearchByIdsAsync(Guid[] ids); + Task GetCountAsync(UserLookupCountInputDto input); -} \ No newline at end of file + + Task> SearchRoleAsync(RoleLookupSearchInputDto input); + + Task> SearchRoleByNamesAsync(string[] ids); + + Task GetRoleCountAsync(RoleLookupCountInputDto input); +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupCountInputDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupCountInputDto.cs new file mode 100644 index 0000000000..875d350f1c --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupCountInputDto.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.Identity; + +public class RoleLookupCountInputDto +{ + public string Filter { get; set; } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupSearchInputDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupSearchInputDto.cs new file mode 100644 index 0000000000..ebc1707055 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/RoleLookupSearchInputDto.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Dtos; + +namespace Volo.Abp.Identity; + +public class RoleLookupSearchInputDto : ExtensiblePagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/Integration/IdentityUserIntegrationService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/Integration/IdentityUserIntegrationService.cs index 37446ce1f3..4019cd9031 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/Integration/IdentityUserIntegrationService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/Integration/IdentityUserIntegrationService.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Users; namespace Volo.Abp.Identity.Integration; @@ -10,13 +11,19 @@ public class IdentityUserIntegrationService : IdentityAppServiceBase, IIdentityU { protected IUserRoleFinder UserRoleFinder { get; } protected IdentityUserRepositoryExternalUserLookupServiceProvider UserLookupServiceProvider { get; } + protected IIdentityUserRepository UserRepository { get; } + protected IIdentityRoleRepository RoleRepository { get; } public IdentityUserIntegrationService( IUserRoleFinder userRoleFinder, - IdentityUserRepositoryExternalUserLookupServiceProvider userLookupServiceProvider) + IdentityUserRepositoryExternalUserLookupServiceProvider userLookupServiceProvider, + IIdentityUserRepository userRepository, + IIdentityRoleRepository roleRepository) { UserRoleFinder = userRoleFinder; UserLookupServiceProvider = userLookupServiceProvider; + UserRepository = userRepository; + RoleRepository = roleRepository; } public virtual async Task GetRoleNamesAsync(Guid id) @@ -62,8 +69,53 @@ public class IdentityUserIntegrationService : IdentityAppServiceBase, IIdentityU ); } + public virtual async Task> SearchByIdsAsync(Guid[] ids) + { + var users = await UserRepository.GetListByIdsAsync(ids); + + return new ListResultDto( + users + .Select(u => new UserData( + u.Id, + u.UserName, + u.Email, + u.Name, + u.Surname, + u.EmailConfirmed, + u.PhoneNumber, + u.PhoneNumberConfirmed, + u.TenantId, + u.IsActive, + u.ExtraProperties)) + .ToList() + ); + } + public virtual async Task GetCountAsync(UserLookupCountInputDto input) { return await UserLookupServiceProvider.GetCountAsync(input.Filter); } + + public virtual async Task> SearchRoleAsync(RoleLookupSearchInputDto input) + { + using (RoleRepository.DisableTracking()) + { + var roles = await RoleRepository.GetListAsync(input.Filter); + return new ListResultDto(roles.Select(r => new RoleData(r.Id, r.Name, r.IsDefault, r.IsStatic, r.IsPublic, r.TenantId, r.ExtraProperties)).ToList()); + } + } + + public virtual async Task> SearchRoleByNamesAsync(string[] names) + { + using (RoleRepository.DisableTracking()) + { + var roles = await RoleRepository.GetListAsync(names); + return new ListResultDto(roles.Select(r => new RoleData(r.Id, r.Name, r.IsDefault, r.IsStatic, r.IsPublic, r.TenantId, r.ExtraProperties)).ToList()); + } + } + + public virtual async Task GetRoleCountAsync(RoleLookupCountInputDto input) + { + return await RoleRepository.GetCountAsync(input.Filter); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IUserRoleFinder.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IUserRoleFinder.cs index 1835f38952..75261b2cc4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IUserRoleFinder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IUserRoleFinder.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace Volo.Abp.Identity; @@ -7,6 +9,14 @@ public interface IUserRoleFinder { [Obsolete("Use GetRoleNamesAsync instead.")] Task GetRolesAsync(Guid userId); - + Task GetRoleNamesAsync(Guid userId); + + Task> SearchUserAsync(string filter, int page = 1); + + Task> SearchRoleAsync(string filter, int page = 1); + + Task> SearchUserByIdsAsync(Guid[] ids); + + Task> SearchRoleByNamesAsync(string[] names); } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json index 49b22071cd..71b858f834 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ar.json @@ -135,6 +135,8 @@ "ModificationTime": "وقت التعديل", "PasswordUpdateTime": "وقت تحديث كلمة المرور", "LockoutEndTime": "وقت انتهاء القفل", - "FailedAccessCount": "فشل عدد الوصول" + "FailedAccessCount": "فشل عدد الوصول", + "UserResourcePermissionProviderKeyLookupService": "المستخدم", + "RoleResourcePermissionProviderKeyLookupService": "الدور" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json index 8f0456c601..e84320059e 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/cs.json @@ -135,6 +135,8 @@ "ModificationTime": "Doba úpravy", "PasswordUpdateTime": "Čas aktualizace hesla", "LockoutEndTime": "Čas konce uzamčení", - "FailedAccessCount": "Počet neúspěšných přístupů" + "FailedAccessCount": "Počet neúspěšných přístupů", + "UserResourcePermissionProviderKeyLookupService": "Uživatel", + "RoleResourcePermissionProviderKeyLookupService": "Role" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json index 19daf4d440..4064866f00 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/de.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Endzeit der Sperrung", "FailedAccessCount": "Anzahl der fehlgeschlagenen Zugriffe", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "E-Mail-Verifizierung für die Registrierung erzwingen", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Benutzerkonten werden nicht erstellt, es sei denn, sie verifizieren ihre E-Mail-Adressen." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Benutzerkonten werden nicht erstellt, es sei denn, sie verifizieren ihre E-Mail-Adressen.", + "UserResourcePermissionProviderKeyLookupService": "Benutzer", + "RoleResourcePermissionProviderKeyLookupService": "Rolle" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json index 1e2c8a23ce..ba610a993a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/el.json @@ -128,6 +128,8 @@ "Description:Abp.Identity.User.IsEmailUpdateEnabled": "Εάν το email μπορεί να ενημερωθεί από τον χρήστη.", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Επιβολή επαλήθευσης email για εγγραφή", "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Οι λογαριασμοί χρηστών δεν θα δημιουργηθούν εκτός αν επαληθεύσουν τις διευθύνσεις email τους.", - "Details": "Λεπτομέρειες" + "Details": "Λεπτομέρειες", + "UserResourcePermissionProviderKeyLookupService": "Χρήστης", + "RoleResourcePermissionProviderKeyLookupService": "Ρόλος" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json index 45f25bc864..9f10e1f188 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en-GB.json @@ -137,6 +137,8 @@ "Description:Abp.Identity.UsersCanChange": "Allow users to change their Two Factor.", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Enforce email verification to register", "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "User accounts will not be created unless they verify their email addresses.", - "Details": "Details" + "Details": "Details", + "UserResourcePermissionProviderKeyLookupService": "User", + "RoleResourcePermissionProviderKeyLookupService": "Role" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json index f2cc74cef0..0deb6a4b56 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json @@ -135,6 +135,8 @@ "ModificationTime": "Modification time", "PasswordUpdateTime": "Password update time", "LockoutEndTime": "Lockout end time", - "FailedAccessCount": "Failed access count" + "FailedAccessCount": "Failed access count", + "UserResourcePermissionProviderKeyLookupService": "User", + "RoleResourcePermissionProviderKeyLookupService": "Role" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json index ff4d4302f8..a2a9414214 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/es.json @@ -135,6 +135,8 @@ "ModificationTime": "tiempo de modificación", "PasswordUpdateTime": "Hora de actualización de contraseña", "LockoutEndTime": "Hora de finalización del bloqueo", - "FailedAccessCount": "Recuento de acceso fallido" + "FailedAccessCount": "Recuento de acceso fallido", + "UserResourcePermissionProviderKeyLookupService": "Usuario", + "RoleResourcePermissionProviderKeyLookupService": "Rol" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json index 024b443fec..e9a1911b52 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fa.json @@ -139,6 +139,8 @@ "Description:Abp.Identity.SignIn.RequireConfirmedEmail": "کاربران می‌توانند حساب ایجاد کنند اما تا زمانی که آدرس ایمیل خود را تایید نکنند نمی‌توانند وارد شوند.", "Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber": "کاربران می‌توانند حساب ایجاد کنند اما تا زمانی که شماره تلفن خود را تایید نکنند نمی‌توانند وارد شوند.", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "اجباری کردن تایید ایمیل برای ثبت‌نام", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "حساب‌های کاربری ایجاد نخواهند شد مگر اینکه آدرس ایمیل خود را تایید کنند." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "حساب‌های کاربری ایجاد نخواهند شد مگر اینکه آدرس ایمیل خود را تایید کنند.", + "UserResourcePermissionProviderKeyLookupService": "کاربر", + "RoleResourcePermissionProviderKeyLookupService": "نقش" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json index 71cfe15712..2a37974cbb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fi.json @@ -135,6 +135,8 @@ "ModificationTime": "Muutosaika", "PasswordUpdateTime": "Salasanan päivityksen aika", "LockoutEndTime": "Lukituksen päättymisaika", - "FailedAccessCount": "Epäonnistuneet käyttöoikeudet" + "FailedAccessCount": "Epäonnistuneet käyttöoikeudet", + "UserResourcePermissionProviderKeyLookupService": "Käyttäjä", + "RoleResourcePermissionProviderKeyLookupService": "Rooli" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json index 61bc1dea98..323bb5927a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/fr.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Heure de fin du verrouillage", "FailedAccessCount": "Nombre d'accès ayant échoué", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Exiger la vérification de l'e-mail pour s'inscrire", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Les comptes d’utilisateurs ne seront pas créés à moins qu’ils ne vérifient leurs adresses e-mail." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Les comptes d’utilisateurs ne seront pas créés à moins qu’ils ne vérifient leurs adresses e-mail.", + "UserResourcePermissionProviderKeyLookupService": "Utilisateur", + "RoleResourcePermissionProviderKeyLookupService": "Rôle" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json index 464426cf34..0d5fca3dde 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hi.json @@ -135,6 +135,8 @@ "ModificationTime": "संशोधन का समय", "PasswordUpdateTime": "पासवर्ड अद्यतन समय", "LockoutEndTime": "तालाबंदी समाप्ति समय", - "FailedAccessCount": "विफल पहुंच गणना" + "FailedAccessCount": "विफल पहुंच गणना", + "UserResourcePermissionProviderKeyLookupService": "उपयोगकर्ता", + "RoleResourcePermissionProviderKeyLookupService": "भूमिका" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json index e8af421629..0e73aa5f1e 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hr.json @@ -135,6 +135,8 @@ "ModificationTime": "Vrijeme izmjene", "PasswordUpdateTime": "Vrijeme ažuriranja lozinke", "LockoutEndTime": "Vrijeme završetka zaključavanja", - "FailedAccessCount": "Broj neuspjelih pristupa" + "FailedAccessCount": "Broj neuspjelih pristupa", + "UserResourcePermissionProviderKeyLookupService": "Korisnik", + "RoleResourcePermissionProviderKeyLookupService": "Uloga" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json index 935a59e2f5..730a831d23 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/hu.json @@ -135,6 +135,8 @@ "ModificationTime": "Módosítási idő", "PasswordUpdateTime": "A jelszó frissítési ideje", "LockoutEndTime": "A zárolás befejezési ideje", - "FailedAccessCount": "Sikertelen hozzáférések száma" + "FailedAccessCount": "Sikertelen hozzáférések száma", + "UserResourcePermissionProviderKeyLookupService": "Felhasználó", + "RoleResourcePermissionProviderKeyLookupService": "Szerep" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json index ebf43ceab3..da53a10657 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/is.json @@ -135,6 +135,8 @@ "ModificationTime": "Breytingartími", "PasswordUpdateTime": "Uppfærslutími lykilorðs", "LockoutEndTime": "Lokatími lokunar", - "FailedAccessCount": "Misheppnuð fjöldi aðgangs" + "FailedAccessCount": "Misheppnuð fjöldi aðgangs", + "UserResourcePermissionProviderKeyLookupService": "Notandi", + "RoleResourcePermissionProviderKeyLookupService": "Hlutverk" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json index 1d1d9771fd..163ff98754 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/it.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Ora di fine del blocco", "FailedAccessCount": "Conteggio accessi non riusciti", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Richiedi verifica email per la registrazione", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Gli account utente non verranno creati a meno che non verifichino i loro indirizzi email." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Gli account utente non verranno creati a meno che non verifichino i loro indirizzi email.", + "UserResourcePermissionProviderKeyLookupService": "Utente", + "RoleResourcePermissionProviderKeyLookupService": "Ruolo" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json index 2b405697ae..9836137c80 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/nl.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Eindtijd uitsluiting", "FailedAccessCount": "Aantal mislukte toegangen", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "E-mailverificatie vereisen voor registratie", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Gebruikersaccounts worden niet aangemaakt tenzij ze hun e-mailadressen verifiëren." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Gebruikersaccounts worden niet aangemaakt tenzij ze hun e-mailadressen verifiëren.", + "UserResourcePermissionProviderKeyLookupService": "Gebruiker", + "RoleResourcePermissionProviderKeyLookupService": "Rol" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json index c3c8053556..18f33d89c1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pl-PL.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Czas zakończenia blokady", "FailedAccessCount": "Liczba nieudanych dostępów", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Wymagaj weryfikacji e-mail do rejestracji", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Konta użytkowników nie zostaną utworzone, dopóki nie zweryfikują swoich adresów e-mail." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Konta użytkowników nie zostaną utworzone, dopóki nie zweryfikują swoich adresów e-mail.", + "UserResourcePermissionProviderKeyLookupService": "Użytkownik", + "RoleResourcePermissionProviderKeyLookupService": "Rola" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json index 40ef80556f..cd796edbde 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/pt-BR.json @@ -135,6 +135,8 @@ "ModificationTime": "Hora da modificação", "PasswordUpdateTime": "Hora de atualização da senha", "LockoutEndTime": "Hora de término do bloqueio", - "FailedAccessCount": "Contagem de acessos com falha" + "FailedAccessCount": "Contagem de acessos com falha", + "UserResourcePermissionProviderKeyLookupService": "Usuário", + "RoleResourcePermissionProviderKeyLookupService": "Perfil" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json index efe0c53541..3ebc98d179 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ro-RO.json @@ -135,6 +135,8 @@ "ModificationTime": "Timp de modificare", "PasswordUpdateTime": "Ora actualizării parolei", "LockoutEndTime": "Ora de încheiere a blocării", - "FailedAccessCount": "Număr de acces eșuat" + "FailedAccessCount": "Număr de acces eșuat", + "UserResourcePermissionProviderKeyLookupService": "Utilizator", + "RoleResourcePermissionProviderKeyLookupService": "Rol" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json index 6afaf14b1a..f9ddb814d4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/ru.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Время окончания блокировки", "FailedAccessCount": "Количество неудачных попыток доступа", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Требовать подтверждение электронной почты для регистрации", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Учетные записи пользователей не будут созданы, пока они не подтвердят свои адреса электронной почты." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Учетные записи пользователей не будут созданы, пока они не подтвердят свои адреса электронной почты.", + "UserResourcePermissionProviderKeyLookupService": "Пользователь", + "RoleResourcePermissionProviderKeyLookupService": "Роль" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json index e529910a5e..26486aa6ab 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sk.json @@ -135,6 +135,8 @@ "ModificationTime": "Čas úpravy", "PasswordUpdateTime": "Čas aktualizácie hesla", "LockoutEndTime": "Čas ukončenia uzamknutia", - "FailedAccessCount": "Počet neúspešných prístupov" + "FailedAccessCount": "Počet neúspešných prístupov", + "UserResourcePermissionProviderKeyLookupService": "Používateľ", + "RoleResourcePermissionProviderKeyLookupService": "Rola" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json index c02577c385..8ae2a2f81b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sl.json @@ -135,6 +135,8 @@ "ModificationTime": "Čas spreminjanja", "PasswordUpdateTime": "Čas posodobitve gesla", "LockoutEndTime": "Končni čas zaklepanja", - "FailedAccessCount": "Število neuspešnih dostopov" + "FailedAccessCount": "Število neuspešnih dostopov", + "UserResourcePermissionProviderKeyLookupService": "Uporabnik", + "RoleResourcePermissionProviderKeyLookupService": "Vloga" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sv.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sv.json index 166f32a10a..aef65e2b11 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sv.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/sv.json @@ -135,6 +135,8 @@ "ModificationTime": "Tid för modifiering", "PasswordUpdateTime": "Uppdateringstid för lösenord", "LockoutEndTime": "Sluttid för låsning", - "FailedAccessCount": "Antal misslyckade åtkomster" + "FailedAccessCount": "Antal misslyckade åtkomster", + "UserResourcePermissionProviderKeyLookupService": "Användare", + "RoleResourcePermissionProviderKeyLookupService": "Roll" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json index 2da62b0355..0a6e4d393c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/tr.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Kilitlenme bitiş zamanı", "FailedAccessCount": "Başarısız giriş denemesi sayısı", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Kayıt için e-posta doğrulaması zorunlu kıl", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Kullanıcı hesapları, e-posta adreslerini doğrulamadıkça oluşturulmayacaktır." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Kullanıcı hesapları, e-posta adreslerini doğrulamadıkça oluşturulmayacaktır.", + "UserResourcePermissionProviderKeyLookupService": "Kullanıcı", + "RoleResourcePermissionProviderKeyLookupService": "Rol" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json index a98baf6566..32c1dfe008 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/vi.json @@ -135,6 +135,8 @@ "LockoutEndTime": "Thời gian kết thúc khóa", "FailedAccessCount": "Số lượt truy cập không thành công", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Yêu cầu xác minh email để đăng ký", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Tài khoản người dùng sẽ không được tạo ra trừ khi họ xác minh địa chỉ email của mình." + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "Tài khoản người dùng sẽ không được tạo ra trừ khi họ xác minh địa chỉ email của mình.", + "UserResourcePermissionProviderKeyLookupService": "Người dùng", + "RoleResourcePermissionProviderKeyLookupService": "Vai trò" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json index 0cfc117cf6..3a1239ddc7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hans.json @@ -135,6 +135,8 @@ "ModificationTime": "修改时间", "PasswordUpdateTime": "密码更新时间", "LockoutEndTime": "锁定结束时间", - "FailedAccessCount": "访问失败次数" + "FailedAccessCount": "访问失败次数", + "UserResourcePermissionProviderKeyLookupService": "用户", + "RoleResourcePermissionProviderKeyLookupService": "角色" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json index 39f6fe5267..a28cc6c7d4 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/zh-Hant.json @@ -135,6 +135,8 @@ "LockoutEndTime": "鎖定結束時間", "FailedAccessCount": "訪問失敗次數", "DisplayName:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "強制要求驗證電子郵件才能註冊", - "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "除非驗證他們的電子郵件地址,否則不會創建用戶帳戶。" + "Description:Abp.Identity.SignIn.RequireEmailVerificationToRegister": "除非驗證他們的電子郵件地址,否則不會創建用戶帳戶。", + "UserResourcePermissionProviderKeyLookupService": "使用者", + "RoleResourcePermissionProviderKeyLookupService": "角色" } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/RoleFinderResult.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/RoleFinderResult.cs new file mode 100644 index 0000000000..8fe118f13d --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/RoleFinderResult.cs @@ -0,0 +1,10 @@ +using System; + +namespace Volo.Abp.Identity; + +public class RoleFinderResult +{ + public Guid Id { get; set; } + + public string RoleName { get; set; } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/UserFinderResult.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/UserFinderResult.cs new file mode 100644 index 0000000000..48ba5ace7a --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/UserFinderResult.cs @@ -0,0 +1,10 @@ +using System; + +namespace Volo.Abp.Identity; + +public class UserFinderResult +{ + public Guid Id { get; set; } + + public string UserName { get; set; } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs index a9eefe019e..26bd8624b9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityRoleRepository.cs @@ -31,11 +31,17 @@ public interface IIdentityRoleRepository : IBasicRepository bool includeDetails = false, CancellationToken cancellationToken = default ); + Task> GetListAsync( IEnumerable ids, CancellationToken cancellationToken = default ); + Task> GetListAsync( + IEnumerable names, + CancellationToken cancellationToken = default + ); + Task> GetDefaultOnesAsync( bool includeDetails = false, CancellationToken cancellationToken = default diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs index 3ec1b2fbb1..48d8b01a73 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserRoleFinder.cs @@ -1,16 +1,21 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; namespace Volo.Abp.Identity; public class UserRoleFinder : IUserRoleFinder, ITransientDependency { protected IIdentityUserRepository IdentityUserRepository { get; } + protected IIdentityRoleRepository IdentityRoleRepository { get; } - public UserRoleFinder(IIdentityUserRepository identityUserRepository) + public UserRoleFinder(IIdentityUserRepository identityUserRepository, IIdentityRoleRepository identityRoleRepository) { IdentityUserRepository = identityUserRepository; + IdentityRoleRepository = identityRoleRepository; } [Obsolete("Use GetRoleNamesAsync instead.")] @@ -19,8 +24,62 @@ public class UserRoleFinder : IUserRoleFinder, ITransientDependency return (await IdentityUserRepository.GetRoleNamesAsync(userId)).ToArray(); } - public async Task GetRoleNamesAsync(Guid userId) + public virtual async Task GetRoleNamesAsync(Guid userId) { return (await IdentityUserRepository.GetRoleNamesAsync(userId)).ToArray(); } + + public virtual async Task> SearchUserAsync(string filter, int page = 1) + { + using (IdentityUserRepository.DisableTracking()) + { + page = page < 1 ? 1 : page; + var users = await IdentityUserRepository.GetListAsync(filter: filter, skipCount: (page - 1) * 10, maxResultCount: 10); + return users.Select(user => new UserFinderResult + { + Id = user.Id, + UserName = user.UserName + }).ToList(); + } + } + + public virtual async Task> SearchRoleAsync(string filter, int page = 1) + { + using (IdentityUserRepository.DisableTracking()) + { + page = page < 1 ? 1 : page; + var roles = await IdentityRoleRepository.GetListAsync(filter: filter, skipCount: (page - 1) * 10, maxResultCount: 10); + return roles.Select(user => new RoleFinderResult + { + Id = user.Id, + RoleName = user.Name + }).ToList(); + } + } + + public virtual async Task> SearchUserByIdsAsync(Guid[] ids) + { + using (IdentityUserRepository.DisableTracking()) + { + var users = await IdentityUserRepository.GetListByIdsAsync(ids); + return users.Select(user => new UserFinderResult + { + Id = user.Id, + UserName = user.UserName + }).ToList(); + } + } + + public virtual async Task> SearchRoleByNamesAsync(string[] names) + { + using (IdentityUserRepository.DisableTracking()) + { + var roles = await IdentityRoleRepository.GetListAsync(names); + return roles.Select(user => new RoleFinderResult + { + Id = user.Id, + RoleName = user.Name + }).ToList(); + } + } } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs index ca6dc42d6f..1da7758f19 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityRoleRepository.cs @@ -72,6 +72,13 @@ public class EfCoreIdentityRoleRepository : EfCoreRepository> GetListAsync(IEnumerable names, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(t => names.Contains(t.Name)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + public virtual async Task> GetDefaultOnesAsync( bool includeDetails = false, CancellationToken cancellationToken = default) { diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/Volo/Abp/Identity/Integration/IdentityUserIntegrationClientProxy.Generated.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/Volo/Abp/Identity/Integration/IdentityUserIntegrationClientProxy.Generated.cs index 1c2f1b61cb..ddbb2cfc55 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/Volo/Abp/Identity/Integration/IdentityUserIntegrationClientProxy.Generated.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/Volo/Abp/Identity/Integration/IdentityUserIntegrationClientProxy.Generated.cs @@ -52,6 +52,14 @@ public partial class IdentityUserIntegrationClientProxy : ClientProxyBase> SearchByIdsAsync(Guid[] ids) + { + return await RequestAsync>(nameof(SearchByIdsAsync), new ClientProxyRequestTypeValue + { + { typeof(Guid[]), ids } + }); + } + public virtual async Task GetCountAsync(UserLookupCountInputDto input) { return await RequestAsync(nameof(GetCountAsync), new ClientProxyRequestTypeValue @@ -59,4 +67,28 @@ public partial class IdentityUserIntegrationClientProxy : ClientProxyBase> SearchRoleAsync(RoleLookupSearchInputDto input) + { + return await RequestAsync>(nameof(SearchRoleAsync), new ClientProxyRequestTypeValue + { + { typeof(RoleLookupSearchInputDto), input } + }); + } + + public virtual async Task> SearchRoleByNamesAsync(String[] names) + { + return await RequestAsync>(nameof(SearchRoleByNamesAsync), new ClientProxyRequestTypeValue + { + { typeof(String[]), names } + }); + } + + public virtual async Task GetRoleCountAsync(RoleLookupCountInputDto input) + { + return await RequestAsync(nameof(GetRoleCountAsync), new ClientProxyRequestTypeValue + { + { typeof(RoleLookupCountInputDto), input } + }); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/identity-generate-proxy.json b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/identity-generate-proxy.json index 33efd0a6e7..3937d99aa9 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/identity-generate-proxy.json +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/ClientProxies/identity-generate-proxy.json @@ -200,6 +200,18 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "ExtraProperties", + "jsonName": null, + "type": "Volo.Abp.Data.ExtraPropertyDictionary", + "typeSimple": "{string:object}", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { @@ -673,6 +685,18 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "ExtraProperties", + "jsonName": null, + "type": "Volo.Abp.Data.ExtraPropertyDictionary", + "typeSimple": "{string:object}", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { @@ -1220,6 +1244,18 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "ExtraProperties", + "jsonName": null, + "type": "Volo.Abp.Data.ExtraPropertyDictionary", + "typeSimple": "{string:object}", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { @@ -1348,6 +1384,23 @@ "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" } }, + { + "name": "SearchByIdsAsync", + "parametersOnMethod": [ + { + "name": "ids", + "typeAsString": "System.Guid[], System.Private.CoreLib", + "type": "System.Guid[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, { "name": "GetCountAsync", "parametersOnMethod": [ @@ -1364,6 +1417,57 @@ "type": "System.Int64", "typeSimple": "number" } + }, + { + "name": "SearchRoleAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Identity.RoleLookupSearchInputDto, Volo.Abp.Identity.Application.Contracts", + "type": "Volo.Abp.Identity.RoleLookupSearchInputDto", + "typeSimple": "Volo.Abp.Identity.RoleLookupSearchInputDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "SearchRoleByNamesAsync", + "parametersOnMethod": [ + { + "name": "ids", + "typeAsString": "System.String[], System.Private.CoreLib", + "type": "System.String[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + } + }, + { + "name": "GetRoleCountAsync", + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Identity.RoleLookupCountInputDto, Volo.Abp.Identity.Application.Contracts", + "type": "Volo.Abp.Identity.RoleLookupCountInputDto", + "typeSimple": "Volo.Abp.Identity.RoleLookupCountInputDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Int64", + "typeSimple": "number" + } } ] } @@ -1544,6 +1648,55 @@ "constraintTypes": null, "bindingSourceId": "ModelBinding", "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "ExtraProperties", + "jsonName": null, + "type": "Volo.Abp.Data.ExtraPropertyDictionary", + "typeSimple": "{string:object}", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.Identity.Integration.IIdentityUserIntegrationService" + }, + "SearchByIdsAsyncByIds": { + "uniqueName": "SearchByIdsAsyncByIds", + "name": "SearchByIdsAsync", + "httpMethod": "GET", + "url": "integration-api/identity/users/search/by-ids", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "ids", + "typeAsString": "System.Guid[], System.Private.CoreLib", + "type": "System.Guid[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "ids", + "name": "ids", + "jsonName": null, + "type": "System.Guid[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" } ], "returnValue": { @@ -1589,6 +1742,165 @@ }, "allowAnonymous": null, "implementFrom": "Volo.Abp.Identity.Integration.IIdentityUserIntegrationService" + }, + "SearchRoleAsyncByInput": { + "uniqueName": "SearchRoleAsyncByInput", + "name": "SearchRoleAsync", + "httpMethod": "GET", + "url": "integration-api/identity/users/search/roles", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Identity.RoleLookupSearchInputDto, Volo.Abp.Identity.Application.Contracts", + "type": "Volo.Abp.Identity.RoleLookupSearchInputDto", + "typeSimple": "Volo.Abp.Identity.RoleLookupSearchInputDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "Filter", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "Sorting", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "SkipCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "MaxResultCount", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "ExtraProperties", + "jsonName": null, + "type": "Volo.Abp.Data.ExtraPropertyDictionary", + "typeSimple": "{string:object}", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.Identity.Integration.IIdentityUserIntegrationService" + }, + "SearchRoleByNamesAsyncByNames": { + "uniqueName": "SearchRoleByNamesAsyncByNames", + "name": "SearchRoleByNamesAsync", + "httpMethod": "GET", + "url": "integration-api/identity/users/search/roles/by-names", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "names", + "typeAsString": "System.String[], System.Private.CoreLib", + "type": "System.String[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "names", + "name": "names", + "jsonName": null, + "type": "System.String[]", + "typeSimple": "[string]", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.Identity.Integration.IIdentityUserIntegrationService" + }, + "GetRoleCountAsyncByInput": { + "uniqueName": "GetRoleCountAsyncByInput", + "name": "GetRoleCountAsync", + "httpMethod": "GET", + "url": "integration-api/identity/users/count/roles", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "input", + "typeAsString": "Volo.Abp.Identity.RoleLookupCountInputDto, Volo.Abp.Identity.Application.Contracts", + "type": "Volo.Abp.Identity.RoleLookupCountInputDto", + "typeSimple": "Volo.Abp.Identity.RoleLookupCountInputDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "input", + "name": "Filter", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" + } + ], + "returnValue": { + "type": "System.Int64", + "typeSimple": "number" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.Identity.Integration.IIdentityUserIntegrationService" } } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs index 201c9f3eb0..ed7f0f5382 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/HttpClientUserRoleFinder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -25,8 +26,59 @@ public class HttpClientUserRoleFinder : IUserRoleFinder, ITransientDependency return output.Items.Select(r => r.Name).ToArray(); } - public async Task GetRoleNamesAsync(Guid userId) + public virtual async Task GetRoleNamesAsync(Guid userId) { return await _userIntegrationService.GetRoleNamesAsync(userId); } + + public virtual async Task> SearchUserAsync(string filter, int page = 1) + { + page = page < 1 ? 1 : page; + var users = await _userIntegrationService.SearchAsync(new UserLookupSearchInputDto() + { + Filter = filter, + SkipCount = (page - 1) * 10 + }); + return users.Items.Select(u => new UserFinderResult + { + Id = u.Id, + UserName = u.UserName + }).ToList(); + } + + public virtual async Task> SearchRoleAsync(string filter, int page = 1) + { + page = page < 1 ? 1 : page; + var roles = await _userIntegrationService.SearchRoleAsync(new RoleLookupSearchInputDto() + { + Filter = filter, + SkipCount = (page - 1) * 10 + }); + + return roles.Items.Select(r => new RoleFinderResult + { + Id = r.Id, + RoleName = r.Name + }).ToList(); + } + + public virtual async Task> SearchUserByIdsAsync(Guid[] ids) + { + var users = await _userIntegrationService.SearchByIdsAsync(ids); + return users.Items.Select(u => new UserFinderResult + { + Id = u.Id, + UserName = u.UserName + }).ToList(); + } + + public virtual async Task> SearchRoleByNamesAsync(string[] names) + { + var roles = await _userIntegrationService.SearchRoleByNamesAsync(names); + return roles.Items.Select(r => new RoleFinderResult + { + Id = r.Id, + RoleName = r.Name + }).ToList(); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/Integration/IdentityUserIntegrationController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/Integration/IdentityUserIntegrationController.cs index 2a84385e48..a30b73d5cd 100644 --- a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/Integration/IdentityUserIntegrationController.cs +++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/Integration/IdentityUserIntegrationController.cs @@ -20,7 +20,7 @@ public class IdentityUserIntegrationController : AbpControllerBase, IIdentityUse { UserIntegrationService = userIntegrationService; } - + [HttpGet] [Route("{id}/role-names")] public virtual Task GetRoleNamesAsync(Guid id) @@ -49,10 +49,38 @@ public class IdentityUserIntegrationController : AbpControllerBase, IIdentityUse return UserIntegrationService.SearchAsync(input); } + [HttpGet] + [Route("search/by-ids")] + public virtual Task> SearchByIdsAsync(Guid[] ids) + { + return UserIntegrationService.SearchByIdsAsync(ids); + } + [HttpGet] [Route("count")] public Task GetCountAsync(UserLookupCountInputDto input) { return UserIntegrationService.GetCountAsync(input); } -} \ No newline at end of file + + [HttpGet] + [Route("search/roles")] + public virtual Task> SearchRoleAsync(RoleLookupSearchInputDto input) + { + return UserIntegrationService.SearchRoleAsync(input); + } + + [HttpGet] + [Route("search/roles/by-names")] + public virtual Task> SearchRoleByNamesAsync(string[] names) + { + return UserIntegrationService.SearchRoleByNamesAsync(names); + } + + [HttpGet] + [Route("count/roles")] + public virtual Task GetRoleCountAsync(RoleLookupCountInputDto input) + { + return UserIntegrationService.GetRoleCountAsync(input); + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs index 7deee94160..f613a3ee88 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityRoleRepository.cs @@ -78,6 +78,13 @@ public class MongoIdentityRoleRepository : MongoDbRepository> GetListAsync(IEnumerable names, CancellationToken cancellationToken = default) + { + return await (await GetQueryableAsync(cancellationToken)) + .Where(x => names.Contains(x.Name)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + public virtual async Task> GetDefaultOnesAsync( bool includeDetails = false, CancellationToken cancellationToken = default) diff --git a/modules/identity/src/Volo.Abp.Identity.Web/wwwroot/client-proxies/identity-proxy.js b/modules/identity/src/Volo.Abp.Identity.Web/wwwroot/client-proxies/identity-proxy.js index 250abbc47b..6de3aeb8d5 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/wwwroot/client-proxies/identity-proxy.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/wwwroot/client-proxies/identity-proxy.js @@ -20,7 +20,7 @@ volo.abp.identity.identityRole.getList = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/identity/roles' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', + url: abp.appPath + 'api/identity/roles' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }, { name: 'extraProperties', value: input.extraProperties }]) + '', type: 'GET' }, ajaxParams)); }; @@ -73,7 +73,7 @@ volo.abp.identity.identityUser.getList = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/identity/users' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', + url: abp.appPath + 'api/identity/users' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }, { name: 'extraProperties', value: input.extraProperties }]) + '', type: 'GET' }, ajaxParams)); }; @@ -163,7 +163,7 @@ volo.abp.identity.identityUserLookup.search = function(input, ajaxParams) { return abp.ajax($.extend(true, { - url: abp.appPath + 'api/identity/users/lookup/search' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', + url: abp.appPath + 'api/identity/users/lookup/search' + abp.utils.buildQueryString([{ name: 'filter', value: input.filter }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }, { name: 'extraProperties', value: input.extraProperties }]) + '', type: 'GET' }, ajaxParams)); }; diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs index 973577ccff..43399a134d 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs @@ -1,4 +1,5 @@ using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.Users; @@ -22,6 +23,12 @@ public class AbpPermissionManagementDomainIdentityModule : AbpModule //TODO: Can we prevent duplication of permission names without breaking the design and making the system complicated options.ProviderPolicies[UserPermissionValueProvider.ProviderName] = "AbpIdentity.Users.ManagePermissions"; options.ProviderPolicies[RolePermissionValueProvider.ProviderName] = "AbpIdentity.Roles.ManagePermissions"; + + options.ResourceManagementProviders.Add(); + options.ResourceManagementProviders.Add(); + + options.ResourcePermissionProviderKeyLookupServices.Add(); + options.ResourcePermissionProviderKeyLookupServices.Add(); }); } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs index cb63b2681a..82200f763f 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus; @@ -14,15 +15,18 @@ public class RoleDeletedEventHandler : ITransientDependency { protected IPermissionManager PermissionManager { get; } + protected IResourcePermissionManager ResourcePermissionManager { get; } - public RoleDeletedEventHandler(IPermissionManager permissionManager) + public RoleDeletedEventHandler(IPermissionManager permissionManager, IResourcePermissionManager resourcePermissionManager) { PermissionManager = permissionManager; + ResourcePermissionManager = resourcePermissionManager; } [UnitOfWork] public virtual async Task HandleEventAsync(EntityDeletedEto eventData) { await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); + await ResourcePermissionManager.DeleteAsync(RoleResourcePermissionValueProvider.ProviderName, eventData.Entity.Name); } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs index e97d524cd7..5cd2dda193 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RolePermissionManagementProvider.cs @@ -49,9 +49,8 @@ public class RolePermissionManagementProvider : PermissionManagementProvider } - if (providerName == UserPermissionValueProvider.ProviderName) + if (providerName == UserPermissionValueProvider.ProviderName && Guid.TryParse(providerKey, out var userId)) { - var userId = Guid.Parse(providerKey); var roleNames = await UserRoleFinder.GetRoleNamesAsync(userId); foreach (var roleName in roleNames) diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..bce070130c --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; +using Volo.Abp.Identity; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class RoleResourcePermissionManagementProvider : ResourcePermissionManagementProvider +{ + public override string Name => RoleResourcePermissionValueProvider.ProviderName; + + protected IUserRoleFinder UserRoleFinder { get; } + + public RoleResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcepPrmissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant, + IUserRoleFinder userRoleFinder) + : base( + resourcepPrmissionGrantRepository, + guidGenerator, + currentTenant) + { + UserRoleFinder = userRoleFinder; + } + + public override async Task CheckAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + var multipleGrantInfo = await CheckAsync(new[] { name }, resourceName, resourceKey, providerName, providerKey); + + return multipleGrantInfo.Result.Values.First(); + } + + public override async Task CheckAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var multiplePermissionValueProviderGrantInfo = new MultipleResourcePermissionValueProviderGrantInfo(names); + var resourcePermissionGrants = new List(); + + if (providerName == Name) + { + resourcePermissionGrants.AddRange(await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, providerName, providerKey)); + } + + if (providerName == UserResourcePermissionValueProvider.ProviderName && Guid.TryParse(providerKey, out var userId)) + { + var roleNames = await UserRoleFinder.GetRoleNamesAsync(userId); + + foreach (var roleName in roleNames) + { + resourcePermissionGrants.AddRange(await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, Name, roleName)); + } + } + + resourcePermissionGrants = resourcePermissionGrants.Distinct().ToList(); + if (!resourcePermissionGrants.Any()) + { + return multiplePermissionValueProviderGrantInfo; + } + + foreach (var permissionName in names) + { + var resourcePermissionGrant = resourcePermissionGrants.FirstOrDefault(x => x.Name == permissionName); + if (resourcePermissionGrant != null) + { + multiplePermissionValueProviderGrantInfo.Result[permissionName] = new ResourcePermissionValueProviderGrantInfo(true, resourcePermissionGrant.ProviderKey); + } + } + + return multiplePermissionValueProviderGrantInfo; + } + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionProviderKeyLookupService.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionProviderKeyLookupService.cs new file mode 100644 index 0000000000..fa9fc31f79 --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionProviderKeyLookupService.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class RoleResourcePermissionProviderKeyLookupService : IResourcePermissionProviderKeyLookupService, ITransientDependency +{ + public string Name => RoleResourcePermissionValueProvider.ProviderName; + + public ILocalizableString DisplayName { get; } + + protected IUserRoleFinder UserRoleFinder { get; } + + public RoleResourcePermissionProviderKeyLookupService(IUserRoleFinder userRoleFinder) + { + UserRoleFinder = userRoleFinder; + DisplayName = LocalizableString.Create(nameof(RoleResourcePermissionProviderKeyLookupService)); + } + + public virtual async Task> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default) + { + var roles = await UserRoleFinder.SearchRoleAsync(filter, page); + return roles.Select(r => new ResourcePermissionProviderKeyInfo(r.RoleName, r.RoleName)).ToList(); + } + + public virtual async Task> SearchAsync(string[] keys, CancellationToken cancellationToken = default) + { + var roles = await UserRoleFinder.SearchRoleByNamesAsync(keys.Distinct().ToArray()); + return roles.Select(r => new ResourcePermissionProviderKeyInfo(r.RoleName, r.RoleName)).ToList(); + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs index ca865063e0..bf9a86c06d 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Identity; @@ -12,13 +13,19 @@ public class RoleUpdateEventHandler : { protected IPermissionManager PermissionManager { get; } protected IPermissionGrantRepository PermissionGrantRepository { get; } + protected IResourcePermissionManager ResourcePermissionManager { get; } + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } public RoleUpdateEventHandler( IPermissionManager permissionManager, - IPermissionGrantRepository permissionGrantRepository) + IPermissionGrantRepository permissionGrantRepository, + IResourcePermissionManager resourcePermissionManager, + IResourcePermissionGrantRepository resourcePermissionGrantRepository) { PermissionManager = permissionManager; PermissionGrantRepository = permissionGrantRepository; + ResourcePermissionManager = resourcePermissionManager; + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; } public async Task HandleEventAsync(IdentityRoleNameChangedEto eventData) @@ -28,5 +35,11 @@ public class RoleUpdateEventHandler : { await PermissionManager.UpdateProviderKeyAsync(permissionGrant, eventData.Name); } + + var resourcePermissionGrantsInRole = await ResourcePermissionGrantRepository.GetListAsync(RoleResourcePermissionValueProvider.ProviderName, eventData.OldName); + foreach (var resourcePermissionGrant in resourcePermissionGrantsInRole) + { + await ResourcePermissionManager.UpdateProviderKeyAsync(resourcePermissionGrant, eventData.Name); + } } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserDeletedEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserDeletedEventHandler.cs index 35aaba29ae..b10cef8fe4 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserDeletedEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserDeletedEventHandler.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; @@ -13,15 +14,18 @@ public class UserDeletedEventHandler : ITransientDependency { protected IPermissionManager PermissionManager { get; } + protected IResourcePermissionManager ResourcePermissionManager { get; } - public UserDeletedEventHandler(IPermissionManager permissionManager) + public UserDeletedEventHandler(IPermissionManager permissionManager, IResourcePermissionManager resourcePermissionManager) { PermissionManager = permissionManager; + ResourcePermissionManager = resourcePermissionManager; } [UnitOfWork] public virtual async Task HandleEventAsync(EntityDeletedEto eventData) { await PermissionManager.DeleteAsync(UserPermissionValueProvider.ProviderName, eventData.Entity.Id.ToString()); + await ResourcePermissionManager.DeleteAsync(UserResourcePermissionValueProvider.ProviderName, eventData.Entity.Id.ToString()); } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..ef165d422d --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs @@ -0,0 +1,22 @@ +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class UserResourcePermissionManagementProvider : ResourcePermissionManagementProvider +{ + public override string Name => UserResourcePermissionValueProvider.ProviderName; + + public UserResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant) + : base( + resourcePermissionGrantRepository, + guidGenerator, + currentTenant) + { + + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionProviderKeyLookupService.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionProviderKeyLookupService.cs new file mode 100644 index 0000000000..83f0e79099 --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionProviderKeyLookupService.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class UserResourcePermissionProviderKeyLookupService : IResourcePermissionProviderKeyLookupService, ITransientDependency +{ + public string Name => UserResourcePermissionValueProvider.ProviderName; + + public ILocalizableString DisplayName { get; } + + protected IUserRoleFinder UserRoleFinder { get; } + + public UserResourcePermissionProviderKeyLookupService(IUserRoleFinder userRoleFinder) + { + UserRoleFinder = userRoleFinder; + DisplayName = LocalizableString.Create(nameof(UserResourcePermissionProviderKeyLookupService)); + } + + public virtual async Task> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default) + { + var users = await UserRoleFinder.SearchUserAsync(filter, page); + return users.Select(u => new ResourcePermissionProviderKeyInfo(u.Id.ToString(), u.UserName)).ToList(); + } + + public virtual async Task> SearchAsync(string[] keys, CancellationToken cancellationToken = default) + { + var ids = keys + .Select(key => Guid.TryParse(key, out var id) ? (Guid?)id : null) + .Where(id => id.HasValue) + .Select(id => id.Value) + .Distinct() + .ToArray(); + var users = await UserRoleFinder.SearchUserByIdsAsync(ids.ToArray()); + return users.Select(u => new ResourcePermissionProviderKeyInfo(u.Id.ToString(), u.UserName)).ToList(); + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/RoleResourcePermissionManagerExtensions.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/RoleResourcePermissionManagerExtensions.cs new file mode 100644 index 0000000000..53ff327f7b --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/RoleResourcePermissionManagerExtensions.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public static class RoleResourceresourcePermissionManagerExtensions +{ + public static Task GetForRoleAsync([NotNull] this IResourcePermissionManager resourcePermissionManager, string roleName, string permissionName, [NotNull] string resourceName, [NotNull] string resourceKey) + { + Check.NotNull(resourcePermissionManager, nameof(resourcePermissionManager)); + + return resourcePermissionManager.GetAsync(permissionName, resourceName, resourceKey, RolePermissionValueProvider.ProviderName, roleName); + } + + public static Task> GetAllForRoleAsync([NotNull] this IResourcePermissionManager resourcePermissionManager, string roleName, [NotNull] string resourceName, [NotNull] string resourceKey) + { + Check.NotNull(resourcePermissionManager, nameof(resourcePermissionManager)); + + return resourcePermissionManager.GetAllAsync(resourceName, resourceKey, RolePermissionValueProvider.ProviderName, roleName); + } + + public static Task SetForRoleAsync([NotNull] this IResourcePermissionManager resourcePermissionManager, string roleName, [NotNull] string permissionName, [NotNull] string resourceName, [NotNull] string resourceKey, bool isGranted) + { + Check.NotNull(resourcePermissionManager, nameof(resourcePermissionManager)); + + return resourcePermissionManager.SetAsync(permissionName, resourceName, resourceKey, RolePermissionValueProvider.ProviderName, roleName, isGranted); + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/UserResourcePermissionManagerExtensions.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/UserResourcePermissionManagerExtensions.cs new file mode 100644 index 0000000000..c0fe2eb845 --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/UserResourcePermissionManagerExtensions.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Authorization.Permissions.Resources; + +namespace Volo.Abp.PermissionManagement; + +public static class UserResourcePermissionManagerExtensions +{ + public static Task> GetAllForUserAsync([NotNull] this IResourcePermissionManager resourcePermissionManager, Guid userId, [NotNull] string resourceName, [NotNull] string resourceKey) + { + Check.NotNull(resourcePermissionManager, nameof(resourcePermissionManager)); + + return resourcePermissionManager.GetAllAsync(resourceName, resourceKey, UserResourcePermissionValueProvider.ProviderName, userId.ToString()); + } + + public static Task SetForUserAsync([NotNull] this IResourcePermissionManager resourcePermissionManager, Guid userId, [NotNull] string name, [NotNull] string resourceName, [NotNull] string resourceKey, bool isGranted) + { + Check.NotNull(resourcePermissionManager, nameof(resourcePermissionManager)); + + return resourcePermissionManager.SetAsync(name, resourceName, resourceKey, UserResourcePermissionValueProvider.ProviderName, userId.ToString(), isGranted); + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs index 524c7c25f3..56f9049b92 100644 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/UserRoleFinder_Tests.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; using Shouldly; using Xunit; @@ -19,11 +16,47 @@ public class UserRoleFinder_Tests : AbpIdentityDomainTestBase } [Fact] - public async Task GetRolesAsync() + public async Task GetRoleNamesAsync() { - var roleNames = await _userRoleFinder.GetRolesAsync(_testData.UserJohnId); + var roleNames = await _userRoleFinder.GetRoleNamesAsync(_testData.UserJohnId); roleNames.ShouldNotBeEmpty(); roleNames.ShouldContain(x => x == "moderator"); roleNames.ShouldContain(x => x == "supporter"); } + + [Fact] + public async Task SearchUserAsync() + { + var userResults = await _userRoleFinder.SearchUserAsync("john"); + userResults.ShouldNotBeEmpty(); + userResults.ShouldContain(x => x.Id == _testData.UserJohnId); + } + + [Fact] + public async Task SearchRoleAsync() + { + var roleResults = await _userRoleFinder.SearchRoleAsync("moderator"); + roleResults.ShouldNotBeEmpty(); + roleResults.ShouldContain(x => x.RoleName == "moderator"); + } + + [Fact] + public async Task SearchUserByIdsAsync() + { + var userResults = await _userRoleFinder.SearchUserByIdsAsync(new[] { _testData.UserJohnId, _testData.UserBobId }); + userResults.ShouldNotBeEmpty(); + userResults.Count.ShouldBe(2); + userResults.ShouldContain(x => x.Id == _testData.UserJohnId && x.UserName == "john.nash"); + userResults.ShouldContain(x => x.Id == _testData.UserBobId && x.UserName == "bob"); + } + + [Fact] + public async Task SearchRoleByNamesAsync() + { + var roleResults = await _userRoleFinder.SearchRoleByNamesAsync(new[] { "moderator", "manager" }); + roleResults.ShouldNotBeEmpty(); + roleResults.Count.ShouldBe(2); + roleResults.ShouldContain(x => x.RoleName == "moderator"); + roleResults.ShouldContain(x => x.RoleName == "manager"); + } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionDefinitionListResultDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionDefinitionListResultDto.cs new file mode 100644 index 0000000000..ea1ce882df --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionDefinitionListResultDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class GetResourcePermissionDefinitionListResultDto +{ + public List Permissions { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionListResultDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionListResultDto.cs new file mode 100644 index 0000000000..b9c4db2190 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionListResultDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class GetResourcePermissionListResultDto +{ + public List Permissions { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionWithProviderListResultDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionWithProviderListResultDto.cs new file mode 100644 index 0000000000..dcf4556d04 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourcePermissionWithProviderListResultDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class GetResourcePermissionWithProviderListResultDto +{ + public List Permissions { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourceProviderListResultDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourceProviderListResultDto.cs new file mode 100644 index 0000000000..ede31a6ca5 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GetResourceProviderListResultDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class GetResourceProviderListResultDto +{ + public List Providers { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GrantedResourcePermissionDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GrantedResourcePermissionDto.cs new file mode 100644 index 0000000000..bbb1de112a --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/GrantedResourcePermissionDto.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.PermissionManagement; + +public class GrantedResourcePermissionDto +{ + public string Name { get; set; } + + public string DisplayName { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs index 819d643a21..dd24d436be 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/IPermissionAppService.cs @@ -11,4 +11,18 @@ public interface IPermissionAppService : IApplicationService Task GetByGroupAsync([NotNull] string groupName, [NotNull] string providerName, [NotNull] string providerKey); Task UpdateAsync([NotNull] string providerName, [NotNull] string providerKey, UpdatePermissionsDto input); + + Task GetResourceProviderKeyLookupServicesAsync(string resourceName); + + Task SearchResourceProviderKeyAsync(string resourceName, string serviceName, string filter, int page); + + Task GetResourceDefinitionsAsync([NotNull] string resourceName); + + Task GetResourceAsync([NotNull] string resourceName, [NotNull] string resourceKey); + + Task GetResourceByProviderAsync([NotNull] string resourceName, [NotNull] string resourceKey, [NotNull] string providerName, [NotNull] string providerKey); + + Task UpdateResourceAsync([NotNull] string resourceName, [NotNull] string resourceKey, UpdateResourcePermissionsDto input); + + Task DeleteResourceAsync([NotNull] string resourceName, [NotNull] string resourceKey, [NotNull] string providerName, [NotNull] string providerKey); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionDefinitionDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionDefinitionDto.cs new file mode 100644 index 0000000000..b8218b562c --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionDefinitionDto.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionDefinitionDto +{ + public string Name { get; set; } + + public string DisplayName { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionGrantInfoDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionGrantInfoDto.cs new file mode 100644 index 0000000000..cf286815a5 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionGrantInfoDto.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionGrantInfoDto +{ + public string ProviderName { get; set; } + + public string ProviderKey { get; set; } + + public string ProviderDisplayName { get; set; } + + public string ProviderNameDisplayName { get; set; } + + public List Permissions { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionWithProdiverGrantInfoDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionWithProdiverGrantInfoDto.cs new file mode 100644 index 0000000000..d56e217cd6 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourcePermissionWithProdiverGrantInfoDto.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionWithProdiverGrantInfoDto +{ + public string Name { get; set; } + + public string DisplayName { get; set; } + + public List Providers { get; set; } + + public bool IsGranted { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourceProviderDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourceProviderDto.cs new file mode 100644 index 0000000000..98ee22c6b7 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/ResourceProviderDto.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.PermissionManagement; + +public class ResourceProviderDto +{ + public string Name { get; set; } + + public string DisplayName { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyInfo.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyInfo.cs new file mode 100644 index 0000000000..efc6ae2b18 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyInfo.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.PermissionManagement; + +public class SearchProviderKeyInfo +{ + public string ProviderKey { get; set; } + + public string ProviderDisplayName { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyListResultDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyListResultDto.cs new file mode 100644 index 0000000000..7fe4edd6e7 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/SearchProviderKeyListResultDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class SearchProviderKeyListResultDto +{ + public List Keys { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/UpdateResourcePermissionsDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/UpdateResourcePermissionsDto.cs new file mode 100644 index 0000000000..f82c27ff02 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/UpdateResourcePermissionsDto.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class UpdateResourcePermissionsDto +{ + public string ProviderName { get; set; } + + public string ProviderKey { get; set; } + + public List Permissions { get; set; } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index e628c39644..e26e387fae 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -18,12 +18,18 @@ public class PermissionAppService : ApplicationService, IPermissionAppService { protected PermissionManagementOptions Options { get; } protected IPermissionManager PermissionManager { get; } + protected IPermissionChecker PermissionChecker { get; } + protected IResourcePermissionManager ResourcePermissionManager { get; } + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } protected IPermissionDefinitionManager PermissionDefinitionManager { get; } protected ISimpleStateCheckerManager SimpleStateCheckerManager { get; } public PermissionAppService( IPermissionManager permissionManager, + IPermissionChecker permissionChecker, IPermissionDefinitionManager permissionDefinitionManager, + IResourcePermissionManager resourcePermissionManager, + IResourcePermissionGrantRepository resourcePermissionGrantRepository, IOptions options, ISimpleStateCheckerManager simpleStateCheckerManager) { @@ -32,6 +38,9 @@ public class PermissionAppService : ApplicationService, IPermissionAppService Options = options.Value; PermissionManager = permissionManager; + PermissionChecker = permissionChecker; + ResourcePermissionManager = resourcePermissionManager; + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; PermissionDefinitionManager = permissionDefinitionManager; SimpleStateCheckerManager = simpleStateCheckerManager; } @@ -160,6 +169,206 @@ public class PermissionAppService : ApplicationService, IPermissionAppService } } + public virtual async Task GetResourceProviderKeyLookupServicesAsync(string resourceName) + { + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + if (!resourcePermissions.Any() || + !await AuthorizationService.IsGrantedAnyAsync(resourcePermissions.Select(p => p.ManagementPermissionName!).ToArray())) + { + return new GetResourceProviderListResultDto + { + Providers = new List() + }; + } + + var lookupServices = await ResourcePermissionManager.GetProviderKeyLookupServicesAsync(); + return new GetResourceProviderListResultDto + { + Providers = lookupServices.Select(s => new ResourceProviderDto + { + Name = s.Name, + DisplayName = s.DisplayName.Localize(StringLocalizerFactory), + }).ToList() + }; + } + + public virtual async Task SearchResourceProviderKeyAsync(string resourceName, string serviceName, string filter, int page) + { + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + if (resourcePermissions.IsNullOrEmpty() || + !await AuthorizationService.IsGrantedAnyAsync(resourcePermissions.Select(p => p.ManagementPermissionName!).ToArray())) + { + return new SearchProviderKeyListResultDto(); + } + + var lookupService = await ResourcePermissionManager.GetProviderKeyLookupServiceAsync(serviceName); + var keys = await lookupService.SearchAsync(filter, page); + return new SearchProviderKeyListResultDto + { + Keys = keys.Select(x => new SearchProviderKeyInfo + { + ProviderKey = x.ProviderKey, + ProviderDisplayName = x.ProviderDisplayName, + }).ToList() + }; + } + + public virtual async Task GetResourceDefinitionsAsync(string resourceName) + { + var result = new GetResourcePermissionDefinitionListResultDto + { + Permissions = new List() + }; + + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + var permissionGrants = (await PermissionChecker.IsGrantedAsync(resourcePermissions + .Select(rp => rp.ManagementPermissionName!) + .Distinct().ToArray())).Result.Where(x => x.Value == PermissionGrantResult.Granted).Select(x => x.Key) + .ToHashSet(); + foreach (var resourcePermission in resourcePermissions) + { + if (!permissionGrants.Contains(resourcePermission.ManagementPermissionName)) + { + continue; + } + + result.Permissions.Add(new ResourcePermissionDefinitionDto + { + Name = resourcePermission.Name, + DisplayName = resourcePermission.DisplayName?.Localize(StringLocalizerFactory), + }); + } + + return result; + } + + public virtual async Task GetResourceAsync(string resourceName, string resourceKey) + { + var result = new GetResourcePermissionListResultDto + { + Permissions = new List() + }; + + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + var resourcePermissionGrants = await ResourcePermissionManager.GetAllGroupAsync(resourceName, resourceKey); + var permissionGrants = (await PermissionChecker.IsGrantedAsync(resourcePermissions + .Select(rp => rp.ManagementPermissionName!) + .Distinct().ToArray())).Result.Where(x => x.Value == PermissionGrantResult.Granted).Select(x => x.Key) + .ToHashSet(); + foreach (var resourcePermissionGrant in resourcePermissionGrants) + { + var resourcePermissionGrantInfoDto = new ResourcePermissionGrantInfoDto + { + ProviderName = resourcePermissionGrant.ProviderName, + ProviderKey = resourcePermissionGrant.ProviderKey, + ProviderDisplayName = resourcePermissionGrant.ProviderDisplayName, + ProviderNameDisplayName = resourcePermissionGrant.ProviderNameDisplayName?.Localize(StringLocalizerFactory), + Permissions = new List() + }; + foreach (var permission in resourcePermissionGrant.Permissions) + { + var resourcePermission = resourcePermissions.FirstOrDefault(x => x.Name == permission); + if (resourcePermission == null) + { + continue; + } + + if (!permissionGrants.Contains(resourcePermission.ManagementPermissionName)) + { + continue; + } + + resourcePermissionGrantInfoDto.Permissions.Add(new GrantedResourcePermissionDto() + { + Name = permission, + DisplayName = resourcePermission?.DisplayName.Localize(StringLocalizerFactory), + }); + } + + if(resourcePermissionGrantInfoDto.Permissions.Any()) + { + result.Permissions.Add(resourcePermissionGrantInfoDto); + } + } + + return result; + } + + public virtual async Task GetResourceByProviderAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + var result = new GetResourcePermissionWithProviderListResultDto + { + Permissions = new List() + }; + + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + var resourcePermissionGrants = await ResourcePermissionManager.GetAllAsync(resourceName, resourceKey, providerName, providerKey); + var permissionGrants = (await PermissionChecker.IsGrantedAsync(resourcePermissions + .Select(rp => rp.ManagementPermissionName!) + .Distinct().ToArray())).Result.Where(x => x.Value == PermissionGrantResult.Granted).Select(x => x.Key) + .ToHashSet(); + foreach (var resourcePermissionGrant in resourcePermissionGrants) + { + var resourcePermission = resourcePermissions.FirstOrDefault(x => x.Name == resourcePermissionGrant.Name); + if (resourcePermission == null) + { + continue; + } + + if (!permissionGrants.Contains(resourcePermission.ManagementPermissionName)) + { + continue; + } + + result.Permissions.Add(new ResourcePermissionWithProdiverGrantInfoDto + { + Name = resourcePermissionGrant.Name, + DisplayName = resourcePermission?.DisplayName.Localize(StringLocalizerFactory), + Providers = resourcePermissionGrant.Providers.Select(x => x.Name).ToList(), + IsGranted = resourcePermissionGrant.IsGranted + }); + } + + return result; + } + + public virtual async Task UpdateResourceAsync(string resourceName, string resourceKey, UpdateResourcePermissionsDto input) + { + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + var permissionGrants = (await PermissionChecker.IsGrantedAsync(resourcePermissions + .Select(rp => rp.ManagementPermissionName!) + .Distinct().ToArray())).Result.Where(x => x.Value == PermissionGrantResult.Granted).Select(x => x.Key) + .ToHashSet(); + foreach (var resourcePermission in resourcePermissions) + { + if (!permissionGrants.Contains(resourcePermission.ManagementPermissionName)) + { + continue; + } + + var isGranted = !input.Permissions.IsNullOrEmpty() && input.Permissions.Any(p => p == resourcePermission.Name); + await ResourcePermissionManager.SetAsync(resourcePermission.Name, resourceName, resourceKey, input.ProviderName, input.ProviderKey, isGranted); + } + } + + public virtual async Task DeleteResourceAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + var resourcePermissions = await ResourcePermissionManager.GetAvailablePermissionsAsync(resourceName); + var permissionGrants = (await PermissionChecker.IsGrantedAsync(resourcePermissions + .Select(rp => rp.ManagementPermissionName!) + .Distinct().ToArray())).Result.Where(x => x.Value == PermissionGrantResult.Granted).Select(x => x.Key) + .ToHashSet(); + foreach (var resourcePermission in resourcePermissions) + { + if (!permissionGrants.Contains(resourcePermission.ManagementPermissionName)) + { + continue; + } + + await ResourcePermissionManager.DeleteAsync(resourcePermission.Name, resourceName, resourceKey, providerName, providerKey); + } + } + protected virtual async Task CheckProviderPolicy(string providerName) { var policyName = Options.ProviderPolicies.GetOrDefault(providerName); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor new file mode 100644 index 0000000000..bd12891063 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor @@ -0,0 +1,179 @@ +@using Blazorise.Components +@using Volo.Abp.BlazoriseUI.Components +@using Volo.Abp.PermissionManagement.Localization +@inherits Volo.Abp.AspNetCore.Components.AbpComponentBase +@inject AbpBlazorMessageLocalizerHelper LH + + + + + @L["ResourcePermissions"] - @ResourceDisplayName + + + + @if(HasAnyResourcePermission && HasAnyResourceProviderKeyLookupService) + { +
+ +
+ + + + + + + @L["Actions"] + + + + @L["Edit"] + + + @L["Delete"] + + + + + + + + @{ + + @context.ProviderName + + @context.ProviderDisplayName + } + + + + + @{ + foreach (var permission in context.Permissions) + { + @permission.DisplayName + } + } + + + + + @L["NoDataAvailableInDatatable"] + + + } + else + { + + } +
+ + + +
+
+ + + +
+ + @L["AddResourcePermission"] + + + + +
+ + @foreach(var keyLookupService in ResourceProviderKeyLookupServices) + { + @keyLookupService.DisplayName + } + + + + + + + + + + +
+
+

@L["ResourcePermissionPermissions"]

+ @L["GrantAllResourcePermissions"] +
+ @foreach (var permission in CreateEntity.Permissions) + { + @permission.DisplayName + } +
+
+
+
+ + + + +
+
+
+ + + +
+ + @L["UpdateResourcePermission"] + + + + +
+

@L["ResourcePermissionPermissions"]

+ @L["GrantAllResourcePermissions"] +
+ @foreach (var permission in EditEntity.Permissions) + { + @permission.DisplayName + } +
+
+
+
+ + + + +
+
+
diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor.cs new file mode 100644 index 0000000000..a69eacea3c --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/ResourcePermissionManagementModal.razor.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Blazorise; +using Blazorise.Components; +using Microsoft.AspNetCore.Components; +using Volo.Abp.AspNetCore.Components.Messages; +using Volo.Abp.PermissionManagement.Localization; + +namespace Volo.Abp.PermissionManagement.Blazor.Components; + +public partial class ResourcePermissionManagementModal +{ + [Inject] protected IPermissionAppService PermissionAppService { get; set; } + + [Inject] protected IUiMessageService UiMessageService { get; set; } + + protected Modal Modal { get; set; } + + public bool HasAnyResourcePermission { get; set; } + public bool HasAnyResourceProviderKeyLookupService { get; set; } + protected string ResourceName { get; set; } + protected string ResourceKey { get; set; } + protected string ResourceDisplayName { get; set; } + protected int PageSize { get; set; } = 10; + + protected Modal CreateModal { get; set; } + protected Validations CreateValidationsRef { get; set; } + protected CreateModel CreateEntity { get; set; } = new CreateModel + { + Permissions = [] + }; + protected Autocomplete ProviderKeyAutocompleteRef { get; set; } + protected Blazorise.Validation ProviderKeyValidationRef { get; set; } + public GetResourcePermissionDefinitionListResultDto ResourcePermissionDefinitions { get; set; } = new() + { + Permissions = [] + }; + protected string CurrentLookupService { get; set; } + protected string ProviderKey { get; set; } + protected string ProviderDisplayName { get; set; } + protected List ResourceProviderKeyLookupServices { get; set; } = new(); + protected List ProviderKeys { get; set; } = new(); + protected GetResourcePermissionListResultDto ResourcePermissionList = new() + { + Permissions = [] + }; + + protected Validations EditValidationsRef { get; set; } + protected Modal EditModal { get; set; } + protected EditModel EditEntity { get; set; } = new EditModel + { + Permissions = [] + }; + + public ResourcePermissionManagementModal() + { + LocalizationResource = typeof(AbpPermissionManagementResource); + } + + public virtual async Task OpenAsync(string resourceName, string resourceKey, string resourceDisplayName) + { + try + { + ResourceName = resourceName; + ResourceKey = resourceKey; + ResourceDisplayName = resourceDisplayName; + + ResourcePermissionDefinitions = await PermissionAppService.GetResourceDefinitionsAsync(ResourceName); + ResourceProviderKeyLookupServices = (await PermissionAppService.GetResourceProviderKeyLookupServicesAsync(ResourceName)).Providers; + + HasAnyResourcePermission = ResourcePermissionDefinitions.Permissions.Any(); + if (HasAnyResourcePermission) + { + HasAnyResourceProviderKeyLookupService = ResourceProviderKeyLookupServices.Count > 0; + } + + await InvokeAsync(StateHasChanged); + + ResourcePermissionList = await PermissionAppService.GetResourceAsync(ResourceName, ResourceKey); + + await Modal.Show(); + + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual async Task CloseModal() + { + await Modal.Hide(); + } + + protected virtual Task ClosingModal(ModalClosingEventArgs eventArgs) + { + eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; + return Task.CompletedTask; + } + + protected virtual async Task OpenCreateModalAsync() + { + CurrentLookupService = ResourceProviderKeyLookupServices.FirstOrDefault()?.Name; + + ProviderKey = null; + ProviderDisplayName = null; + ProviderKeys = new List(); + await ProviderKeyAutocompleteRef.Clear(); + await CreateValidationsRef.ClearAll(); + + CreateEntity = new CreateModel + { + Permissions = ResourcePermissionDefinitions.Permissions.Select(x => new ResourcePermissionModel + { + Name = x.Name, + DisplayName = x.DisplayName, + IsGranted = false + }).ToList() + }; + + await CreateModal.Show(); + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task SelectedProviderKeyAsync(string value) + { + ProviderKey = value; + ProviderDisplayName = ProviderKeys.FirstOrDefault(p => p.ProviderKey == value)?.ProviderDisplayName; + + var permissionGrants = await PermissionAppService.GetResourceByProviderAsync(ResourceName, ResourceKey, CurrentLookupService, ProviderKey); + foreach (var permission in CreateEntity.Permissions) + { + permission.IsGranted = permissionGrants.Permissions.Any(p => p.Name == permission.Name && p.Providers.Contains(CurrentLookupService) && p.IsGranted); + } + + await InvokeAsync(StateHasChanged); + } + + private async Task SearchProviderKeyAsync(AutocompleteReadDataEventArgs autocompleteReadDataEventArgs) + { + if ( !autocompleteReadDataEventArgs.CancellationToken.IsCancellationRequested ) + { + if (autocompleteReadDataEventArgs.SearchValue.IsNullOrWhiteSpace()) + { + ProviderKeys = new List(); + return; + } + + ProviderKeys = (await PermissionAppService.SearchResourceProviderKeyAsync(ResourceName, CurrentLookupService, autocompleteReadDataEventArgs.SearchValue, 1)).Keys; + + await InvokeAsync(StateHasChanged); + } + } + + protected virtual async Task OnPermissionCheckedChanged(ResourcePermissionModel permission, bool value) + { + permission.IsGranted = value; + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task GrantAllAsync(bool value) + { + foreach (var permission in CreateEntity.Permissions) + { + permission.IsGranted = value; + } + + foreach (var permission in EditEntity.Permissions) + { + permission.IsGranted = value; + } + + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task OpenEditModalAsync(ResourcePermissionGrantInfoDto permission) + { + var resourcePermissions = await PermissionAppService.GetResourceByProviderAsync(ResourceName, ResourceKey, permission.ProviderName, permission.ProviderKey); + EditEntity = new EditModel + { + ProviderName = permission.ProviderName, + ProviderKey = permission.ProviderKey, + Permissions = resourcePermissions.Permissions.Select(x => new ResourcePermissionModel + { + Name = x.Name, + DisplayName = x.DisplayName, + IsGranted = x.IsGranted + }).ToList() + }; + + await EditModal.Show(); + } + + protected virtual Task ClosingCreateModal(ModalClosingEventArgs eventArgs) + { + eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; + return Task.CompletedTask; + } + + protected virtual Task ClosingEditModal(ModalClosingEventArgs eventArgs) + { + eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; + return Task.CompletedTask; + } + + protected virtual async Task CloseCreateModalAsync() + { + await CreateModal.Hide(); + } + + protected virtual async Task CloseEditModalAsync() + { + await EditModal.Hide(); + } + + protected virtual async Task OnLookupServiceCheckedValueChanged(string value) + { + CurrentLookupService = value; + ProviderKey = null; + ProviderDisplayName = null; + await ProviderKeyAutocompleteRef.Clear(); + await CreateValidationsRef.ClearAll(); + await InvokeAsync(StateHasChanged); + } + + protected virtual void ValidateProviderKey(ValidatorEventArgs validatorEventArgs) + { + validatorEventArgs.Status = ProviderKey.IsNullOrWhiteSpace() + ? ValidationStatus.Error + : ValidationStatus.Success; + validatorEventArgs.ErrorText = L["ThisFieldIsRequired."]; + } + + protected virtual async Task CreateResourcePermissionAsync() + { + if (await CreateValidationsRef.ValidateAll()) + { + await PermissionAppService.UpdateResourceAsync( + ResourceName, + ResourceKey, + new UpdateResourcePermissionsDto + { + ProviderName = CurrentLookupService, + ProviderKey = ProviderKey, + Permissions = CreateEntity.Permissions.Where(p => p.IsGranted).Select(p => p.Name).ToList() + } + ); + + await CloseCreateModalAsync(); + ResourcePermissionList = await PermissionAppService.GetResourceAsync(ResourceName, ResourceKey); + await InvokeAsync(StateHasChanged); + } + } + + protected virtual async Task UpdateResourcePermissionAsync() + { + if (await EditValidationsRef.ValidateAll()) + { + await PermissionAppService.UpdateResourceAsync( + ResourceName, + ResourceKey, + new UpdateResourcePermissionsDto + { + ProviderName = EditEntity.ProviderName, + ProviderKey = EditEntity.ProviderKey, + Permissions = EditEntity.Permissions.Where(p => p.IsGranted).Select(p => p.Name).ToList() + } + ); + + await CloseEditModalAsync(); + ResourcePermissionList = await PermissionAppService.GetResourceAsync(ResourceName, ResourceKey); + await InvokeAsync(StateHasChanged); + } + } + + protected virtual async Task DeleteResourcePermissionAsync(ResourcePermissionGrantInfoDto permission) + { + if(await UiMessageService.Confirm(L["ResourcePermissionDeletionConfirmationMessage"])) + { + await PermissionAppService.DeleteResourceAsync( + ResourceName, + ResourceKey, + permission.ProviderName, + permission.ProviderKey + ); + + ResourcePermissionList = await PermissionAppService.GetResourceAsync(ResourceName, ResourceKey); + await Notify.Success(L["DeletedSuccessfully"]); + await InvokeAsync(StateHasChanged); + } + } + + public class CreateModel + { + public List Permissions { get; set; } + } + + public class EditModel + { + public string ProviderName { get; set; } + + public string ProviderKey { get; set; } + + public List Permissions { get; set; } + } + + public class ResourcePermissionModel + { + public string Name { get; set; } + + public string DisplayName { get; set; } + + public bool IsGranted { get; set; } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ar.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ar.json index 30f4b647e8..f234ef9068 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ar.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ar.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "تحديد الكل", "SaveWithoutAnyPermissionsWarningMessage": "هل أنت متأكد أنك تريد الحفظ بدون أي أذونات؟", "PermissionGroup": "مجموعة الأذونات", - "Filter": "تصفية" + "Filter": "تصفية", + "ResourcePermissions": "الأذونات", + "ResourcePermissionTarget": "الهدف", + "ResourcePermissionPermissions": "الأذونات", + "AddResourcePermission": "إضافة إذن", + "ResourcePermissionDeletionConfirmationMessage": "هل أنت متأكد أنك تريد حذف جميع الأذونات؟", + "UpdateResourcePermission": "تحديث الإذن", + "GrantAllResourcePermissions": "منح الكل", + "NoResourceProviderKeyLookupServiceFound": "لم يتم العثور على خدمة البحث عن مفتاح المزود", + "NoResourcePermissionFound": "لا توجد أي أذونات محددة." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json index 814b8e423c..2083a51da2 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/cs.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Vybrat vše", "SaveWithoutAnyPermissionsWarningMessage": "Opravdu chcete ukládat bez jakýchkoli oprávnění?", "PermissionGroup": "Skupina oprávnění", - "Filter": "Filtr" + "Filter": "Filtr", + "ResourcePermissions": "Oprávnění", + "ResourcePermissionTarget": "Cíl", + "ResourcePermissionPermissions": "Oprávnění", + "AddResourcePermission": "Přidat oprávnění", + "ResourcePermissionDeletionConfirmationMessage": "Opravdu chcete smazat všechna oprávnění?", + "UpdateResourcePermission": "Aktualizovat oprávnění", + "GrantAllResourcePermissions": "Udělit vše", + "NoResourceProviderKeyLookupServiceFound": "Nebyla nalezena služba pro vyhledávání klíče poskytovatele zdrojů", + "NoResourcePermissionFound": "Pro aktuální prostředek není definováno žádné oprávnění." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/de.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/de.json index 7a40c5d4d4..65fb5b83d6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/de.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/de.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Alle auswählen", "SaveWithoutAnyPermissionsWarningMessage": "Sind Sie sicher, dass Sie ohne Berechtigungen speichern möchten?", "PermissionGroup": "Berechtigungsgruppe", - "Filter": "Filtern" + "Filter": "Filtern", + "ResourcePermissions": "Berechtigungen", + "ResourcePermissionTarget": "Ziel", + "ResourcePermissionPermissions": "Berechtigungen", + "AddResourcePermission": "Berechtigung hinzufügen", + "ResourcePermissionDeletionConfirmationMessage": "Sind Sie sicher, dass Sie alle Berechtigungen löschen möchten?", + "UpdateResourcePermission": "Berechtigung aktualisieren", + "GrantAllResourcePermissions": "Alle gewähren", + "NoResourceProviderKeyLookupServiceFound": "Es wurde kein Dienst zum Nachschlagen des Anbieterschlüssels gefunden", + "NoResourcePermissionFound": "Es ist keine Berechtigung definiert." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/el.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/el.json index 3449b7fab6..125d64e5dc 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/el.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/el.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Επιλογή όλων", "SaveWithoutAnyPermissionsWarningMessage": "Είστε βέβαιοι ότι θέλετε να αποθηκεύσετε χωρίς δικαιώματα;", "PermissionGroup": "Ομάδα δικαιωμάτων", - "Filter": "Φίλτρο" + "Filter": "Φίλτρο", + "ResourcePermissions": "Δικαιώματα", + "ResourcePermissionTarget": "Στόχος", + "ResourcePermissionPermissions": "Δικαιώματα", + "AddResourcePermission": "Προσθήκη δικαιώματος", + "ResourcePermissionDeletionConfirmationMessage": "Είστε βέβαιοι ότι θέλετε να διαγράψετε όλα τα δικαιώματα;", + "UpdateResourcePermission": "Ενημέρωση δικαιώματος", + "GrantAllResourcePermissions": "Παραχώρηση όλων", + "NoResourceProviderKeyLookupServiceFound": "Δεν βρέθηκε υπηρεσία αναζήτησης κλειδιού παρόχου", + "NoResourcePermissionFound": "Δεν έχει οριστεί καμία άδεια." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en-GB.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en-GB.json index be6cbcd1f5..75d6509523 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en-GB.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en-GB.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Select all", "SaveWithoutAnyPermissionsWarningMessage": "Are you sure you want to save without any permissions?", "PermissionGroup": "Permission Group", - "Filter": "Filter" + "Filter": "Filter", + "ResourcePermissions": "Permissions", + "ResourcePermissionTarget": "Target", + "ResourcePermissionPermissions": "Permissions", + "AddResourcePermission": "Add permission", + "ResourcePermissionDeletionConfirmationMessage": "Are you sure you want to delete all permissions?", + "UpdateResourcePermission": "Update permission", + "GrantAllResourcePermissions": "Grant all", + "NoResourceProviderKeyLookupServiceFound": "There is no provider key lookup service was found", + "NoResourcePermissionFound": "There is no permission defined." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json index b8299d4e5b..f3dde4d6a6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Select all", "SaveWithoutAnyPermissionsWarningMessage": "Are you sure you want to save without any permissions?", "PermissionGroup": "Permission Group", - "Filter": "Filter" + "Filter": "Filter", + "ResourcePermissions": "Permissions", + "ResourcePermissionTarget": "Target", + "ResourcePermissionPermissions": "Permissions", + "AddResourcePermission": "Add permission", + "ResourcePermissionDeletionConfirmationMessage": "Are you sure you want to delete all permissions?", + "UpdateResourcePermission": "Update permission", + "GrantAllResourcePermissions": "Grant all", + "NoResourceProviderKeyLookupServiceFound": "There is no provider key lookup service was found", + "NoResourcePermissionFound": "There is no permission defined." } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/es.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/es.json index 622883b259..1007ca87ef 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/es.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/es.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Seleccionar todo", "SaveWithoutAnyPermissionsWarningMessage": "¿Estás seguro de que quieres guardar sin ningún permiso?", "PermissionGroup": "Grupo de permisos", - "Filter": "Filtrar" + "Filter": "Filtrar", + "ResourcePermissions": "Permisos", + "ResourcePermissionTarget": "Objetivo", + "ResourcePermissionPermissions": "Permisos", + "AddResourcePermission": "Agregar permiso", + "ResourcePermissionDeletionConfirmationMessage": "¿Está seguro de que desea eliminar todos los permisos?", + "UpdateResourcePermission": "Actualizar permiso", + "GrantAllResourcePermissions": "Conceder todos", + "NoResourceProviderKeyLookupServiceFound": "No se encontró ningún servicio de búsqueda de clave de proveedor", + "NoResourcePermissionFound": "No hay ningún permiso definido." } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fa.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fa.json index 7ea9a6c4f3..4d711f6542 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fa.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fa.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "انتخاب همه", "SaveWithoutAnyPermissionsWarningMessage": "آیا مطمئن هستید که می خواهید بدون هیچ دسترسی ذخیره کنید؟", "PermissionGroup": "گروه دسترسی", - "Filter": "فیلتر" + "Filter": "فیلتر", + "ResourcePermissions": "دسترسی‌ها", + "ResourcePermissionTarget": "هدف", + "ResourcePermissionPermissions": "دسترسی‌ها", + "AddResourcePermission": "افزودن مجوز", + "ResourcePermissionDeletionConfirmationMessage": "آیا مطمئن هستید که می‌خواهید همه مجوزها را حذف کنید؟", + "UpdateResourcePermission": "به‌روزرسانی مجوز", + "GrantAllResourcePermissions": "اعطای همه", + "NoResourceProviderKeyLookupServiceFound": "هیچ سرویس جستجوی کلید ارائه‌دهنده یافت نشد", + "NoResourcePermissionFound": "هیچ مجوزی تعریف نشده است." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json index f9b828ade4..02bd697c43 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fi.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Valitse kaikki", "SaveWithoutAnyPermissionsWarningMessage": "Haluatko varmasti tallentaa ilman käyttöoikeuksia?", "PermissionGroup": "Käyttöoikeus", - "Filter": "Suodatus" + "Filter": "Suodatus", + "ResourcePermissions": "Käyttöoikeudet", + "ResourcePermissionTarget": "Kohde", + "ResourcePermissionPermissions": "Käyttöoikeudet", + "AddResourcePermission": "Lisää käyttöoikeus", + "ResourcePermissionDeletionConfirmationMessage": "Haluatko varmasti poistaa kaikki käyttöoikeudet?", + "UpdateResourcePermission": "Päivitä käyttöoikeus", + "GrantAllResourcePermissions": "Myönnä kaikki", + "NoResourceProviderKeyLookupServiceFound": "Palveluntarjoajan avaimen hakupalvelua ei löytynyt", + "NoResourcePermissionFound": "Ei käyttöoikeuksia määritetty." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fr.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fr.json index 79f4e68377..d019936494 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fr.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/fr.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Sélectionner tous les", "SaveWithoutAnyPermissionsWarningMessage": "Êtes-vous sûr de vouloir enregistrer sans aucune autorisation ?", "PermissionGroup": "Groupe d'autorisations", - "Filter": "Filtrer" + "Filter": "Filtrer", + "ResourcePermissions": "Autorisations", + "ResourcePermissionTarget": "Cible", + "ResourcePermissionPermissions": "Autorisations", + "AddResourcePermission": "Ajouter une autorisation", + "ResourcePermissionDeletionConfirmationMessage": "Êtes-vous sûr de vouloir supprimer toutes les autorisations ?", + "UpdateResourcePermission": "Mettre à jour l'autorisation", + "GrantAllResourcePermissions": "Accorder tout", + "NoResourceProviderKeyLookupServiceFound": "Aucun service de recherche de clé de fournisseur n'a été trouvé", + "NoResourcePermissionFound": "Aucune autorisation n'est définie." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hi.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hi.json index cdc030e8ef..141be77ce5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hi.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hi.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "सभी का चयन करे", "SaveWithoutAnyPermissionsWarningMessage": "क्या आप वाकई बिना किसी अनुमति के सहेजना चाहते हैं?", "PermissionGroup": "अनुमति समूह", - "Filter": "फ़िल्टर" + "Filter": "फ़िल्टर", + "ResourcePermissions": "अनुमतियाँ", + "ResourcePermissionTarget": "लक्ष्य", + "ResourcePermissionPermissions": "अनुमतियाँ", + "AddResourcePermission": "अनुमति जोड़ें", + "ResourcePermissionDeletionConfirmationMessage": "क्या आप वाकई सभी अनुमतियां हटाना चाहते हैं?", + "UpdateResourcePermission": "अनुमति अपडेट करें", + "GrantAllResourcePermissions": "सभी प्रदान करें", + "NoResourceProviderKeyLookupServiceFound": "कोई प्रदाता कुंजी खोज सेवा नहीं मिली", + "NoResourcePermissionFound": "कोई अनुमति परिभाषित नहीं है।" } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hr.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hr.json index 531d0a35d2..fb7129a678 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hr.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hr.json @@ -1,13 +1,22 @@ { - "culture": "hr", - "texts": { - "Permissions": "Dozvole", - "OnlyProviderPermissons": "Samo ovaj pružatelj usluga", - "All": "Svi", - "SelectAllInAllTabs": "Dodijelite sva dopuštenja", - "SelectAllInThisTab": "Odaberi sve", - "SaveWithoutAnyPermissionsWarningMessage": "Jeste li sigurni da želite spremiti bez ikakvih dopuštenja?", - "PermissionGroup": "Grupa dozvola", - "Filter": "Filtriraj" - } + "culture": "hr", + "texts": { + "Permissions": "Dozvole", + "OnlyProviderPermissons": "Samo ovaj pružatelj usluga", + "All": "Svi", + "SelectAllInAllTabs": "Dodijelite sva dopuštenja", + "SelectAllInThisTab": "Odaberi sve", + "SaveWithoutAnyPermissionsWarningMessage": "Jeste li sigurni da želite spremiti bez ikakvih dopuštenja?", + "PermissionGroup": "Grupa dozvola", + "Filter": "Filtriraj", + "ResourcePermissions": "Dozvole", + "ResourcePermissionTarget": "Cilj", + "ResourcePermissionPermissions": "Dozvole", + "AddResourcePermission": "Dodaj dozvolu", + "ResourcePermissionDeletionConfirmationMessage": "Jeste li sigurni da želite izbrisati sve dozvole?", + "UpdateResourcePermission": "Ažuriraj dozvolu", + "GrantAllResourcePermissions": "Dodijeli sve", + "NoResourceProviderKeyLookupServiceFound": "Nije pronađena usluga za pronalaženje ključa pružatelja", + "NoResourcePermissionFound": "Nijedna dozvola nije definirana." + } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hu.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hu.json index 3177ef8fa7..9ef8822f63 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hu.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/hu.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Mindet kiválaszt", "SaveWithoutAnyPermissionsWarningMessage": "Biztos, hogy engedélyek nélkül akar menteni?", "PermissionGroup": "Engedélycsoport", - "Filter": "Szűrő" + "Filter": "Szűrő", + "ResourcePermissions": "Engedélyek", + "ResourcePermissionTarget": "Cél", + "ResourcePermissionPermissions": "Engedélyek", + "AddResourcePermission": "Engedély hozzáadása", + "ResourcePermissionDeletionConfirmationMessage": "Biztosan törölni szeretné az összes engedélyt?", + "UpdateResourcePermission": "Engedély frissítése", + "GrantAllResourcePermissions": "Összes engedély megadása", + "NoResourceProviderKeyLookupServiceFound": "Nem található szolgáltató kulcs kereső szolgáltatás", + "NoResourcePermissionFound": "Nincs meghatározva engedély." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/is.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/is.json index 7db32eb99e..0510d8a1b8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/is.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/is.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Velja allt", "SaveWithoutAnyPermissionsWarningMessage": "Ertu viss um að þú viljir vista án nokkurra heimilda?", "PermissionGroup": "Heimildahópur", - "Filter": "Sía" + "Filter": "Sía", + "ResourcePermissions": "Heimildir", + "ResourcePermissionTarget": "Markmið", + "ResourcePermissionPermissions": "Heimildir", + "AddResourcePermission": "Bæta við heimild", + "ResourcePermissionDeletionConfirmationMessage": "Ertu viss um að þú viljir eyða öllum heimildum?", + "UpdateResourcePermission": "Uppfæra heimild", + "GrantAllResourcePermissions": "Veita allt", + "NoResourceProviderKeyLookupServiceFound": "Engin þjónusta fannst til að leita að lykli veitanda", + "NoResourcePermissionFound": "Engin heimild er skilgreind." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/it.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/it.json index e473c7b310..644eae25ee 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/it.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/it.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Seleziona tutto", "SaveWithoutAnyPermissionsWarningMessage": "Sei sicuro di voler salvare senza alcuna autorizzazione?", "PermissionGroup": "Gruppo di autorizzazioni", - "Filter": "Filtro" + "Filter": "Filtro", + "ResourcePermissions": "Autorizzazioni", + "ResourcePermissionTarget": "Obiettivo", + "ResourcePermissionPermissions": "Autorizzazioni", + "AddResourcePermission": "Aggiungi autorizzazione", + "ResourcePermissionDeletionConfirmationMessage": "Sei sicuro di voler eliminare tutte le autorizzazioni?", + "UpdateResourcePermission": "Aggiorna autorizzazione", + "GrantAllResourcePermissions": "Concedi tutto", + "NoResourceProviderKeyLookupServiceFound": "Non è stato trovato alcun servizio di ricerca chiave del provider", + "NoResourcePermissionFound": "Non è definita alcuna autorizzazione." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/nl.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/nl.json index 4b928c4d03..b9af1b227b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/nl.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/nl.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Selecteer alles", "SaveWithoutAnyPermissionsWarningMessage": "Weet u zeker dat u zonder rechten wilt opslaan?", "PermissionGroup": "Rechtengroep", - "Filter": "Filter" + "Filter": "Filter", + "ResourcePermissions": "Rechten", + "ResourcePermissionTarget": "Doel", + "ResourcePermissionPermissions": "Rechten", + "AddResourcePermission": "Recht toevoegen", + "ResourcePermissionDeletionConfirmationMessage": "Weet u zeker dat u alle rechten wilt verwijderen?", + "UpdateResourcePermission": "Recht bijwerken", + "GrantAllResourcePermissions": "Alles toekennen", + "NoResourceProviderKeyLookupServiceFound": "Er is geen service gevonden voor het opzoeken van de sleutel van de provider", + "NoResourcePermissionFound": "Er is geen machtiging gedefinieerd." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pl-PL.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pl-PL.json index ee483651eb..9ba0bd5690 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pl-PL.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pl-PL.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Zaznacz wszystkie", "SaveWithoutAnyPermissionsWarningMessage": "Czy na pewno chcesz zapisać bez żadnych uprawnień?", "PermissionGroup": "Grupa uprawnień", - "Filter": "Filtr" + "Filter": "Filtr", + "ResourcePermissions": "Uprawnienia", + "ResourcePermissionTarget": "Cel", + "ResourcePermissionPermissions": "Uprawnienia", + "AddResourcePermission": "Dodaj uprawnienie", + "ResourcePermissionDeletionConfirmationMessage": "Czy na pewno chcesz usunąć wszystkie uprawnienia?", + "UpdateResourcePermission": "Zaktualizuj uprawnienie", + "GrantAllResourcePermissions": "Przyznaj wszystko", + "NoResourceProviderKeyLookupServiceFound": "Nie znaleziono usługi wyszukiwania klucza dostawcy", + "NoResourcePermissionFound": "Nie zdefiniowano żadnych uprawnień." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pt-BR.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pt-BR.json index 28231b227f..d9ceca3317 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pt-BR.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/pt-BR.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Selecionar todos", "SaveWithoutAnyPermissionsWarningMessage": "Tem certeza que deseja salvar sem nenhuma permissão?", "PermissionGroup": "Grupo de permissão", - "Filter": "Filtrar" + "Filter": "Filtrar", + "ResourcePermissions": "Permissões", + "ResourcePermissionTarget": "Alvo", + "ResourcePermissionPermissions": "Permissões", + "AddResourcePermission": "Adicionar permissão", + "ResourcePermissionDeletionConfirmationMessage": "Tem certeza de que deseja excluir todas as permissões?", + "UpdateResourcePermission": "Atualizar permissão", + "GrantAllResourcePermissions": "Conceder tudo", + "NoResourceProviderKeyLookupServiceFound": "Nenhum serviço de pesquisa de chave do provedor foi encontrado", + "NoResourcePermissionFound": "Nenhuma permissão foi definida." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ro-RO.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ro-RO.json index af7db26acb..25553f693b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ro-RO.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ro-RO.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Selectează toate", "SaveWithoutAnyPermissionsWarningMessage": "Sigur doriți să salvați fără nicio permisiune?", "PermissionGroup": "Grup de permisiuni", - "Filter": "Filtru" + "Filter": "Filtru", + "ResourcePermissions": "Permisiuni", + "ResourcePermissionTarget": "Țintă", + "ResourcePermissionPermissions": "Permisiuni", + "AddResourcePermission": "Adăugați permisiune", + "ResourcePermissionDeletionConfirmationMessage": "Sigur doriți să ștergeți toate permisiunile?", + "UpdateResourcePermission": "Actualizați permisiunea", + "GrantAllResourcePermissions": "Acordați toate", + "NoResourceProviderKeyLookupServiceFound": "Nu a fost găsit niciun serviciu de căutare a cheii furnizorului", + "NoResourcePermissionFound": "Nu există nicio permisiune definită." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ru.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ru.json index 6041357b0e..409460e2dd 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ru.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/ru.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Выбрать все", "SaveWithoutAnyPermissionsWarningMessage": "Вы уверены, что хотите сохранить без каких-либо разрешений?", "PermissionGroup": "Группа разрешений", - "Filter": "Фильтр" + "Filter": "Фильтр", + "ResourcePermissions": "Разрешения", + "ResourcePermissionTarget": "Цель", + "ResourcePermissionPermissions": "Разрешения", + "AddResourcePermission": "Добавить разрешение", + "ResourcePermissionDeletionConfirmationMessage": "Вы уверены, что хотите удалить все разрешения?", + "UpdateResourcePermission": "Обновить разрешение", + "GrantAllResourcePermissions": "Предоставить все", + "NoResourceProviderKeyLookupServiceFound": "Служба поиска ключа поставщика не найдена", + "NoResourcePermissionFound": "Не определено ни одного разрешения." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sk.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sk.json index c079b8eba1..09394f87a9 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sk.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sk.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Vybrať všetky", "SaveWithoutAnyPermissionsWarningMessage": "Naozaj chcete ukladať bez akýchkoľvek povolení?", "PermissionGroup": "Skupina oprávnení", - "Filter": "Filtrovať" + "Filter": "Filtrovať", + "ResourcePermissions": "Oprávnenia", + "ResourcePermissionTarget": "Cieľ", + "ResourcePermissionPermissions": "Oprávnenia", + "AddResourcePermission": "Pridať oprávnenie", + "ResourcePermissionDeletionConfirmationMessage": "Naozaj chcete odstrániť všetky oprávnenia?", + "UpdateResourcePermission": "Aktualizovať oprávnenie", + "GrantAllResourcePermissions": "Udeľ všetko", + "NoResourceProviderKeyLookupServiceFound": "Nebola nájdená služba na vyhľadávanie kľúča poskytovateľa", + "NoResourcePermissionFound": "Nie je definované žiadne povolenie." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sl.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sl.json index 9c906f7387..60ee9af67a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sl.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sl.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Izberi vse", "SaveWithoutAnyPermissionsWarningMessage": "Ali ste prepričani, da želite shraniti brez kakršnih koli dovoljenj?", "PermissionGroup": "Skupina dovoljenj", - "Filter": "Filtriraj" + "Filter": "Filtriraj", + "ResourcePermissions": "Dovoljenja", + "ResourcePermissionTarget": "Cilj", + "ResourcePermissionPermissions": "Dovoljenja", + "AddResourcePermission": "Dodaj dovoljenje", + "ResourcePermissionDeletionConfirmationMessage": "Ali ste prepričani, da želite izbrisati vsa dovoljenja?", + "UpdateResourcePermission": "Posodobi dovoljenje", + "GrantAllResourcePermissions": "Dodeli vse", + "NoResourceProviderKeyLookupServiceFound": "Ni bilo mogoče najti storitve za iskanje ključa ponudnika", + "NoResourcePermissionFound": "Nobeno dovoljenje ni določeno." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sv.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sv.json index d46fca4dc4..a5c1260438 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sv.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/sv.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Välj alla", "SaveWithoutAnyPermissionsWarningMessage": "Är du säker på att du vill spara utan några behörigheter?", "PermissionGroup": "Behörighetsgrupp", - "Filter": "Filtrera" + "Filter": "Filtrera", + "ResourcePermissions": "Behörigheter", + "ResourcePermissionTarget": "Mål", + "ResourcePermissionPermissions": "Behörigheter", + "AddResourcePermission": "Lägg till behörighet", + "ResourcePermissionDeletionConfirmationMessage": "Är du säker på att du vill ta bort alla behörigheter?", + "UpdateResourcePermission": "Uppdatera behörighet", + "GrantAllResourcePermissions": "Bevilja alla", + "NoResourceProviderKeyLookupServiceFound": "Ingen tjänst för att söka efter leverantörsnyckel hittades", + "NoResourcePermissionFound": "Ingen behörighet är definierad." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/tr.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/tr.json index 960cd8cf02..b96baa2383 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/tr.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/tr.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Hepsini seç", "SaveWithoutAnyPermissionsWarningMessage": "Hiçbir izin olmadan kaydetmek istediğinize emin misiniz?", "PermissionGroup": "İzin Grubu", - "Filter": "Filtre" + "Filter": "Filtre", + "ResourcePermissions": "İzinler", + "ResourcePermissionTarget": "Hedef", + "ResourcePermissionPermissions": "İzinler", + "AddResourcePermission": "İzin ekle", + "ResourcePermissionDeletionConfirmationMessage": "Tüm izinleri silmek istediğinizden emin misiniz?", + "UpdateResourcePermission": "İzni güncelle", + "GrantAllResourcePermissions": "Tümünü ver", + "NoResourceProviderKeyLookupServiceFound": "Herhangi bir sağlayıcı anahtar arama hizmeti bulunamadı", + "NoResourcePermissionFound": "Herhangi bir izin tanımlı değil." } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/vi.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/vi.json index 5e9a9d8565..2a5aca86e1 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/vi.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/vi.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "Chọn tất cả", "SaveWithoutAnyPermissionsWarningMessage": "Bạn có chắc chắn muốn lưu mà không có bất kỳ quyền nào không?", "PermissionGroup": "Nhóm quyền", - "Filter": "Lọc" + "Filter": "Lọc", + "ResourcePermissions": "Quyền", + "ResourcePermissionTarget": "Mục tiêu", + "ResourcePermissionPermissions": "Quyền", + "AddResourcePermission": "Thêm quyền", + "ResourcePermissionDeletionConfirmationMessage": "Bạn có chắc chắn muốn xóa tất cả quyền không?", + "UpdateResourcePermission": "Cập nhật quyền", + "GrantAllResourcePermissions": "Cấp tất cả", + "NoResourceProviderKeyLookupServiceFound": "Không tìm thấy dịch vụ tra cứu khóa nhà cung cấp", + "NoResourcePermissionFound": "Không có quyền nào được định nghĩa." } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hans.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hans.json index df844ca2bf..bbd53f9606 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hans.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hans.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "全选", "SaveWithoutAnyPermissionsWarningMessage": "您确定要在没有任何权限的情况下保存吗?", "PermissionGroup": "权限组", - "Filter": "过滤" + "Filter": "过滤", + "ResourcePermissions": "权限", + "ResourcePermissionTarget": "目标", + "ResourcePermissionPermissions": "权限", + "AddResourcePermission": "添加权限", + "ResourcePermissionDeletionConfirmationMessage": "您确定要删除所有权限吗?", + "UpdateResourcePermission": "更新权限", + "GrantAllResourcePermissions": "授予所有", + "NoResourceProviderKeyLookupServiceFound": "未找到提供者键查找服务", + "NoResourcePermissionFound": "未定义任何权限。" } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json index 72af56c960..c081c54f20 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/zh-Hant.json @@ -8,6 +8,15 @@ "SelectAllInThisTab": "全選", "SaveWithoutAnyPermissionsWarningMessage": "您確定要在沒有任何權限的情況下保存嗎?", "PermissionGroup": "權限組", - "Filter": "過濾" + "Filter": "過濾", + "ResourcePermissions": "權限", + "ResourcePermissionTarget": "目標", + "ResourcePermissionPermissions": "權限", + "AddResourcePermission": "添加權限", + "ResourcePermissionDeletionConfirmationMessage": "您確定要刪除所有權限嗎?", + "UpdateResourcePermission": "更新權限", + "GrantAllResourcePermissions": "授予所有", + "NoResourceProviderKeyLookupServiceFound": "未找到提供者鍵查找服務", + "NoResourcePermissionFound": "未定義任何權限。" } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs index 93b1b465c6..0aadef7940 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs @@ -6,10 +6,14 @@ public class PermissionDefinitionRecordConsts /// Default value: 128 ///
public static int MaxNameLength { get; set; } = 128; - + public static int MaxDisplayNameLength { get; set; } = 256; public static int MaxProvidersLength { get; set; } = 128; - + public static int MaxStateCheckersLength { get; set; } = 256; -} \ No newline at end of file + + public static int MaxResourceNameLength { get; set; } = 256; + + public static int MaxManagementPermissionNameLength { get; set; } = 128; +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs index 630f5dc72e..d1008bcbdb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs @@ -11,4 +11,14 @@ public static class PermissionGrantConsts /// Default value: 64 ///
public static int MaxProviderKeyLength { get; set; } = 64; + + /// + /// Default value: 256 + /// + public static int MaxResourceNameLength { get; set; } = 256; + + /// + /// Default value: 256 + /// + public static int MaxResourceKeyLength { get; set; } = 256; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index f2e73cefc0..ff525ab263 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -23,7 +23,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor protected IAbpDistributedLock DistributedLock { get; } public PermissionManagementOptions PermissionManagementOptions { get; } protected AbpDistributedCacheOptions CacheOptions { get; } - + public DynamicPermissionDefinitionStore( IPermissionGroupDefinitionRecordRepository permissionGroupRepository, IPermissionDefinitionRecordRepository permissionRepository, @@ -72,6 +72,34 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor } } + public virtual async Task GetResourcePermissionOrNullAsync(string resourceName, string name) + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return null; + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetResourcePermissionOrNull(resourceName, name); + } + } + + public virtual async Task> GetResourcePermissionsAsync() + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetResourcePermissions().ToImmutableList(); + } + } + public virtual async Task> GetGroupsAsync() { if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) @@ -94,9 +122,9 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor /* We get the latest permission with a small delay for optimization */ return; } - + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); - + if (stampInDistributedCache == StoreCache.CacheStamp) { StoreCache.LastCheckTime = DateTime.Now; @@ -145,7 +173,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor } stampInDistributedCache = Guid.NewGuid().ToString(); - + await DistributedCache.SetStringAsync( cacheKey, stampInDistributedCache, @@ -163,9 +191,9 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor { return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; } - + protected virtual string GetCommonDistributedLockKey() { return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index 1040ea84a0..15a98c84dd 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -18,6 +18,7 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : protected IDictionary PermissionGroupDefinitions { get; } protected IDictionary PermissionDefinitions { get; } + protected IList ResourcePermissionDefinitions { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } protected ILocalizableStringSerializer LocalizableStringSerializer { get; } @@ -34,6 +35,7 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : PermissionGroupDefinitions = new Dictionary(); PermissionDefinitions = new Dictionary(); + ResourcePermissionDefinitions = new List(); } public Task FillAsync( @@ -42,9 +44,22 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : { PermissionGroupDefinitions.Clear(); PermissionDefinitions.Clear(); + ResourcePermissionDefinitions.Clear(); var context = new PermissionDefinitionContext(null); + var resourcePermissions = permissionRecords.Where(x => !x.ResourceName.IsNullOrWhiteSpace()); + foreach (var resourcePermission in resourcePermissions) + { + context.AddResourcePermission(resourcePermission.Name, + resourcePermission.ResourceName, + resourcePermission.ManagementPermissionName, + resourcePermission.DisplayName != null ? LocalizableStringSerializer.Deserialize(resourcePermission.DisplayName) : null, + resourcePermission.MultiTenancySide, + resourcePermission.IsEnabled); + } + + var permissions = permissionRecords.Where(x => x.ResourceName.IsNullOrWhiteSpace()).ToList(); foreach (var permissionGroupRecord in permissionGroupRecords) { var permissionGroup = context.AddGroup( @@ -59,12 +74,12 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : permissionGroup[property.Key] = property.Value; } - var permissionRecordsInThisGroup = permissionRecords + var permissionRecordsInThisGroup = permissions .Where(p => p.GroupName == permissionGroup.Name); foreach (var permissionRecord in permissionRecordsInThisGroup.Where(x => x.ParentName == null)) { - AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords); + AddPermissionRecursively(permissionGroup, permissionRecord, permissions); } } @@ -86,6 +101,16 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : return PermissionGroupDefinitions.Values.ToList(); } + public PermissionDefinition GetResourcePermissionOrNull(string resourceName, string name) + { + return ResourcePermissionDefinitions.FirstOrDefault(p => p.ResourceName == resourceName && p.Name == name); + } + + public IReadOnlyList GetResourcePermissions() + { + return ResourcePermissionDefinitions.ToList(); + } + private void AddPermissionRecursively(ICanAddChildPermission permissionContainer, PermissionDefinitionRecord permissionRecord, List allPermissionRecords) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs index 2dab588ebd..eb079f6c76 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs @@ -9,9 +9,9 @@ namespace Volo.Abp.PermissionManagement; public interface IDynamicPermissionDefinitionStoreInMemoryCache { string CacheStamp { get; set; } - + SemaphoreSlim SyncSemaphore { get; } - + DateTime? LastCheckTime { get; set; } Task FillAsync( @@ -19,8 +19,12 @@ public interface IDynamicPermissionDefinitionStoreInMemoryCache List permissionRecords); PermissionDefinition GetPermissionOrNull(string name); - + IReadOnlyList GetPermissions(); - + IReadOnlyList GetGroups(); -} \ No newline at end of file + + PermissionDefinition GetResourcePermissionOrNull(string resourceName, string name); + + IReadOnlyList GetResourcePermissions(); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs index 8ed09a4380..3c5f4a8783 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -10,10 +10,13 @@ public interface IPermissionDefinitionSerializer Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> SerializeAsync(IEnumerable permissionGroups); + Task SerializeAsync( + IEnumerable permissions); + Task SerializeAsync( PermissionGroupDefinition permissionGroup); Task SerializeAsync( PermissionDefinition permission, [CanBeNull] PermissionGroupDefinition permissionGroup); -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs index 7ec69ad100..ffb934321b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionManager.cs @@ -4,19 +4,39 @@ using JetBrains.Annotations; namespace Volo.Abp.PermissionManagement; -//TODO: Write extension methods for simple IsGranted check - public interface IPermissionManager { - Task GetAsync(string permissionName, string providerName, string providerKey); - - Task GetAsync(string[] permissionNames, string provideName, string providerKey); - - Task> GetAllAsync([NotNull] string providerName, [NotNull] string providerKey); - - Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted); - - Task UpdateProviderKeyAsync(PermissionGrant permissionGrant, string providerKey); - - Task DeleteAsync(string providerName, string providerKey); -} + Task GetAsync( + string permissionName, + string providerName, + string providerKey + ); + + Task GetAsync( + string[] permissionNames, + string provideName, + string providerKey + ); + + Task> GetAllAsync( + [NotNull] string providerName, + [NotNull] string providerKey + ); + + Task SetAsync( + string permissionName, + string providerName, + string providerKey, + bool isGranted + ); + + Task UpdateProviderKeyAsync( + PermissionGrant permissionGrant, + string providerKey + ); + + Task DeleteAsync( + string providerName, + string providerKey + ); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionGrantRepository.cs new file mode 100644 index 0000000000..82060c7ea7 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionGrantRepository.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public interface IResourcePermissionGrantRepository : IBasicRepository +{ + Task FindAsync( + string name, + string resourceName, + string resourceKey, + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); + + Task> GetListAsync( + string resourceName, + string resourceKey, + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); + + Task> GetListAsync( + string[] names, + string resourceName, + string resourceKey, + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); + + Task> GetListAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); + + Task> GetPermissionsAsync( + string resourceName, + string resourceKey, + CancellationToken cancellationToken = default + ); + + Task> GetResourceKeys( + string resourceName, + string name, + CancellationToken cancellationToken = default + ); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..429e6f6e85 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.PermissionManagement; + +public interface IResourcePermissionManagementProvider : ISingletonDependency //TODO: Consider to remove this pre-assumption +{ + string Name { get; } + + Task CheckAsync( + [NotNull] string name, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerName, + [NotNull] string providerKey + ); + + Task CheckAsync( + [NotNull] string[] names, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerName, + [NotNull] string providerKey + ); + + Task SetAsync( + [NotNull] string name, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerKey, + bool isGranted + ); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs new file mode 100644 index 0000000000..5bd2d143ca --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IResourcePermissionManager +{ + Task> GetProviderKeyLookupServicesAsync(); + + Task GetProviderKeyLookupServiceAsync(string providerName); + + Task> GetAvailablePermissionsAsync(string resourceName); + + Task GetAsync( + string permissionName, + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + Task GetAsync( + string[] permissionNames, + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + Task> GetAllAsync( + string resourceName, + string resourceKey + ); + + Task> GetAllAsync( + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + Task> GetAllGroupAsync( + string resourceName, + string resourceKey + ); + + Task SetAsync( + string permissionName, + string resourceName, + string resourceKey, + string providerName, + string providerKey, + bool isGranted + ); + + Task UpdateProviderKeyAsync( + ResourcePermissionGrant resourcePermissionGrant, + string providerKey + ); + + Task DeleteAsync( + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + Task DeleteAsync( + string name, + string resourceName, + string resourceKey, + string providerName, + string providerKey + ); + + Task DeleteAsync( + string providerName, + string providerKey + ); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionProviderKeyLookupService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionProviderKeyLookupService.cs new file mode 100644 index 0000000000..aa6ad2a06e --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionProviderKeyLookupService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace Volo.Abp.PermissionManagement; + +public interface IResourcePermissionProviderKeyLookupService +{ + public string Name { get; } + + public ILocalizableString DisplayName { get; } + + Task> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default); + + Task> SearchAsync(string[] keys, CancellationToken cancellationToken = default); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/MultipleResourcePermissionValueProviderGrantInfo.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/MultipleResourcePermissionValueProviderGrantInfo.cs new file mode 100644 index 0000000000..4ff1790488 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/MultipleResourcePermissionValueProviderGrantInfo.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace Volo.Abp.PermissionManagement; + +public class MultipleResourcePermissionValueProviderGrantInfo +{ + public Dictionary Result { get; } + + public MultipleResourcePermissionValueProviderGrantInfo() + { + Result = new Dictionary(); + } + + public MultipleResourcePermissionValueProviderGrantInfo(string[] names) + { + Check.NotNull(names, nameof(names)); + + Result = new Dictionary(); + + foreach (var name in names) + { + Result.Add(name, ResourcePermissionValueProviderGrantInfo.NonGranted); + } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index 7473eb2589..61a6ba1f14 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -1,4 +1,5 @@ using System; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; @@ -11,6 +12,10 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro public string Name { get; set; } + public string ResourceName { get; set; } + + public string ManagementPermissionName { get; set; } + public string ParentName { get; set; } public string DisplayName { get; set; } @@ -41,6 +46,8 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro Guid id, string groupName, string name, + string resourceName, + string managementPermissionName, string parentName, string displayName, bool isEnabled = true, @@ -49,8 +56,14 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro string stateCheckers = null) : base(id) { - GroupName = Check.NotNullOrWhiteSpace(groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength); + GroupName = groupName; + if (resourceName == null) + { + GroupName = Check.NotNullOrWhiteSpace(groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength); + } Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionDefinitionRecordConsts.MaxNameLength); + ResourceName = resourceName; + ManagementPermissionName = managementPermissionName; ParentName = Check.Length(parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength); DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionDefinitionRecordConsts.MaxDisplayNameLength); IsEnabled = isEnabled; @@ -69,6 +82,16 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro return false; } + if (ResourceName != otherRecord.ResourceName) + { + return false; + } + + if (ManagementPermissionName != otherRecord.ManagementPermissionName) + { + return false; + } + if (GroupName != otherRecord.GroupName) { return false; @@ -119,6 +142,16 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro Name = otherRecord.Name; } + if (ResourceName != otherRecord.ResourceName) + { + ResourceName = otherRecord.ResourceName; + } + + if (ManagementPermissionName != otherRecord.ManagementPermissionName) + { + ManagementPermissionName = otherRecord.ManagementPermissionName; + } + if (GroupName != otherRecord.GroupName) { GroupName = otherRecord.GroupName; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index 8e63342502..707a3e89ea 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -19,7 +19,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I public PermissionDefinitionSerializer( IGuidGenerator guidGenerator, - ISimpleStateCheckerSerializer stateCheckerSerializer, + ISimpleStateCheckerSerializer stateCheckerSerializer, ILocalizableStringSerializer localizableStringSerializer) { StateCheckerSerializer = stateCheckerSerializer; @@ -27,16 +27,16 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I GuidGenerator = guidGenerator; } - public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + public virtual async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> SerializeAsync(IEnumerable permissionGroups) { var permissionGroupRecords = new List(); var permissionRecords = new List(); - + foreach (var permissionGroup in permissionGroups) { permissionGroupRecords.Add(await SerializeAsync(permissionGroup)); - + foreach (var permission in permissionGroup.GetPermissionsWithChildren()) { permissionRecords.Add(await SerializeAsync(permission, permissionGroup)); @@ -45,8 +45,19 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); } - - public Task SerializeAsync(PermissionGroupDefinition permissionGroup) + + public virtual async Task SerializeAsync(IEnumerable permissions) + { + var permissionRecords = new List(); + foreach (var permission in permissions) + { + permissionRecords.Add(await SerializeAsync(permission, null)); + } + + return permissionRecords.ToArray(); + } + + public virtual Task SerializeAsync(PermissionGroupDefinition permissionGroup) { using (CultureHelper.Use(CultureInfo.InvariantCulture)) { @@ -60,12 +71,12 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I { permissionGroupRecord.SetProperty(property.Key, property.Value); } - + return Task.FromResult(permissionGroupRecord); } } - - public Task SerializeAsync( + + public virtual Task SerializeAsync( PermissionDefinition permission, PermissionGroupDefinition permissionGroup) { @@ -75,6 +86,8 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I GuidGenerator.Create(), permissionGroup?.Name, permission.Name, + permission.ResourceName, + permission.ManagementPermissionName, permission.Parent?.Name, LocalizableStringSerializer.Serialize(permission.DisplayName), permission.IsEnabled, @@ -87,11 +100,11 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I { permissionRecord.SetProperty(property.Key, property.Value); } - + return Task.FromResult(permissionRecord); } } - + protected virtual string SerializeProviders(ICollection providers) { return providers.Any() @@ -103,4 +116,4 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I { return StateCheckerSerializer.Serialize(stateCheckers); } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 489ae26e3d..2971cc18ae 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -9,6 +9,10 @@ public class PermissionManagementOptions public Dictionary ProviderPolicies { get; } + public ITypeList ResourceManagementProviders { get; } + + public ITypeList ResourcePermissionProviderKeyLookupServices { get; } + /// /// Default: true. /// @@ -23,5 +27,8 @@ public class PermissionManagementOptions { ManagementProviders = new TypeList(); ProviderPolicies = new Dictionary(); + + ResourceManagementProviders = new TypeList(); + ResourcePermissionProviderKeyLookupServices = new TypeList(); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionProviderWithPermissions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionProviderWithPermissions.cs new file mode 100644 index 0000000000..a6507ef0bc --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionProviderWithPermissions.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionProviderWithPermissions +{ + public string ProviderName { get; set; } + + public string ProviderKey { get; set; } + + public string ProviderDisplayName { get; set; } + + public ILocalizableString ProviderNameDisplayName { get; set; } + + public List Permissions { get; set; } + + public PermissionProviderWithPermissions(string providerName, string providerKey, string providerDisplayName) + { + ProviderName = providerName; + ProviderKey = providerKey; + ProviderDisplayName = providerDisplayName; + Permissions = new List(); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrant.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrant.cs new file mode 100644 index 0000000000..b74da527ae --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrant.cs @@ -0,0 +1,52 @@ +using System; +using JetBrains.Annotations; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +//TODO: To aggregate root? +public class ResourcePermissionGrant : Entity, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + + [NotNull] + public virtual string Name { get; protected set; } + + [NotNull] + public virtual string ProviderName { get; protected set; } + + [NotNull] + public virtual string ProviderKey { get; protected internal set; } + + [NotNull] + public virtual string ResourceName { get; protected set; } + + [NotNull] + public virtual string ResourceKey { get; protected set; } + + protected ResourcePermissionGrant() + { + + } + + public ResourcePermissionGrant( + Guid id, + [NotNull] string name, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerName, + [CanBeNull] string providerKey, + Guid? tenantId = null) + { + Check.NotNull(name, nameof(name)); + + Id = id; + Name = Check.NotNullOrWhiteSpace(name, nameof(name)); + ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + ResourceKey = Check.NotNullOrWhiteSpace(resourceKey, nameof(resourceKey)); + ProviderName = Check.NotNullOrWhiteSpace(providerName, nameof(providerName)); + ProviderKey = Check.NotNullOrWhiteSpace(providerKey, nameof(providerKey)); + TenantId = tenantId; + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem.cs new file mode 100644 index 0000000000..59362f6f5f --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using Volo.Abp.Text.Formatting; + +namespace Volo.Abp.PermissionManagement; + +[Serializable] +public class ResourcePermissionGrantCacheItem +{ + private const string CacheKeyFormat = "rn:{0},rk:{1},pn:{2},pk:{3},n:{4}"; + + public bool IsGranted { get; set; } + + public ResourcePermissionGrantCacheItem() + { + + } + + public ResourcePermissionGrantCacheItem(bool isGranted) + { + IsGranted = isGranted; + } + + public static string CalculateCacheKey(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return string.Format(CacheKeyFormat, resourceName, resourceKey, providerName, providerKey, name); + } + + public static string GetPermissionNameFormCacheKeyOrNull(string cacheKey) + { + var result = FormattedStringValueExtracter.Extract(cacheKey, CacheKeyFormat, true); + return result.IsMatch ? result.Matches.Last().Value : null; + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator.cs new file mode 100644 index 0000000000..97c116de56 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionGrantCacheItemInvalidator : + ILocalEventHandler>, + ITransientDependency +{ + protected ICurrentTenant CurrentTenant { get; } + + protected IDistributedCache Cache { get; } + + public ResourcePermissionGrantCacheItemInvalidator(IDistributedCache cache, ICurrentTenant currentTenant) + { + Cache = cache; + CurrentTenant = currentTenant; + } + + public virtual async Task HandleEventAsync(EntityChangedEventData eventData) + { + var cacheKey = CalculateCacheKey( + eventData.Entity.Name, + eventData.Entity.ResourceName, + eventData.Entity.ResourceKey, + eventData.Entity.ProviderName, + eventData.Entity.ProviderKey + ); + + using (CurrentTenant.Change(eventData.Entity.TenantId)) + { + await Cache.RemoveAsync(cacheKey, considerUow: true); + } + } + + protected virtual string CalculateCacheKey(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return ResourcePermissionGrantCacheItem.CalculateCacheKey(name, resourceName, resourceKey, providerName, providerKey); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..90d4e176d3 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs @@ -0,0 +1,87 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public abstract class ResourcePermissionManagementProvider : IResourcePermissionManagementProvider +{ + public abstract string Name { get; } + + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected IGuidGenerator GuidGenerator { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected ResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant) + { + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; + GuidGenerator = guidGenerator; + CurrentTenant = currentTenant; + } + + public virtual async Task CheckAsync(string name, string resourceName,string resourceKey, string providerName, string providerKey) + { + var multiplePermissionValueProviderGrantInfo = await CheckAsync(new[] { name }, resourceName, resourceKey, providerName, providerKey); + + return multiplePermissionValueProviderGrantInfo.Result.First().Value; + } + + public virtual async Task CheckAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var multiplePermissionValueProviderGrantInfo = new MultipleResourcePermissionValueProviderGrantInfo(names); + if (providerName != Name) + { + return multiplePermissionValueProviderGrantInfo; + } + + var resourcePermissionGrants = await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, providerName, providerKey); + + foreach (var permissionName in names) + { + var isGrant = resourcePermissionGrants.Any(x => x.Name == permissionName); + multiplePermissionValueProviderGrantInfo.Result[permissionName] = new ResourcePermissionValueProviderGrantInfo(isGrant, providerKey); + } + + return multiplePermissionValueProviderGrantInfo; + } + } + + public virtual Task SetAsync(string name, string resourceName,string resourceKey, string providerKey, bool isGranted) + { + return isGranted + ? GrantAsync(name, resourceName, resourceKey, providerKey) + : RevokeAsync(name, resourceName, resourceKey, providerKey); + } + + protected virtual async Task GrantAsync(string name, string resourceName, string resourceKey, string providerKey) + { + var resourcePermissionGrants = await ResourcePermissionGrantRepository.FindAsync(name, resourceName, resourceKey, Name, providerKey); + if (resourcePermissionGrants != null) + { + return; + } + + resourcePermissionGrants = new ResourcePermissionGrant(GuidGenerator.Create(), name, resourceName, resourceKey, Name, providerKey, CurrentTenant.Id); + await ResourcePermissionGrantRepository.InsertAsync(resourcePermissionGrants, true); + } + + protected virtual async Task RevokeAsync(string name, string resourceName,string resourceKey, string providerKey) + { + var resourcePermissionGrants = await ResourcePermissionGrantRepository.FindAsync(name, resourceName, resourceKey, Name, providerKey); + if (resourcePermissionGrants == null) + { + return; + } + + await ResourcePermissionGrantRepository.DeleteAsync(resourcePermissionGrants, true); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs new file mode 100644 index 0000000000..fc06819b47 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionManager : IResourcePermissionManager, ISingletonDependency +{ + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + + protected ISimpleStateCheckerManager SimpleStateCheckerManager { get; } + + protected IGuidGenerator GuidGenerator { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected IReadOnlyList ManagementProviders => _lazyProviders.Value; + + protected PermissionManagementOptions Options { get; } + + protected IDistributedCache Cache { get; } + + private readonly Lazy> _lazyProviders; + + private readonly Lazy> _lazyProviderKeyLookupServices; + + public ResourcePermissionManager( + IPermissionDefinitionManager permissionDefinitionManager, + ISimpleStateCheckerManager simpleStateCheckerManager, + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IServiceProvider serviceProvider, + IGuidGenerator guidGenerator, + IOptions options, + ICurrentTenant currentTenant, + IDistributedCache cache) + { + GuidGenerator = guidGenerator; + CurrentTenant = currentTenant; + Cache = cache; + SimpleStateCheckerManager = simpleStateCheckerManager; + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; + PermissionDefinitionManager = permissionDefinitionManager; + Options = options.Value; + + _lazyProviders = new Lazy>( + () => Options + .ResourceManagementProviders + .Select(c => serviceProvider.GetRequiredService(c) as IResourcePermissionManagementProvider) + .ToList(), + true + ); + + _lazyProviderKeyLookupServices = new Lazy>( + () => Options + .ResourcePermissionProviderKeyLookupServices + .Select(c => serviceProvider.GetRequiredService(c) as IResourcePermissionProviderKeyLookupService) + .ToList(), + true + ); + } + + public virtual Task> GetProviderKeyLookupServicesAsync() + { + return Task.FromResult(_lazyProviderKeyLookupServices.Value); + } + + public virtual Task GetProviderKeyLookupServiceAsync(string serviceName) + { + var service = _lazyProviderKeyLookupServices.Value.FirstOrDefault(s => s.Name == serviceName); + return service == null + ? throw new AbpException("Unknown resource permission provider key lookup service: " + serviceName) + : Task.FromResult(service); + } + + public virtual async Task> GetAvailablePermissionsAsync(string resourceName) + { + var multiTenancySide = CurrentTenant.GetMultiTenancySide(); + var resourcePermissions = new List(); + foreach (var resourcePermission in (await PermissionDefinitionManager.GetResourcePermissionsAsync()) + .Where(x => x.IsEnabled && x.MultiTenancySide.HasFlag(multiTenancySide) && x.ResourceName == resourceName)) + { + if (await SimpleStateCheckerManager.IsEnabledAsync(resourcePermission)) + { + resourcePermissions.Add(resourcePermission); + } + } + + return resourcePermissions; + } + + public virtual async Task GetAsync(string permissionName, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(resourceName, permissionName); + if (permission == null || permission.ResourceName != resourceName) + { + return new PermissionWithGrantedProviders(permissionName, false); + } + + return await GetInternalAsync( + permission, + resourceName, + resourceKey, + providerName, + providerKey + ); + } + + public virtual async Task GetAsync(string[] permissionNames, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissions = new List(); + var undefinedPermissions = new List(); + + foreach (var permissionName in permissionNames) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(resourceName, permissionName); + if (permission != null && permission.ResourceName == resourceName) + { + permissions.Add(permission); + } + else + { + undefinedPermissions.Add(permissionName); + } + } + + if (!permissions.Any()) + { + return new MultiplePermissionWithGrantedProviders(undefinedPermissions.ToArray()); + } + + var result = await GetInternalAsync( + permissions.ToArray(), + resourceName, + resourceKey, + providerName, + providerKey + ); + + foreach (var undefinedPermission in undefinedPermissions) + { + result.Result.Add(new PermissionWithGrantedProviders(undefinedPermission, false)); + } + + return result; + } + + public virtual async Task> GetAllAsync(string resourceName, string resourceKey) + { + var resourcePermissionDefinitions = await GetAvailablePermissionsAsync(resourceName); + var resourcePermissionGrants = await ResourcePermissionGrantRepository.GetPermissionsAsync(resourceName, resourceKey); + var result = new List(); + foreach (var resourcePermissionDefinition in resourcePermissionDefinitions) + { + var permissionWithGrantedProviders = new PermissionWithGrantedProviders(resourcePermissionDefinition.Name, false); + + var grantedPermissions = resourcePermissionGrants + .Where(x => x.Name == resourcePermissionDefinition.Name && x.ResourceName == resourceName && x.ResourceKey == resourceKey) + .ToList(); + + if (grantedPermissions.Any()) + { + permissionWithGrantedProviders.IsGranted = true; + foreach (var grantedPermission in grantedPermissions) + { + permissionWithGrantedProviders.Providers.Add(new PermissionValueProviderInfo(grantedPermission.ProviderName, grantedPermission.ProviderKey)); + } + } + + result.Add(permissionWithGrantedProviders); + } + + return result; + } + + public virtual async Task> GetAllAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionDefinitions = await GetAvailablePermissionsAsync(resourceName); + var multiplePermissionWithGrantedProviders = await GetInternalAsync(permissionDefinitions.ToArray(), resourceName, resourceKey, providerName, providerKey); + return multiplePermissionWithGrantedProviders.Result; + } + + public virtual async Task> GetAllGroupAsync(string resourceName, string resourceKey) + { + var resourcePermissions = await GetAvailablePermissionsAsync(resourceName); + var resourcePermissionGrants = await ResourcePermissionGrantRepository.GetPermissionsAsync(resourceName, resourceKey); + resourcePermissionGrants = resourcePermissionGrants.Where(x => resourcePermissions.Any(rp => rp.Name == x.Name)).ToList(); + var resourcePermissionGrantsGroup = resourcePermissionGrants.GroupBy(x => new { x.ProviderName, x.ProviderKey }); + var result = new List(); + foreach (var resourcePermissionGrant in resourcePermissionGrantsGroup) + { + result.Add(new PermissionProviderWithPermissions(resourcePermissionGrant.Key.ProviderName, resourcePermissionGrant.Key.ProviderKey, resourcePermissionGrant.Key.ProviderKey) + { + Permissions = resourcePermissionGrant.Select(x => x.Name).ToList() + }); + } + + if (result.Any()) + { + var providerKeyInfos = new Dictionary>(); + var resourcePermissionProviderGroup = resourcePermissionGrants.GroupBy(x => x.ProviderName); + var providerKeyLookupServices = await GetProviderKeyLookupServicesAsync(); + foreach (var resourcePermissionProvider in resourcePermissionProviderGroup) + { + var providerKeyLookupService = providerKeyLookupServices.FirstOrDefault(s => s.Name == resourcePermissionProvider.Key); + if (providerKeyLookupService == null) + { + continue; + } + var keys = resourcePermissionProvider.Select(rp => rp.ProviderKey).Distinct().ToList(); + providerKeyInfos.Add(resourcePermissionProvider.Key, await providerKeyLookupService.SearchAsync(keys.ToArray())); + } + + foreach (var item in result) + { + if (!providerKeyInfos.TryGetValue(item.ProviderName, out var providerKeyInfoList)) + { + continue; + } + + var providerKeyInfo = providerKeyInfoList.FirstOrDefault(p => p.ProviderKey == item.ProviderKey); + if (providerKeyInfo != null) + { + item.ProviderDisplayName = providerKeyInfo.ProviderDisplayName; + item.ProviderNameDisplayName = providerKeyLookupServices + .FirstOrDefault(s => s.Name == item.ProviderName)?.DisplayName; + } + } + } + + return result; + } + + public virtual async Task SetAsync(string permissionName, string resourceName, string resourceKey, string providerName, string providerKey, bool isGranted) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(resourceName, permissionName); + if (permission == null || permission.ResourceName != resourceName) + { + /* Silently ignore undefined permissions, + maybe they were removed from dynamic permission definition store */ + return; + } + + if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission)) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' is disabled!"); + } + + if (permission.Providers.Any() && !permission.Providers.Contains(providerName)) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' has not compatible with the provider named '{providerName}'"); + } + + if (!permission.MultiTenancySide.HasFlag(CurrentTenant.GetMultiTenancySide())) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' has multitenancy side '{permission.MultiTenancySide}' which is not compatible with the current multitenancy side '{CurrentTenant.GetMultiTenancySide()}'"); + } + + var currentGrantInfo = await GetInternalAsync(permission, resourceName, resourceKey, providerName, providerKey); + if (currentGrantInfo.IsGranted == isGranted) + { + return; + } + + var provider = ManagementProviders.FirstOrDefault(m => m.Name == providerName); + if (provider == null) + { + //TODO: BusinessException + throw new AbpException("Unknown resource permission management provider: " + providerName); + } + + await provider.SetAsync(permissionName, resourceName, resourceKey, providerKey, isGranted); + } + + public virtual async Task UpdateProviderKeyAsync(ResourcePermissionGrant resourcePermissionGrant, string providerKey) + { + using (CurrentTenant.Change(resourcePermissionGrant.TenantId)) + { + //Invalidating the cache for the old key + await Cache.RemoveAsync( + ResourcePermissionGrantCacheItem.CalculateCacheKey( + resourcePermissionGrant.Name, + resourcePermissionGrant.ResourceName, + resourcePermissionGrant.ResourceKey, + resourcePermissionGrant.ProviderName, + resourcePermissionGrant.ProviderKey + ) + ); + } + + resourcePermissionGrant.ProviderKey = providerKey; + return await ResourcePermissionGrantRepository.UpdateAsync(resourcePermissionGrant, true); + } + + public virtual async Task UpdateProviderKeyAsync(ResourcePermissionGrant resourcePermissionGrant, string resourceName, string resourceKey, string providerKey) + { + using (CurrentTenant.Change(resourcePermissionGrant.TenantId)) + { + //Invalidating the cache for the old key + await Cache.RemoveAsync( + ResourcePermissionGrantCacheItem.CalculateCacheKey( + resourcePermissionGrant.Name, + resourcePermissionGrant.ResourceName, + resourcePermissionGrant.ResourceKey, + resourcePermissionGrant.ProviderName, + resourcePermissionGrant.ProviderKey + ) + ); + } + + resourcePermissionGrant.ProviderKey = providerKey; + return await ResourcePermissionGrantRepository.UpdateAsync(resourcePermissionGrant, true); + } + + public virtual async Task DeleteAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionGrants = await ResourcePermissionGrantRepository.GetListAsync(resourceName, resourceKey, providerName, providerKey); + foreach (var permissionGrant in permissionGrants) + { + await ResourcePermissionGrantRepository.DeleteAsync(permissionGrant, true); + } + } + + public virtual async Task DeleteAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionGrant = await ResourcePermissionGrantRepository.FindAsync(name, resourceName, resourceKey, providerName, providerKey); + if (permissionGrant != null) + { + await ResourcePermissionGrantRepository.DeleteAsync(permissionGrant, true); + } + } + + public virtual async Task DeleteAsync(string providerName, string providerKey) + { + var permissionGrants = await ResourcePermissionGrantRepository.GetListAsync(providerName, providerKey); + foreach (var permissionGrant in permissionGrants) + { + await ResourcePermissionGrantRepository.DeleteAsync(permissionGrant, true); + } + } + + protected virtual async Task GetInternalAsync(PermissionDefinition permission, string resourceName, string resourceKey, string providerName, string providerKey) + { + var multiplePermissionWithGrantedProviders = await GetInternalAsync( + new[] { permission }, + resourceName, + resourceKey, + providerName, + providerKey + ); + + return multiplePermissionWithGrantedProviders.Result.First(); + } + + protected virtual async Task GetInternalAsync(PermissionDefinition[] permissions, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionNames = permissions.Select(x => x.Name).ToArray(); + var multiplePermissionWithGrantedProviders = new MultiplePermissionWithGrantedProviders(permissionNames); + + var resourcePermissions = await GetAvailablePermissionsAsync(resourceName); + if (!resourcePermissions.Any()) + { + return multiplePermissionWithGrantedProviders; + } + + foreach (var provider in ManagementProviders) + { + permissionNames = resourcePermissions.Select(x => x.Name).ToArray(); + var multiplePermissionValueProviderGrantInfo = await provider.CheckAsync(permissionNames, resourceName, resourceKey, providerName, providerKey); + + foreach (var providerResultDict in multiplePermissionValueProviderGrantInfo.Result) + { + if (providerResultDict.Value.IsGranted) + { + var permissionWithGrantedProvider = multiplePermissionWithGrantedProviders.Result + .FirstOrDefault(x => x.Name == providerResultDict.Key); + + if (permissionWithGrantedProvider == null) + { + continue; + } + + permissionWithGrantedProvider.IsGranted = true; + permissionWithGrantedProvider.Providers.Add( + new PermissionValueProviderInfo(provider.Name, providerResultDict.Value.ProviderKey)); + } + } + } + + return multiplePermissionWithGrantedProviders; + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionProviderKeyInfo.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionProviderKeyInfo.cs new file mode 100644 index 0000000000..841277514a --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionProviderKeyInfo.cs @@ -0,0 +1,16 @@ +using Volo.Abp.ObjectExtending; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionProviderKeyInfo +{ + public string ProviderKey { get; set; } + + public string ProviderDisplayName { get; set; } + + public ResourcePermissionProviderKeyInfo(string providerKey, string providerDisplayName) + { + ProviderKey = providerKey; + ProviderDisplayName = providerDisplayName; + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionStore.cs new file mode 100644 index 0000000000..9e09ff2db4 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionStore.cs @@ -0,0 +1,249 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionStore : IResourcePermissionStore, ITransientDependency +{ + public ILogger Logger { get; set; } + + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + + protected IDistributedCache Cache { get; } + + public ResourcePermissionStore( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IDistributedCache cache, + IPermissionDefinitionManager permissionDefinitionManager) + { + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; + Cache = cache; + PermissionDefinitionManager = permissionDefinitionManager; + Logger = NullLogger.Instance; + } + + public virtual async Task IsGrantedAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return (await GetCacheItemAsync(name, resourceName, resourceKey, providerName, providerKey)).IsGranted; + } + + protected virtual async Task GetCacheItemAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + var cacheKey = CalculateCacheKey(name, providerName, providerKey, resourceName, resourceKey); + + Logger.LogDebug($"ResourcePermissionStore.GetCacheItemAsync: {cacheKey}"); + + var cacheItem = await Cache.GetAsync(cacheKey); + + if (cacheItem != null) + { + Logger.LogDebug($"Found in the cache: {cacheKey}"); + return cacheItem; + } + + Logger.LogDebug($"Not found in the cache: {cacheKey}"); + + cacheItem = new ResourcePermissionGrantCacheItem(false); + + await SetCacheItemsAsync(resourceName, resourceKey, providerName, providerKey, name, cacheItem); + + return cacheItem; + } + + protected virtual async Task SetCacheItemsAsync(string resourceName, string resourceKey, string providerName, string providerKey, string currentName, ResourcePermissionGrantCacheItem currentCacheItem) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var permissions = await PermissionDefinitionManager.GetResourcePermissionsAsync(); + + Logger.LogDebug($"Getting all granted resource permissions from the repository for resource name,key:{resourceName},{resourceKey} and provider name,key: {providerName},{providerKey}"); + + var grantedPermissionsHashSet = new HashSet( + (await ResourcePermissionGrantRepository.GetListAsync(resourceName, resourceKey, providerName, providerKey)).Select(p => p.Name) + ); + + Logger.LogDebug($"Setting the cache items. Count: {permissions.Count}"); + + var cacheItems = new List>(); + + foreach (var permission in permissions) + { + var isGranted = grantedPermissionsHashSet.Contains(permission.Name); + + cacheItems.Add(new KeyValuePair( + CalculateCacheKey(permission.Name, resourceName, resourceKey, providerName, providerKey), + new ResourcePermissionGrantCacheItem(isGranted)) + ); + + if (permission.Name == currentName) + { + currentCacheItem.IsGranted = isGranted; + } + } + + await Cache.SetManyAsync(cacheItems); + + Logger.LogDebug($"Finished setting the cache items. Count: {permissions.Count}"); + } + } + + public virtual async Task IsGrantedAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + Check.NotNullOrEmpty(names, nameof(names)); + + var result = new MultiplePermissionGrantResult(); + + if (names.Length == 1) + { + var name = names.First(); + result.Result.Add(name, + await IsGrantedAsync(names.First(), resourceName, resourceKey, providerName, providerKey) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + return result; + } + + var cacheItems = await GetCacheItemsAsync(names, resourceName, resourceKey, providerName, providerKey); + foreach (var item in cacheItems) + { + result.Result.Add(GetPermissionNameFormCacheKeyOrNull(item.Key), + item.Value != null && item.Value.IsGranted + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + } + + return result; + } + + protected virtual async Task>> GetCacheItemsAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + var cacheKeys = names.Select(x => CalculateCacheKey(x, resourceName, resourceKey, providerName, providerKey)).ToList(); + + Logger.LogDebug($"ResourcePermissionStore.GetCacheItemAsync: {string.Join(",", cacheKeys)}"); + + var cacheItems = (await Cache.GetManyAsync(cacheKeys)).ToList(); + if (cacheItems.All(x => x.Value != null)) + { + Logger.LogDebug($"Found in the cache: {string.Join(",", cacheKeys)}"); + return cacheItems; + } + + var notCacheKeys = cacheItems.Where(x => x.Value == null).Select(x => x.Key).ToList(); + + Logger.LogDebug($"Not found in the cache: {string.Join(",", notCacheKeys)}"); + + var newCacheItems = await SetCacheItemsAsync(resourceName, resourceKey, providerName, providerKey, notCacheKeys); + + var result = new List>(); + foreach (var key in cacheKeys) + { + var item = newCacheItems.FirstOrDefault(x => x.Key == key); + if (item.Value == null) + { + item = cacheItems.FirstOrDefault(x => x.Key == key); + } + + result.Add(new KeyValuePair(key, item.Value)); + } + + return result; + } + + protected virtual async Task>> SetCacheItemsAsync(string resourceName, string resourceKey, string providerName, string providerKey, List notCacheKeys) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var permissionNames = new HashSet(notCacheKeys.Select(GetPermissionNameFormCacheKeyOrNull)); + var permissions = (await PermissionDefinitionManager.GetResourcePermissionsAsync()) + .Where(x => permissionNames.Contains(x.Name)) + .ToList(); + + Logger.LogDebug($"Getting not cache granted permissions from the repository for resource name,key:{resourceName},{resourceKey} and provider name,key: {providerName},{providerKey}"); + + var grantedPermissionsHashSet = new HashSet( + (await ResourcePermissionGrantRepository.GetListAsync(permissionNames.ToArray(), resourceName, resourceKey, providerName, providerKey)).Select(p => p.Name) + ); + + Logger.LogDebug($"Setting the cache items. Count: {permissions.Count}"); + + var cacheItems = new List>(); + + foreach (var permission in permissions) + { + var isGranted = grantedPermissionsHashSet.Contains(permission.Name); + + cacheItems.Add(new KeyValuePair( + CalculateCacheKey(permission.Name, resourceName, resourceKey, providerName, providerKey), + new ResourcePermissionGrantCacheItem(isGranted)) + ); + } + + await Cache.SetManyAsync(cacheItems); + + Logger.LogDebug($"Finished setting the cache items. Count: {permissions.Count}"); + + return cacheItems; + } + } + + public virtual async Task GetPermissionsAsync(string resourceName, string resourceKey) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var result = new MultiplePermissionGrantResult(); + + var resourcePermissions = (await PermissionDefinitionManager.GetResourcePermissionsAsync()).Where(x => x.ResourceName == resourceName).ToList(); + var permissionGrants = await ResourcePermissionGrantRepository.GetPermissionsAsync(resourceName, resourceKey); + foreach (var resourcePermission in resourcePermissions) + { + var isGranted = permissionGrants.Any(x => x.Name == resourcePermission.Name); + result.Result.Add(resourcePermission.Name, isGranted ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined); + } + + return result; + } + } + + public virtual async Task GetGrantedPermissionsAsync(string resourceName, string resourceKey) + { + var resourcePermissions = (await PermissionDefinitionManager.GetResourcePermissionsAsync()).Where(x => x.ResourceName == resourceName).ToList(); + var grantedPermissions = await ResourcePermissionGrantRepository.GetPermissionsAsync(resourceName, resourceKey); + + var result = new List(); + foreach (var grantedPermission in grantedPermissions) + { + if (resourcePermissions.Any(x => x.Name == grantedPermission.Name)) + { + result.Add(grantedPermission.Name); + } + } + + return result.ToArray(); + } + + public virtual async Task GetGrantedResourceKeysAsync(string resourceName, string name) + { + return (await ResourcePermissionGrantRepository.GetResourceKeys(resourceName, name)).Select(x => x.ResourceKey).ToArray(); + } + + protected virtual string GetPermissionNameFormCacheKeyOrNull(string key) + { + //TODO: throw ex when name is null? + return ResourcePermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull(key); + } + + protected virtual string CalculateCacheKey(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + return ResourcePermissionGrantCacheItem.CalculateCacheKey(name, resourceName, resourceKey, providerName, providerKey); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionValueProviderGrantInfo.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionValueProviderGrantInfo.cs new file mode 100644 index 0000000000..5cb0d5013a --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionValueProviderGrantInfo.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionValueProviderGrantInfo //TODO: Rename to ResourcePermissionGrantInfo +{ + public static ResourcePermissionValueProviderGrantInfo NonGranted { get; } = new ResourcePermissionValueProviderGrantInfo(false); + + public virtual bool IsGranted { get; set; } + + public virtual string ProviderKey { get; set; } + + public ResourcePermissionValueProviderGrantInfo(bool isGranted, [CanBeNull] string providerKey = null) + { + IsGranted = isGranted; + ProviderKey = providerKey; + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index d1dff35f35..c672207f4f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -85,6 +85,12 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc await StaticStore.GetGroupsAsync() ); + var resourcePermissions = await PermissionSerializer.SerializeAsync( + await StaticStore.GetResourcePermissionsAsync() + ); + + permissionRecords = permissionRecords.Union(resourcePermissions).ToArray(); + var currentHash = CalculateHash( permissionGroupRecords, permissionRecords, diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs index fa6862abf6..c7bf3f2a5a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs @@ -27,6 +27,23 @@ public static class AbpPermissionManagementDbContextModelBuilderExtensions b.ApplyObjectExtensionMappings(); }); + builder.Entity(b => + { + b.ToTable(AbpPermissionManagementDbProperties.DbTablePrefix + "ResourcePermissionGrants", AbpPermissionManagementDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.ResourceName).HasMaxLength(PermissionGrantConsts.MaxResourceNameLength).IsRequired(); + b.Property(x => x.ResourceKey).HasMaxLength(PermissionGrantConsts.MaxResourceKeyLength).IsRequired(); + b.Property(x => x.ProviderName).HasMaxLength(PermissionGrantConsts.MaxProviderNameLength).IsRequired(); + b.Property(x => x.ProviderKey).HasMaxLength(PermissionGrantConsts.MaxProviderKeyLength).IsRequired(); + + b.HasIndex(x => new { x.TenantId, x.Name, x.ResourceName, x.ResourceKey, x.ProviderName, x.ProviderKey }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + if (builder.IsHostDatabase()) { builder.Entity(b => @@ -52,16 +69,16 @@ public static class AbpPermissionManagementDbContextModelBuilderExtensions b.ConfigureByConvention(); - b.Property(x => x.GroupName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength) - .IsRequired(); + b.Property(x => x.GroupName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength); b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.ResourceName).HasMaxLength(PermissionDefinitionRecordConsts.MaxResourceNameLength); + b.Property(x => x.ManagementPermissionName).HasMaxLength(PermissionDefinitionRecordConsts.MaxManagementPermissionNameLength); b.Property(x => x.ParentName).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength); - b.Property(x => x.DisplayName).HasMaxLength(PermissionDefinitionRecordConsts.MaxDisplayNameLength) - .IsRequired(); + b.Property(x => x.DisplayName).HasMaxLength(PermissionDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); b.Property(x => x.Providers).HasMaxLength(PermissionDefinitionRecordConsts.MaxProvidersLength); b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength); - b.HasIndex(x => new { x.Name }).IsUnique(); + b.HasIndex(x => new { x.ResourceName, x.Name }).IsUnique(); b.HasIndex(x => new { x.GroupName }); b.ApplyObjectExtensionMappings(); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs index ebcc8527c1..da6dfe8b06 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs @@ -17,6 +17,7 @@ public class AbpPermissionManagementEntityFrameworkCoreModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCoreResourcePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCoreResourcePermissionGrantRepository.cs new file mode 100644 index 0000000000..385a45f989 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCoreResourcePermissionGrantRepository.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCoreResourcePermissionGrantRepository : EfCoreRepository, IResourcePermissionGrantRepository +{ + public EfCoreResourcePermissionGrantRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + public virtual async Task FindAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(s => + s.Name == name && + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey, + GetCancellationToken(cancellationToken) + ); + } + + public virtual async Task> GetListAsync(string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(s => + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetListAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(s => + names.Contains(s.Name) && + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetListAsync(string providerName, string providerKey, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(s => + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetPermissionsAsync(string resourceName, string resourceKey, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(s => + s.ResourceName == resourceName && + s.ResourceKey == resourceKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetResourceKeys(string resourceName, string name, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(s => + s.ResourceName == resourceName && + s.Name == name + ).ToListAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs index c294c1b248..de02ab70ec 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs @@ -8,8 +8,10 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; public interface IPermissionManagementDbContext : IEfCoreDbContext { DbSet PermissionGroups { get; } - + DbSet Permissions { get; } - + DbSet PermissionGrants { get; } + + DbSet ResourcePermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs index fe143fa8ae..59c724bfb7 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs @@ -10,6 +10,7 @@ public class PermissionManagementDbContext : AbpDbContext PermissionGroups { get; set; } public DbSet Permissions { get; set; } public DbSet PermissionGrants { get; set; } + public DbSet ResourcePermissionGrants { get; set; } public PermissionManagementDbContext(DbContextOptions options) : base(options) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs index 2fe22472f0..bd6e2c5e8e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/Volo/Abp/PermissionManagement/PermissionsClientProxy.Generated.cs @@ -45,4 +45,72 @@ public partial class PermissionsClientProxy : ClientProxyBase GetResourceProviderKeyLookupServicesAsync(string resourceName) + { + return await RequestAsync(nameof(GetResourceProviderKeyLookupServicesAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName } + }); + } + + public virtual async Task SearchResourceProviderKeyAsync(string resourceName, string serviceName, string filter, int page) + { + return await RequestAsync(nameof(SearchResourceProviderKeyAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName }, + { typeof(string), serviceName }, + { typeof(string), filter }, + { typeof(int), page } + }); + } + + public virtual async Task GetResourceDefinitionsAsync(string resourceName) + { + return await RequestAsync(nameof(GetResourceDefinitionsAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName } + }); + } + + public virtual async Task GetResourceAsync(string resourceName, string resourceKey) + { + return await RequestAsync(nameof(GetResourceAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName }, + { typeof(string), resourceKey } + }); + } + + public virtual async Task GetResourceByProviderAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + return await RequestAsync(nameof(GetResourceByProviderAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName }, + { typeof(string), resourceKey }, + { typeof(string), providerName }, + { typeof(string), providerKey } + }); + } + + public virtual async Task UpdateResourceAsync(string resourceName, string resourceKey, UpdateResourcePermissionsDto input) + { + await RequestAsync(nameof(UpdateResourceAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName }, + { typeof(string), resourceKey }, + { typeof(UpdateResourcePermissionsDto), input } + }); + } + + public virtual async Task DeleteResourceAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + await RequestAsync(nameof(DeleteResourceAsync), new ClientProxyRequestTypeValue + { + { typeof(string), resourceName }, + { typeof(string), resourceKey }, + { typeof(string), providerName }, + { typeof(string), providerKey } + }); + } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json index 208271e67d..8b95d9be21 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client/ClientProxies/permissionManagement-generate-proxy.json @@ -21,7 +21,7 @@ "parametersOnMethod": [ { "name": "input", - "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=9.3.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", + "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=10.1.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", "type": "System.Collections.Generic.List", "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", "isOptional": false, @@ -46,7 +46,7 @@ "parametersOnMethod": [ { "name": "input", - "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=9.3.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", + "typeAsString": "System.Collections.Generic.List`1[[Volo.Abp.PermissionManagement.IsGrantedRequest, Volo.Abp.PermissionManagement.Domain.Shared, Version=10.1.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib", "type": "System.Collections.Generic.List", "typeSimple": "[Volo.Abp.PermissionManagement.IsGrantedRequest]", "isOptional": false, @@ -178,6 +178,221 @@ "type": "System.Void", "typeSimple": "System.Void" } + }, + { + "name": "GetResourceProviderKeyLookupServicesAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourceProviderListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourceProviderListResultDto" + } + }, + { + "name": "SearchResourceProviderKeyAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "serviceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "filter", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "page", + "typeAsString": "System.Int32, System.Private.CoreLib", + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.SearchProviderKeyListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.SearchProviderKeyListResultDto" + } + }, + { + "name": "GetResourceDefinitionsAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionDefinitionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionDefinitionListResultDto" + } + }, + { + "name": "GetResourceAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionListResultDto" + } + }, + { + "name": "GetResourceByProviderAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionWithProviderListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionWithProviderListResultDto" + } + }, + { + "name": "UpdateResourceAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "input", + "typeAsString": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto, Volo.Abp.PermissionManagement.Application.Contracts", + "type": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "typeSimple": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } + }, + { + "name": "DeleteResourceAsync", + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + } } ] } @@ -393,6 +608,505 @@ }, "allowAnonymous": null, "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "GetResourceProviderKeyLookupServicesAsyncByResourceName": { + "uniqueName": "GetResourceProviderKeyLookupServicesAsyncByResourceName", + "name": "GetResourceProviderKeyLookupServicesAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/resource-provider-key-lookup-services", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourceProviderListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourceProviderListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "SearchResourceProviderKeyAsyncByResourceNameAndServiceNameAndFilterAndPage": { + "uniqueName": "SearchResourceProviderKeyAsyncByResourceNameAndServiceNameAndFilterAndPage", + "name": "SearchResourceProviderKeyAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/search-resource-provider-keys", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "serviceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "filter", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "page", + "typeAsString": "System.Int32, System.Private.CoreLib", + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "serviceName", + "name": "serviceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "filter", + "name": "filter", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "page", + "name": "page", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.SearchProviderKeyListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.SearchProviderKeyListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "GetResourceDefinitionsAsyncByResourceName": { + "uniqueName": "GetResourceDefinitionsAsyncByResourceName", + "name": "GetResourceDefinitionsAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/resource-definitions", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionDefinitionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionDefinitionListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "GetResourceAsyncByResourceNameAndResourceKey": { + "uniqueName": "GetResourceAsyncByResourceNameAndResourceKey", + "name": "GetResourceAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/resource", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "resourceKey", + "name": "resourceKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "GetResourceByProviderAsyncByResourceNameAndResourceKeyAndProviderNameAndProviderKey": { + "uniqueName": "GetResourceByProviderAsyncByResourceNameAndResourceKeyAndProviderNameAndProviderKey", + "name": "GetResourceByProviderAsync", + "httpMethod": "GET", + "url": "api/permission-management/permissions/resource/by-provider", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "resourceKey", + "name": "resourceKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerName", + "name": "providerName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerKey", + "name": "providerKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.PermissionManagement.GetResourcePermissionWithProviderListResultDto", + "typeSimple": "Volo.Abp.PermissionManagement.GetResourcePermissionWithProviderListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "UpdateResourceAsyncByResourceNameAndResourceKeyAndInput": { + "uniqueName": "UpdateResourceAsyncByResourceNameAndResourceKeyAndInput", + "name": "UpdateResourceAsync", + "httpMethod": "PUT", + "url": "api/permission-management/permissions/resource", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "input", + "typeAsString": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto, Volo.Abp.PermissionManagement.Application.Contracts", + "type": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "typeSimple": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "resourceKey", + "name": "resourceKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "input", + "name": "input", + "jsonName": null, + "type": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "typeSimple": "Volo.Abp.PermissionManagement.UpdateResourcePermissionsDto", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "Body", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" + }, + "DeleteResourceAsyncByResourceNameAndResourceKeyAndProviderNameAndProviderKey": { + "uniqueName": "DeleteResourceAsyncByResourceNameAndResourceKeyAndProviderNameAndProviderKey", + "name": "DeleteResourceAsync", + "httpMethod": "DELETE", + "url": "api/permission-management/permissions/resource", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "resourceName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "resourceKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "resourceName", + "name": "resourceName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "resourceKey", + "name": "resourceKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerName", + "name": "providerName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerKey", + "name": "providerKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.PermissionManagement.IPermissionAppService" } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs index ff6d7e6128..c1f65e353e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi/Volo/Abp/PermissionManagement/PermissionsController.cs @@ -34,4 +34,50 @@ public class PermissionsController : AbpControllerBase, IPermissionAppService { return PermissionAppService.UpdateAsync(providerName, providerKey, input); } + + [HttpGet("resource-provider-key-lookup-services")] + public virtual Task GetResourceProviderKeyLookupServicesAsync(string resourceName) + { + return PermissionAppService.GetResourceProviderKeyLookupServicesAsync(resourceName); + } + + [HttpGet("search-resource-provider-keys")] + public virtual Task SearchResourceProviderKeyAsync(string resourceName, string serviceName, string filter, int page) + { + return PermissionAppService.SearchResourceProviderKeyAsync(resourceName, serviceName, filter, page); + } + + [HttpGet("resource-definitions")] + public virtual Task GetResourceDefinitionsAsync(string resourceName) + { + return PermissionAppService.GetResourceDefinitionsAsync(resourceName); + } + + [HttpGet] + [Route("resource")] + public virtual Task GetResourceAsync(string resourceName, string resourceKey) + { + return PermissionAppService.GetResourceAsync(resourceName, resourceKey); + } + + [HttpGet] + [Route("resource/by-provider")] + public virtual Task GetResourceByProviderAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + return PermissionAppService.GetResourceByProviderAsync(resourceName, resourceKey, providerName, providerKey); + } + + [HttpPut] + [Route("resource")] + public virtual Task UpdateResourceAsync(string resourceName, string resourceKey, UpdateResourcePermissionsDto input) + { + return PermissionAppService.UpdateResourceAsync(resourceName, resourceKey, input); + } + + [HttpDelete] + [Route("resource")] + public virtual Task DeleteResourceAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + return PermissionAppService.DeleteResourceAsync(resourceName, resourceKey, providerName, providerKey); + } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs index 9c7c90af58..4eb8eea3b6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs @@ -13,15 +13,20 @@ public static class AbpPermissionManagementMongoDbContextExtensions { b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGroups"; }); - + builder.Entity(b => { b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "Permissions"; }); - + builder.Entity(b => { b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGrants"; }); + + builder.Entity(b => + { + b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "ResourcePermissionGrants"; + }); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs index 80831660f8..686d219295 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs @@ -19,6 +19,7 @@ public class AbpPermissionManagementMongoDbModule : AbpModule options.AddRepository(); options.AddRepository(); options.AddRepository(); + options.AddRepository(); }); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs index 98015484fb..454875f517 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs @@ -8,8 +8,10 @@ namespace Volo.Abp.PermissionManagement.MongoDB; public interface IPermissionManagementMongoDbContext : IAbpMongoDbContext { IMongoCollection PermissionGroups { get; } - + IMongoCollection Permissions { get; } - + IMongoCollection PermissionGrants { get; } + + IMongoCollection ResourcePermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoResourcePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoResourcePermissionGrantRepository.cs new file mode 100644 index 0000000000..30db095854 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoResourcePermissionGrantRepository.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +public class MongoResourcePermissionGrantRepository : MongoDbRepository, IResourcePermissionGrantRepository +{ + public MongoResourcePermissionGrantRepository(IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + + } + + public virtual async Task FindAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(s => + s.Name == name && + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey, + cancellationToken + ); + } + + public virtual async Task> GetListAsync(string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .Where(s => + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(cancellationToken); + } + + public virtual async Task> GetListAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .Where(s => + names.AsEnumerable().Contains(s.Name) && + s.ResourceName == resourceName && + s.ResourceKey == resourceKey && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(cancellationToken); + } + + public virtual async Task> GetListAsync(string providerName, string providerKey, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .Where(s => + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(cancellationToken); + } + + public virtual async Task> GetPermissionsAsync(string resourceName, string resourceKey, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .Where(s => + s.ResourceName == resourceName && + s.ResourceKey == resourceKey + ).ToListAsync(cancellationToken); + } + + public virtual async Task> GetResourceKeys(string resourceName, string name, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetQueryableAsync(cancellationToken)) + .Where(s => + s.ResourceName == resourceName && + s.Name == name + ).ToListAsync(cancellationToken); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs index c62db52c11..c9ea6ea984 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs @@ -10,6 +10,7 @@ public class PermissionManagementMongoDbContext : AbpMongoDbContext, IPermission public IMongoCollection PermissionGroups => Collection(); public IMongoCollection Permissions => Collection(); public IMongoCollection PermissionGrants => Collection(); + public IMongoCollection ResourcePermissionGrants => Collection(); protected override void CreateModel(IMongoModelBuilder modelBuilder) { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs index baa27b44ff..e20e38c53a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/AbpPermissionManagementWebModule.cs @@ -20,7 +20,7 @@ public class AbpPermissionManagementWebModule : AbpModule { options.AddAssemblyResource( typeof(AbpPermissionManagementResource), - typeof(AbpPermissionManagementWebModule).Assembly, + typeof(AbpPermissionManagementWebModule).Assembly, typeof(AbpPermissionManagementApplicationContractsModule).Assembly ); }); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml new file mode 100644 index 0000000000..be12c7cd1d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml @@ -0,0 +1,54 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Abp.Localization +@using Volo.Abp.PermissionManagement.Localization +@using Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement +@model AddResourcePermissionManagementModal +@inject IHtmlLocalizer L + +@{ + Layout = null; +} + + + + +
+ + + + + + +
+
+ @foreach (var provider in Model.ResourceProviders.Providers.Select((value, i) => new { i, value })) + { +
+ + +
+ } +
+ + +
+
+

@L["ResourcePermissionPermissions"]

+
+ + +
+ @foreach (var permission in Model.ResourcePermissionDefinitions.Permissions) + { +
+ + +
+ } +
+
+ +
+
diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml.cs new file mode 100644 index 0000000000..d9828ee661 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/AddResourcePermissionManagementModal.cshtml.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement; + +public class AddResourcePermissionManagementModal : AbpPageModel +{ + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceName { get; set; } + + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceKey { get; set; } + + [BindProperty(SupportsGet = true)] + [HiddenInput] + public string ResourceDisplayName { get; set; } + + [BindProperty] + public ResourcePermissionViewModel AddModel { get; set; } + + public GetResourcePermissionDefinitionListResultDto ResourcePermissionDefinitions { get; set; } + public GetResourceProviderListResultDto ResourceProviders { get; set; } + + protected IPermissionAppService PermissionAppService { get; } + + public AddResourcePermissionManagementModal(IPermissionAppService permissionAppService) + { + ObjectMapperContext = typeof(AbpPermissionManagementWebModule); + + PermissionAppService = permissionAppService; + } + + public virtual async Task OnGetAsync() + { + ValidateModel(); + + ResourcePermissionDefinitions = await PermissionAppService.GetResourceDefinitionsAsync(ResourceName); + ResourceProviders = await PermissionAppService.GetResourceProviderKeyLookupServicesAsync(ResourceName); + + return Page(); + } + + public virtual async Task OnPostAsync() + { + ValidateModel(); + + await PermissionAppService.UpdateResourceAsync( + ResourceName, + ResourceKey, + new UpdateResourcePermissionsDto() + { + ProviderName = AddModel.ProviderName, + ProviderKey = AddModel.ProviderKey, + Permissions = AddModel.Permissions ?? new List() + } + ); + + return NoContent(); + } + + public class ResourcePermissionViewModel + { + [Required] + public string ProviderName { get; set; } + + [Required] + public string ProviderKey { get; set; } + + public List Permissions { get; set; } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml index a9caf5c348..c1241af454 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml @@ -79,5 +79,3 @@ - - \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml new file mode 100644 index 0000000000..5717448c70 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml @@ -0,0 +1,52 @@ +@page +@using System.Web; +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Abp.Localization +@using Volo.Abp.PermissionManagement.Localization +@using Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement +@model ResourcePermissionManagementModal +@inject IHtmlLocalizer L + +@{ + Layout = null; +} + +@if(Model.HasAnyResourcePermission && Model.HasAnyResourceProviderKeyLookupService) +{ + + +
+ + + + + +
+ +
+ +
+ +
+
+} +else +{ + + + + + + + +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml.cs new file mode 100644 index 0000000000..1b1373e017 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/ResourcePermissionManagementModal.cshtml.cs @@ -0,0 +1,51 @@ +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement; + +public class ResourcePermissionManagementModal : AbpPageModel +{ + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceName { get; set; } + + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceKey { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceDisplayName { get; set; } + + public bool HasAnyResourcePermission { get; set; } + public bool HasAnyResourceProviderKeyLookupService { get; set; } + + protected IPermissionAppService PermissionAppService { get; } + + public ResourcePermissionManagementModal(IPermissionAppService permissionAppService) + { + ObjectMapperContext = typeof(AbpPermissionManagementWebModule); + + PermissionAppService = permissionAppService; + } + + public virtual async Task OnGetAsync() + { + HasAnyResourcePermission = (await PermissionAppService.GetResourceDefinitionsAsync(ResourceName)).Permissions.Any(); + if (HasAnyResourcePermission) + { + HasAnyResourceProviderKeyLookupService = (await PermissionAppService.GetResourceProviderKeyLookupServicesAsync(ResourceName)).Providers.Count > 0; + } + return Page(); + } + + public virtual Task OnPostAsync() + { + return Task.FromResult(NoContent()); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml new file mode 100644 index 0000000000..3e90319e02 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml @@ -0,0 +1,42 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.Abp.Localization +@using Volo.Abp.PermissionManagement.Localization +@using Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement +@model UpdateResourcePermissionManagementModal +@inject IHtmlLocalizer L + +@{ + Layout = null; +} + + + + +
+ + + + + + + +
+

@L["ResourcePermissionPermissions"]

+
+ + +
+ @foreach (var permission in Model.ResourcePermissions.Permissions) + { +
+ + +
+ } +
+
+ +
+
diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml.cs new file mode 100644 index 0000000000..db2e661993 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/UpdateResourcePermissionManagementModal.cshtml.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement; + +public class UpdateResourcePermissionManagementModal : AbpPageModel +{ + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceName { get; set; } + + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ResourceKey { get; set; } + + [BindProperty(SupportsGet = true)] + public string ResourceDisplayName { get; set; } + + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ProviderName { get; set; } + + [Required] + [HiddenInput] + [BindProperty(SupportsGet = true)] + public string ProviderKey { get; set; } + + [BindProperty(SupportsGet = true)] + public ResourcePermissionViewModel UpdateModel { get; set; } + + public GetResourcePermissionWithProviderListResultDto ResourcePermissions { get; set; } + + protected IPermissionAppService PermissionAppService { get; } + + public UpdateResourcePermissionManagementModal(IPermissionAppService permissionAppService) + { + ObjectMapperContext = typeof(AbpPermissionManagementWebModule); + + PermissionAppService = permissionAppService; + } + + public virtual async Task OnGetAsync() + { + ValidateModel(); + + ResourcePermissions = await PermissionAppService.GetResourceByProviderAsync(ResourceName, ResourceKey, ProviderName, ProviderKey); + + return Page(); + } + + public virtual async Task OnPostAsync() + { + ValidateModel(); + + await PermissionAppService.UpdateResourceAsync( + ResourceName, + ResourceKey, + new UpdateResourcePermissionsDto() + { + ProviderName = ProviderName, + ProviderKey = ProviderKey, + Permissions = UpdateModel.Permissions ?? new List() + } + ); + + return NoContent(); + } + + public class ResourcePermissionViewModel + { + public List Permissions { get; set; } + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/add-resource-permission-management-modal.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/add-resource-permission-management-modal.js new file mode 100644 index 0000000000..2fa7f06550 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/add-resource-permission-management-modal.js @@ -0,0 +1,91 @@ +var abp = abp || {}; +(function ($) { + var $all = $("#grantAllresourcePermissions"); + var $items = $("#permissionList input[type='checkbox']").not("#grantAllresourcePermissions"); + $all.on("change", function () { + $items.prop("checked", this.checked); + }); + $items.on("change", function () { + $all.prop("checked", $items.length === $items.filter(":checked").length); + }); + + var $permissionManagementForm = $("#addResourcePermissionManagementForm"); + var $providerKey = $("#AddModel_ProviderKey"); + $providerKey.select2({ + ajax: { + url: '/api/permission-management/permissions/search-resource-provider-keys', + delay: 250, + dataType: "json", + data: function (params) { + var query = {}; + query["resourceName"] = $('#ResourceName').val(); + query["serviceName"] = $('input[name="AddModel.ProviderName"]:checked').val(); + query["page"] = params.page || 1; + query["filter"] = params.term; + return query; + }, + processResults: function (data) { + var keyValues = []; + data.keys.forEach(function (item, index) { + keyValues.push({ + id: item["providerKey"], + text: item["providerDisplayName"], + displayName: item["providerDisplayName"] + }) + }); + return { + results: keyValues, + pagination: { + more: keyValues.length == 10 + } + }; + } + }, + width: '100%', + dropdownParent: $('#addResourcePermissionManagementModal'), + language: abp.localization.currentCulture.cultureName + }); + + $('input[name="AddModel.ProviderName"]').change(function () { + $providerKey.val(null).trigger('change'); + }); + + $providerKey.change(function () { + if ($providerKey.val()) { + $permissionManagementForm.valid(); + } + var providerKey = $providerKey.val(); + if (!providerKey) { + $items.prop('checked', false); + $all.prop("checked", false); + return; + } + + abp.ui.setBusy('#permissionList'); + var resourceName = $("#ResourceName").val(); + var resourceKey = $("#ResourceKey").val(); + var providerName = $('input[name="AddModel.ProviderName"]:checked').val(); + volo.abp.permissionManagement.permissions.getResourceByProvider(resourceName, resourceKey, providerName, providerKey).then(function (result) { + abp.ui.clearBusy(); + var grantedPermissionNames = result.permissions.filter(function (p) { + return p.providers.indexOf(providerName) >= 0 && p.isGranted === true; + }).map(function (p) { + return p.name; + }); + $items.each(function () { + var $checkbox = $(this); + if (grantedPermissionNames.indexOf($checkbox.val()) >= 0) { + $checkbox.prop('checked', true); + } else { + $checkbox.prop('checked', false); + } + }); + $all.prop("checked", $items.length === $items.filter(":checked").length); + }); + }); + + $permissionManagementForm.submit(function () { + $(this).valid(); + }); + +})(jQuery); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/resource-permission-management-modal.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/resource-permission-management-modal.js new file mode 100644 index 0000000000..7a6c100c07 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/resource-permission-management-modal.js @@ -0,0 +1,131 @@ +var abp = abp || {}; +(function ($) { + var l = abp.localization.getResource('AbpPermissionManagement'); + var _dataTable = null; + abp.ui.extensions.entityActions.get('permissionManagement.resource').addContributor( + function (actionList) { + return actionList.addManyTail( + [ + { + text: l('Edit'), + action: function (data) { + var _updateResourcePermissionsModal = new abp.ModalManager(abp.appPath + "AbpPermissionManagement/UpdateResourcePermissionManagementModal"); + _updateResourcePermissionsModal.open({ + resourceName: $("#ResourceName").val(), + resourceKey: $("#ResourceKey").val(), + resourceDisplayName: $("#ResourceDisplayName").val(), + providerName: data.record.providerName, + providerKey: data.record.providerKey + }); + _updateResourcePermissionsModal.onResult(function () { + _dataTable.ajax.reloadEx(function (json) { + _dataTable.columns.adjust(); + }); + }); + }, + }, + { + text: l('Delete'), + confirmMessage: function (data) { + return l( + 'ResourcePermissionDeletionConfirmationMessage', + data.record.name + ); + }, + action: function (data) { + volo.abp.permissionManagement.permissions.deleteResource($("#ResourceName").val(), $("#ResourceKey").val(), data.record.providerName, data.record.providerKey).then(function () { + abp.notify.info(l('DeletedSuccessfully')); + _dataTable.ajax.reloadEx(function (json) { + _dataTable.columns.adjust(); + }); + }); + }, + } + ] + ); + } + ); + + abp.ui.extensions.tableColumns.get('permissionManagement.resource').addContributor( + function (columnList) { + columnList.addManyTail( + [ + { + title: l("Actions"), + rowAction: { + items: abp.ui.extensions.entityActions.get('permissionManagement.resource').actions.toArray() + } + }, + { + title: l("ResourcePermissionTarget"), + data: 'providerName', + render: function (data, type, row) { + return '' + row.providerName + '' + row.providerDisplayName; + }, + }, + { + title: l("ResourcePermissionPermissions"), + data: 'permissions', + render: function (data, type, row) { + var spans = ''; + for (var i = 0; i < row.permissions.length; i++) { + spans += '' + row.permissions[i].displayName + ''; + } + return spans; + }, + } + ] + ); + }, + 0 //adds as the first contributor + ); + + abp.modals = abp.modals || {}; + + abp.modals.ResourcePermissionManagement = function () { + var initModal = function (publicApi, args) { + _dataTable = $('#resourcePermissionTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + order: [], + searching: false, + processing: true, + scrollX: false, + serverSide: false, + paging: true, + ajax: function () { + return function (requestData, callback, settings) { + if (callback) { + volo.abp.permissionManagement.permissions.getResource(args.resourceName, args.resourceKey).then(function (result) { + callback({ + recordsTotal: result.permissions.length, + recordsFiltered: result.permissions.length, + data: result.permissions + }); + }); + } + } + }(), + columnDefs: abp.ui.extensions.tableColumns.get('permissionManagement.resource').columns.toArray(), + }) + ); + + $("#addPermission").click(function () { + var _addResourcePermissionsModal = new abp.ModalManager(abp.appPath + "AbpPermissionManagement/AddResourcePermissionManagementModal"); + _addResourcePermissionsModal.open({ + resourceName: $("#ResourceName").val(), + resourceKey: $("#ResourceKey").val(), + resourceDisplayName: $("#ResourceDisplayName").val() + }); + _addResourcePermissionsModal.onResult(function () { + _dataTable.ajax.reloadEx(function (json) { + _dataTable.columns.adjust(); + }); + }); + }); + }; + + return { + initModal: initModal, + }; + }; +})(jQuery); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/update-resource-permission-management-modal.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/update-resource-permission-management-modal.js new file mode 100644 index 0000000000..d1e1f02fa4 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/update-resource-permission-management-modal.js @@ -0,0 +1,11 @@ +var abp = abp || {}; +(function ($) { + var $all = $("#grantAllresourcePermissions"); + var $items = $("#permissionList input[type='checkbox']").not("#grantAllresourcePermissions"); + $all.on("change", function () { + $items.prop("checked", this.checked); + }); + $items.on("change", function () { + $all.prop("checked", $items.length === $items.filter(":checked").length); + }); +})(jQuery); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js index a296877917..893c86ab97 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/wwwroot/client-proxies/permissionManagement-proxy.js @@ -34,6 +34,58 @@ }, ajaxParams)); }; + volo.abp.permissionManagement.permissions.getResourceProviderKeyLookupServices = function(resourceName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource-provider-key-lookup-services' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.searchResourceProviderKey = function(resourceName, serviceName, filter, page, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/search-resource-provider-keys' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }, { name: 'serviceName', value: serviceName }, { name: 'filter', value: filter }, { name: 'page', value: page }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.getResourceDefinitions = function(resourceName, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource-definitions' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.getResource = function(resourceName, resourceKey, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }, { name: 'resourceKey', value: resourceKey }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.getResourceByProvider = function(resourceName, resourceKey, providerName, providerKey, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource/by-provider' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }, { name: 'resourceKey', value: resourceKey }, { name: 'providerName', value: providerName }, { name: 'providerKey', value: providerKey }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.updateResource = function(resourceName, resourceKey, input, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }, { name: 'resourceKey', value: resourceKey }]) + '', + type: 'PUT', + dataType: null, + data: JSON.stringify(input) + }, ajaxParams)); + }; + + volo.abp.permissionManagement.permissions.deleteResource = function(resourceName, resourceKey, providerName, providerKey, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/permission-management/permissions/resource' + abp.utils.buildQueryString([{ name: 'resourceName', value: resourceName }, { name: 'resourceKey', value: resourceKey }, { name: 'providerName', value: providerName }, { name: 'providerKey', value: providerKey }]) + '', + type: 'DELETE', + dataType: null + }, ajaxParams)); + }; + })(); })(); diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementApplicationTestModule.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementApplicationTestModule.cs index a5e8461a28..e43cc0fa71 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementApplicationTestModule.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementApplicationTestModule.cs @@ -22,6 +22,7 @@ public class AbpPermissionManagementApplicationTestModule : AbpModule options.ProviderPolicies[UserPermissionValueProvider.ProviderName] = UserPermissionValueProvider.ProviderName; options.ProviderPolicies["Test"] = "Test"; options.ManagementProviders.Add(); + options.ResourceManagementProviders.Add(); }); } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs index 11e9e8ca04..61f984a27b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs @@ -32,34 +32,39 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest permissionListResultDto.ShouldNotBeNull(); permissionListResultDto.EntityDisplayName.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); - permissionListResultDto.Groups.Count.ShouldBe(2); + + permissionListResultDto.Groups.Count.ShouldBe(3); permissionListResultDto.Groups.ShouldContain(x => x.Name == "TestGroup"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission1"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission2"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission2.ChildPermission1"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission3"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission4"); + var testGroup = permissionListResultDto.Groups.FirstOrDefault(g => g.Name == "TestGroup"); + testGroup.ShouldNotBeNull(); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission1"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission2"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission2.ChildPermission1"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission3"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission4"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyPermission5"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyPermission5.ChildPermission1"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyPermission5"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyPermission5.ChildPermission1"); using (_currentPrincipalAccessor.Change(new Claim(AbpClaimTypes.Role, "super-admin"))) { var result = await _permissionAppService.GetAsync(UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()); - result.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission5"); - result.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission5.ChildPermission1"); + var testGroupWithRole = result.Groups.FirstOrDefault(g => g.Name == "TestGroup"); + testGroupWithRole.ShouldNotBeNull(); + testGroupWithRole.Permissions.ShouldContain(x => x.Name == "MyPermission5"); + testGroupWithRole.Permissions.ShouldContain(x => x.Name == "MyPermission5.ChildPermission1"); } - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission6"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyPermission6.ChildDisabledPermission1"); - permissionListResultDto.Groups.First().Permissions.ShouldContain(x => x.Name == "MyPermission6.ChildPermission2"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission6"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyPermission6.ChildDisabledPermission1"); + testGroup.Permissions.ShouldContain(x => x.Name == "MyPermission6.ChildPermission2"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission1"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission1"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission2"); - permissionListResultDto.Groups.First().Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission2.ChildPermission1"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission1"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission1"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission2"); + testGroup.Permissions.ShouldNotContain(x => x.Name == "MyDisabledPermission2.ChildPermission2.ChildPermission1"); } [Fact] diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/CalculateHash_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/CalculateHash_Tests.cs index 2e862c8f85..cfec0d27a2 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/CalculateHash_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/CalculateHash_Tests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization.Metadata; using Shouldly; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Json.SystemTextJson.Modifiers; using Xunit; @@ -34,7 +35,7 @@ public class CalculateHash_Tests: PermissionTestBase json.ShouldNotContain(id.ToString("D")); json = JsonSerializer.Serialize(new List() { - new PermissionDefinitionRecord(id, "Test", "Test", "Test", "Test") + new PermissionDefinitionRecord(id, "Test", "Test", "Test", "Test", "Test", "Test") }, jsonSerializerOptions); json.ShouldNotContain("\"Id\""); diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionRecordRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionRecordRepository_Tests.cs index d7ca406624..62369869c4 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionRecordRepository_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionRecordRepository_Tests.cs @@ -26,4 +26,19 @@ public abstract class PermissionDefinitionRecordRepository_Tests permission.ShouldNotBeNull(); permission.Name.ShouldBe("MyPermission2"); } + + [Fact] + public async Task FindByResourceNameAsync() + { + var qq = await PermissionDefinitionRecordRepository.GetListAsync(); + var permission = await PermissionDefinitionRecordRepository.FindByNameAsync("MyResourcePermission1"); + permission.ShouldNotBeNull(); + permission.ResourceName.ShouldBe(TestEntityResource.ResourceName); + permission.Name.ShouldBe("MyResourcePermission1"); + + permission = await PermissionDefinitionRecordRepository.FindByNameAsync("MyResourcePermission2"); + permission.ShouldNotBeNull(); + permission.ResourceName.ShouldBe(TestEntityResource.ResourceName); + permission.Name.ShouldBe("MyResourcePermission2"); + } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index 1e7c04580c..4dca621a63 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.PermissionManagement; public class PermissionDefinitionSerializer_Tests : PermissionTestBase { private readonly IPermissionDefinitionSerializer _serializer; - + public PermissionDefinitionSerializer_Tests() { _serializer = GetRequiredService(); @@ -26,26 +26,26 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase public async Task Serialize_Permission_Group_Definition() { // Arrange - + var context = new PermissionDefinitionContext(null); var group1 = CreatePermissionGroup1(context); - + // Act var permissionGroupRecord = await _serializer.SerializeAsync(group1); - + //Assert permissionGroupRecord.Name.ShouldBe("Group1"); permissionGroupRecord.DisplayName.ShouldBe("F:Group one"); permissionGroupRecord.GetProperty("CustomProperty1").ShouldBe("CustomValue1"); } - + [Fact] public async Task Serialize_Complex_Permission_Definition() { // Arrange - + var context = new PermissionDefinitionContext(null); var group1 = CreatePermissionGroup1(context); var permission1 = group1.AddPermission( @@ -61,14 +61,14 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase .RequirePermissions(requiresAll: false, batchCheck: false,"Permission2", "Permission3"); // Act - + var permissionRecord = await _serializer.SerializeAsync( permission1, group1 ); - + //Assert - + permissionRecord.Name.ShouldBe("Permission1"); permissionRecord.GroupName.ShouldBe("Group1"); permissionRecord.DisplayName.ShouldBe("L:AbpPermissionManagement,Permission1"); @@ -78,6 +78,48 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]},{\"T\":\"P\",\"A\":false,\"N\":[\"Permission2\",\"Permission3\"]}]"); } + + [Fact] + public async Task Serialize_Complex_Resource_Permission_Definition() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var resourcePermission1 = context.AddResourcePermission( + "ResourcePermission1", + TestEntityResource.ResourceName, + "Permission1", + new LocalizableString(typeof(AbpPermissionManagementResource), "ResourcePermission1"), + MultiTenancySides.Tenant + ) + .WithProviders("ProviderA", "ProviderB") + .WithProperty("CustomProperty2", "CustomValue2") + .RequireAuthenticated() //For for testing, not so meaningful + .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2") + .RequireFeatures("Feature1", "Feature2") + .RequirePermissions(requiresAll: false, batchCheck: false,"Permission2", "Permission3"); + + // Act + + var permissionRecord = await _serializer.SerializeAsync( + resourcePermission1, + null + ); + + //Assert + + permissionRecord.Name.ShouldBe("ResourcePermission1"); + permissionRecord.GroupName.ShouldBe(null); + permissionRecord.ResourceName.ShouldBe(TestEntityResource.ResourceName); + permissionRecord.ManagementPermissionName.ShouldBe("Permission1"); + permissionRecord.DisplayName.ShouldBe("L:AbpPermissionManagement,ResourcePermission1"); + permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); + permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); + permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); + permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]},{\"T\":\"P\",\"A\":false,\"N\":[\"Permission2\",\"Permission3\"]}]"); + } + + private static PermissionGroupDefinition CreatePermissionGroup1( IPermissionDefinitionContext context) { @@ -85,9 +127,9 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase "Group1", displayName: new FixedLocalizableString("Group one") ); - + group["CustomProperty1"] = "CustomValue1"; - + return group; } -} \ No newline at end of file +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_Basic_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_Basic_Tests.cs new file mode 100644 index 0000000000..81ba38f7f9 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_Basic_Tests.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions.Resources; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionChecker_Basic_Tests : PermissionTestBase +{ + private readonly IResourcePermissionChecker _resourcePermissionChecker; + + public ResourcePermissionChecker_Basic_Tests() + { + _resourcePermissionChecker = GetRequiredService(); + } + + [Fact] + public async Task Should_Return_Prohibited_If_Permission_Is_Not_Defined() + { + (await _resourcePermissionChecker.IsGrantedAsync(TestEntityResource.ResourceName, TestEntityResource.ResourceKey1,"UndefinedResourcePermissionName")).ShouldBeFalse(); + } + + [Fact] + public async Task Should_Return_False_As_Default_For_Any_Permission() + { + (await _resourcePermissionChecker.IsGrantedAsync(TestEntityResource.ResourceName, TestEntityResource.ResourceKey1,"MyPermission1")).ShouldBeFalse(); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_User_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_User_Tests.cs new file mode 100644 index 0000000000..261b5136d2 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionChecker_User_Tests.cs @@ -0,0 +1,121 @@ +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionChecker_User_Tests : PermissionTestBase +{ + private readonly IResourcePermissionChecker _resourcePermissionChecker; + private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; + + public ResourcePermissionChecker_User_Tests() + { + _resourcePermissionChecker = GetRequiredService(); + _currentPrincipalAccessor = GetRequiredService(); + } + + [Fact] + public async Task Should_Return_True_For_Granted_Current_User() + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User1Id), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1 + )).ShouldBeTrue(); + } + + [Fact] + public async Task Should_Return_False_For_Non_Granted_Current_User() + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User2Id), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1 + )).ShouldBeFalse(); + } + + + [Fact] + public async Task Should_Return_False_For_Granted_Current_User_If_The_Permission_Is_Disabled() + { + //Disabled permissions always returns false! + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User1Id), + "MyDisabledPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1 + )).ShouldBeFalse(); + } + + [Fact] + public async Task Should_Return_False_For_Current_User_If_Anonymous() + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(null), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1 + )).ShouldBeFalse(); + } + + [Fact] + public async Task Should_Not_Allow_Host_Permission_To_Tenant_User_Even_Granted_Before() + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User1Id, Guid.NewGuid()), + "MyResourcePermission3", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3 + )).ShouldBeFalse(); + } + + [Fact] + public async Task Should_Return_False_For_Granted_Current_User_If_The_Permission_State_Is_Disabled() + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User1Id, Guid.NewGuid()), + "MyResourcePermission5", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey5 + )).ShouldBeFalse(); + } + + [Fact] + public async Task Should_Return_True_For_Granted_Current_User_If_The_Permission_State_Is_Enabled() + { + using (_currentPrincipalAccessor.Change(new Claim(AbpClaimTypes.Role, "super-admin"))) + { + (await _resourcePermissionChecker.IsGrantedAsync( + CreatePrincipal(PermissionTestDataBuilder.User1Id, Guid.NewGuid()), + "MyResourcePermission5", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey5 + )).ShouldBeTrue(); + } + } + + private static ClaimsPrincipal CreatePrincipal(Guid? userId, Guid? tenantId = null) + { + var claimsIdentity = new ClaimsIdentity(); + + if (userId != null) + { + claimsIdentity.AddClaim(new Claim(AbpClaimTypes.UserId, userId.ToString())); + } + + if (tenantId != null) + { + claimsIdentity.AddClaim(new Claim(AbpClaimTypes.TenantId, tenantId.ToString())); + } + + return new ClaimsPrincipal(claimsIdentity); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator_Tests.cs new file mode 100644 index 0000000000..3bdc4ee69e --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItemInvalidator_Tests.cs @@ -0,0 +1,69 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Caching; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionGrantCacheItemInvalidator_Tests : PermissionTestBase +{ + private readonly IDistributedCache _cache; + private readonly IResourcePermissionStore _resourcePermissionStore; + private readonly IResourcePermissionGrantRepository _resourcePermissionGrantRepository; + + public ResourcePermissionGrantCacheItemInvalidator_Tests() + { + _cache = GetRequiredService>(); + _resourcePermissionStore = GetRequiredService(); + _resourcePermissionGrantRepository = GetRequiredService(); + } + + [Fact] + public async Task PermissionStore_IsGrantedAsync_Should_Cache_PermissionGrant() + { + (await _cache.GetAsync(ResourcePermissionGrantCacheItem.CalculateCacheKey("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()))).ShouldBeNull(); + + await _resourcePermissionStore.IsGrantedAsync("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + (await _cache.GetAsync(ResourcePermissionGrantCacheItem.CalculateCacheKey("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()))).ShouldNotBeNull(); + } + + [Fact] + public async Task Cache_Should_Invalidator_WhenPermissionGrantChanged() + { + // IsGrantedAsync will cache ResourcePermissionGrant + await _resourcePermissionStore.IsGrantedAsync("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + var resourcePermissionGrant = await _resourcePermissionGrantRepository.FindAsync("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + resourcePermissionGrant.ShouldNotBeNull(); + await _resourcePermissionGrantRepository.DeleteAsync(resourcePermissionGrant); + + (await _cache.GetAsync(ResourcePermissionGrantCacheItem.CalculateCacheKey("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()))).ShouldBeNull(); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem_Tests.cs new file mode 100644 index 0000000000..1d7b4ea12d --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionGrantCacheItem_Tests.cs @@ -0,0 +1,15 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionGrantCacheItem_Tests +{ + [Fact] + public void GetPermissionNameFormCacheKeyOrNull() + { + var key = ResourcePermissionGrantCacheItem.CalculateCacheKey("aaa", TestEntityResource.ResourceName, TestEntityResource.ResourceKey1,"bbb", "ccc"); + ResourcePermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull(key).ShouldBe("aaa"); + ResourcePermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull("aaabbbccc").ShouldBeNull(); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider_Tests.cs new file mode 100644 index 0000000000..9651c3f313 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider_Tests.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionManagementProvider_Tests : PermissionTestBase +{ + private readonly IResourcePermissionManagementProvider _resourcePermissionManagementProvider; + private readonly IResourcePermissionGrantRepository _resourcePermissionGrantRepository; + + public ResourcePermissionManagementProvider_Tests() + { + _resourcePermissionManagementProvider = GetRequiredService(); + _resourcePermissionGrantRepository = GetRequiredService(); + } + + [Fact] + public async Task CheckAsync() + { + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + Guid.NewGuid(), + "MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test" + ) + ); + + var permissionValueProviderGrantInfo = await _resourcePermissionManagementProvider.CheckAsync( + "MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + permissionValueProviderGrantInfo.IsGranted.ShouldBeTrue(); + permissionValueProviderGrantInfo.ProviderKey.ShouldBe("Test"); + } + + [Fact] + public async Task Check_Should_Return_NonGranted_When_ProviderName_NotEquals_Name() + { + var permissionValueProviderGrantInfo = await _resourcePermissionManagementProvider.CheckAsync( + "MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "TestNotExist", + "Test"); + + permissionValueProviderGrantInfo.IsGranted.ShouldBeFalse(); + permissionValueProviderGrantInfo.ProviderKey.ShouldBeNull(); + } + + [Fact] + public async Task SetAsync() + { + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + Guid.NewGuid(), + "MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test" + ) + ); + (await _resourcePermissionGrantRepository.FindAsync("MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test")).ShouldNotBeNull(); + + await _resourcePermissionManagementProvider.SetAsync("MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + false); + + (await _resourcePermissionGrantRepository.FindAsync("MyPermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test")).ShouldBeNull(); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManager_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManager_Tests.cs new file mode 100644 index 0000000000..73d37a5ff3 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManager_Tests.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionManager_Tests : PermissionTestBase +{ + private readonly IResourcePermissionManager _resourcePermissionManager; + private readonly IResourcePermissionGrantRepository _resourcePermissionGrantRepository; + + public ResourcePermissionManager_Tests() + { + _resourcePermissionManager = GetRequiredService(); + _resourcePermissionGrantRepository = GetRequiredService(); + } + + [Fact] + public async Task GetProviderKeyLookupServicesAsync() + { + var permissionProviderKeyLookupServices = await _resourcePermissionManager.GetProviderKeyLookupServicesAsync(); + + permissionProviderKeyLookupServices.ShouldNotBeNull(); + permissionProviderKeyLookupServices.First().Name.ShouldBe("Test"); + } + + [Fact] + public async Task GetProviderKeyLookupServiceAsync() + { + var testProviderKeyLookupService = await _resourcePermissionManager.GetProviderKeyLookupServiceAsync("Test"); + testProviderKeyLookupService.ShouldNotBeNull(); + testProviderKeyLookupService.Name.ShouldBe("Test"); + + var exception = await Assert.ThrowsAsync(async () => + { + await _resourcePermissionManager.GetProviderKeyLookupServiceAsync("UndefinedProvider"); + }); + exception.Message.ShouldBe("Unknown resource permission provider key lookup service: UndefinedProvider"); + } + + [Fact] + public async Task GetAvailablePermissionsAsync() + { + var availablePermissions = await _resourcePermissionManager.GetAvailablePermissionsAsync(TestEntityResource.ResourceName); + + availablePermissions.ShouldNotBeNull(); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission1"); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission2"); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission3"); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission4"); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission6"); + availablePermissions.ShouldContain(p => p.Name == "MyResourcePermission7"); + + availablePermissions.ShouldNotContain(p => p.Name == "MyResourcePermission5"); + availablePermissions.ShouldNotContain(p => p.Name == "MyResourceDisabledPermission1"); + availablePermissions.ShouldNotContain(p => p.Name == "MyResourceDisabledPermission2"); + } + + [Fact] + public async Task GetAsync() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + + var grantedProviders = await _resourcePermissionManager.GetAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + grantedProviders.ShouldNotBeNull(); + grantedProviders.IsGranted.ShouldBeTrue(); + grantedProviders.Name.ShouldBe("MyResourcePermission1"); + grantedProviders.Providers.ShouldContain(x => x.Key == "Test"); + } + + [Fact] + public async Task Multiple_GetAsync() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission2", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + + var grantedProviders = await _resourcePermissionManager.GetAsync( + new[] { "MyResourcePermission1", "MyResourcePermission2" }, + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + grantedProviders.Result.Count.ShouldBe(2); + grantedProviders.Result.First().IsGranted.ShouldBeTrue(); + grantedProviders.Result.First().Name.ShouldBe("MyResourcePermission1"); + grantedProviders.Result.First().Providers.ShouldContain(x => x.Key == "Test"); + + grantedProviders.Result.Last().IsGranted.ShouldBeTrue(); + grantedProviders.Result.Last().Name.ShouldBe("MyResourcePermission2"); + grantedProviders.Result.Last().Providers.ShouldContain(x => x.Key == "Test"); + } + + [Fact] + public async Task Get_Should_Return_Not_Granted_When_Permission_Undefined() + { + var result = await _resourcePermissionManager.GetAsync( + "MyResourcePermission1NotExist", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1,"Test", "Test"); + result.Name.ShouldBe("MyResourcePermission1NotExist"); + result.Providers.ShouldBeEmpty(); + result.IsGranted.ShouldBeFalse(); + } + + [Fact] + public async Task GetAllAsync() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission2", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + + var permissionWithGrantedProviders = await _resourcePermissionManager.GetAllAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + permissionWithGrantedProviders.ShouldNotBeNull(); + permissionWithGrantedProviders.ShouldContain(x => + x.IsGranted && x.Name == "MyResourcePermission1" && x.Providers.Any(p => p.Key == "Test")); + permissionWithGrantedProviders.ShouldContain(x => + x.IsGranted && x.Name == "MyResourcePermission2" && x.Providers.Any(p => p.Key == "Test")); + + + permissionWithGrantedProviders = await _resourcePermissionManager.GetAllAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1); + + permissionWithGrantedProviders.ShouldNotBeNull(); + permissionWithGrantedProviders.ShouldContain(x => x.IsGranted && x.Name == "MyResourcePermission1" && x.Providers.Any(p => p.Key == "Test")); + permissionWithGrantedProviders.ShouldContain(x => x.IsGranted && x.Name == "MyResourcePermission2" && x.Providers.Any(p => p.Key == "Test")); + + permissionWithGrantedProviders.ShouldNotContain(x => x.Name == "MyResourcePermission5"); // Not available permission + + permissionWithGrantedProviders.ShouldContain(x => !x.IsGranted && x.Name == "MyResourcePermission3" && x.Providers.Count == 0); + permissionWithGrantedProviders.ShouldContain(x => !x.IsGranted && x.Name == "MyResourcePermission4" && x.Providers.Count == 0); + permissionWithGrantedProviders.ShouldContain(x => !x.IsGranted && x.Name == "MyResourcePermission6" && x.Providers.Count == 0); + permissionWithGrantedProviders.ShouldContain(x => !x.IsGranted && x.Name == "MyResourcePermission7" && x.Providers.Count == 0); + permissionWithGrantedProviders.ShouldContain(x => !x.IsGranted && x.Name == "MyResourcePermission8" && x.Providers.Count == 0); + } + + [Fact] + public async Task GetAllGroupAsync() + { + var group = await _resourcePermissionManager.GetAllGroupAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1); + + group.ShouldNotBeNull(); + group.Count.ShouldBe(1); + group.First().ProviderName.ShouldBe(UserResourcePermissionValueProvider.ProviderName); + group.First().ProviderKey.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); + group.First().Permissions.Count.ShouldBe(1); + group.First().Permissions.ShouldContain(x => x == "MyResourcePermission1"); + + group = await _resourcePermissionManager.GetAllGroupAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3); + + group.ShouldNotBeNull(); + group.Count.ShouldBe(1); + group.First().ProviderName.ShouldBe(UserResourcePermissionValueProvider.ProviderName); + group.First().ProviderKey.ShouldBe(PermissionTestDataBuilder.User1Id.ToString()); + group.First().Permissions.Count.ShouldBe(2); + group.First().Permissions.ShouldContain(x => x == "MyResourcePermission3"); + group.First().Permissions.ShouldContain(x => x == "MyResourcePermission6"); + } + + [Fact] + public async Task Set_Should_Silently_Ignore_When_Permission_Undefined() + { + await _resourcePermissionManager.SetAsync( + "MyResourcePermission1NotExist", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test", + true); + } + + [Fact] + public async Task Set_Should_Throw_Exception_If_Provider_Not_Found() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _resourcePermissionManager.SetAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "UndefinedProvider", + "Test", + true); + }); + + exception.Message.ShouldBe("Unknown resource permission management provider: UndefinedProvider"); + } + + [Fact] + public async Task UpdateProviderKey() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + var permissionGrant = await _resourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + permissionGrant.ProviderKey.ShouldBe("Test"); + + await _resourcePermissionManager.UpdateProviderKeyAsync(permissionGrant, "NewProviderKey"); + (await _resourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "NewProviderKey")).ShouldNotBeNull(); + } + + [Fact] + public async Task DeleteAsync() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + var permissionGrant = await _resourcePermissionGrantRepository.FindAsync("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + permissionGrant.ProviderKey.ShouldBe("Test"); + + await _resourcePermissionManager.DeleteAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + (await _resourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test")).ShouldBeNull(); + } + + [Fact] + public async Task DeleteByProviderAsync() + { + await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant( + Guid.NewGuid(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test") + ); + + var permissionGrant = await _resourcePermissionGrantRepository.FindAsync("MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test"); + + permissionGrant.ProviderKey.ShouldBe("Test"); + + await _resourcePermissionManager.DeleteAsync( + "Test", + "Test"); + + (await _resourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Test", + "Test")).ShouldBeNull(); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionStore_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionStore_Tests.cs new file mode 100644 index 0000000000..34e6f89c0c --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionStore_Tests.cs @@ -0,0 +1,119 @@ +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionStore_Tests : PermissionTestBase +{ + private readonly IResourcePermissionStore _resourcePermissionStore; + + public ResourcePermissionStore_Tests() + { + _resourcePermissionStore = GetRequiredService(); + } + + [Fact] + public async Task IsGrantedAsync() + { + (await _resourcePermissionStore.IsGrantedAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString())).ShouldBeTrue(); + + (await _resourcePermissionStore.IsGrantedAsync( + "MyPermission1NotExist", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString())).ShouldBeFalse(); + } + + [Fact] + public async Task IsGranted_Multiple() + { + var result = await _resourcePermissionStore.IsGrantedAsync( + new[] { "MyResourcePermission1", "MyResourcePermission1NotExist" }, + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + result.Result.Count.ShouldBe(2); + + result.Result.FirstOrDefault(x => x.Key == "MyResourcePermission1").Value.ShouldBe(PermissionGrantResult.Granted); + result.Result.FirstOrDefault(x => x.Key == "MyResourcePermission1NotExist").Value.ShouldBe(PermissionGrantResult.Undefined); + } + + + [Fact] + public async Task GetPermissionsAsync() + { + var permissions = await _resourcePermissionStore.GetPermissionsAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1); + + permissions.Result.Count.ShouldBe(10); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission1" && p.Value == PermissionGrantResult.Granted); + permissions.Result.ShouldContain(p => p.Key == "MyResourceDisabledPermission1" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission2" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission3" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission4" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission5" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission6" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourceDisabledPermission2" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission7" && p.Value == PermissionGrantResult.Undefined); + permissions.Result.ShouldContain(p => p.Key == "MyResourcePermission8" && p.Value == PermissionGrantResult.Undefined); + + permissions = await _resourcePermissionStore.GetPermissionsAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey2); + permissions.Result.ShouldAllBe(x => x.Value == PermissionGrantResult.Undefined); + } + + [Fact] + public async Task GetGrantedPermissionsAsync() + { + var grantedPermissions = await _resourcePermissionStore.GetGrantedPermissionsAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1); + + grantedPermissions.Length.ShouldBe(1); + grantedPermissions.ShouldContain("MyResourcePermission1"); + + grantedPermissions = await _resourcePermissionStore.GetGrantedPermissionsAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3); + + grantedPermissions.Length.ShouldBe(3); + grantedPermissions.ShouldContain("MyResourcePermission3"); + grantedPermissions.ShouldContain("MyResourcePermission5"); + grantedPermissions.ShouldContain("MyResourcePermission6"); + + } + + + [Fact] + public async Task GetGrantedResourceKeysAsync() + { + var grantedResourceKeys = await _resourcePermissionStore.GetGrantedResourceKeysAsync( + TestEntityResource.ResourceName, + "MyResourcePermission1"); + + grantedResourceKeys.Length.ShouldBe(1); + grantedResourceKeys.ShouldContain(TestEntityResource.ResourceKey1); + + grantedResourceKeys = await _resourcePermissionStore.GetGrantedResourceKeysAsync( + TestEntityResource.ResourceName, + "MyResourcePermission5"); + + grantedResourceKeys.Length.ShouldBe(2); + grantedResourceKeys.ShouldContain(TestEntityResource.ResourceKey3); + grantedResourceKeys.ShouldContain(TestEntityResource.ResourceKey5); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo/Abp/PermissionManagement/EntityFrameworkCore/ResourcePermissionGrantRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo/Abp/PermissionManagement/EntityFrameworkCore/ResourcePermissionGrantRepository_Tests.cs new file mode 100644 index 0000000000..89fdb9a9d4 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.EntityFrameworkCore.Tests/Volo/Abp/PermissionManagement/EntityFrameworkCore/ResourcePermissionGrantRepository_Tests.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class ResourcePermissionGrantRepository_Tests : ResourcePermissionGrantRepository_Tests +{ + +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbPermissionDefinitionRecordRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbPermissionDefinitionRecordRepository_Tests.cs index d43634cdb9..30f09c5720 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbPermissionDefinitionRecordRepository_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/MongoDbPermissionDefinitionRecordRepository_Tests.cs @@ -3,7 +3,7 @@ namespace Volo.Abp.PermissionManagement.MongoDB; [Collection(MongoTestCollection.Name)] -public class MongoDbPermissionDefinitionRecordRepository_Tests : PermissionGrantRepository_Tests +public class MongoDbPermissionDefinitionRecordRepository_Tests : PermissionDefinitionRecordRepository_Tests { } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/ResourcePermissionGrantRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/ResourcePermissionGrantRepository_Tests.cs new file mode 100644 index 0000000000..32240f998c --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.MongoDB.Tests/Volo/Abp/PermissionManagement/MongoDb/ResourcePermissionGrantRepository_Tests.cs @@ -0,0 +1,9 @@ +using Xunit; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +[Collection(MongoTestCollection.Name)] +public class ResourcePermissionGrantRepository_Tests : ResourcePermissionGrantRepository_Tests +{ + +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs index a6102a318e..88c6ea1d69 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs @@ -18,6 +18,8 @@ public class AbpPermissionManagementTestBaseModule : AbpModule context.Services.Configure(options => { options.ManagementProviders.Add(); + options.ResourceManagementProviders.Add(); + options.ResourcePermissionProviderKeyLookupServices.Add(); }); } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs index c60dff997a..d0448ea5bd 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionTestDataBuilder.cs @@ -12,12 +12,17 @@ public class PermissionTestDataBuilder : ITransientDependency public static Guid User2Id { get; } = Guid.NewGuid(); private readonly IPermissionGrantRepository _permissionGrantRepository; + private readonly IResourcePermissionGrantRepository _resourcePermissionGrantRepository; private readonly IGuidGenerator _guidGenerator; - public PermissionTestDataBuilder(IGuidGenerator guidGenerator, IPermissionGrantRepository permissionGrantRepository) + public PermissionTestDataBuilder( + IGuidGenerator guidGenerator, + IPermissionGrantRepository permissionGrantRepository, + IResourcePermissionGrantRepository resourcePermissionGrantRepository) { _guidGenerator = guidGenerator; _permissionGrantRepository = permissionGrantRepository; + _resourcePermissionGrantRepository = resourcePermissionGrantRepository; } public async Task BuildAsync() @@ -31,6 +36,15 @@ public class PermissionTestDataBuilder : ITransientDependency ) ); + await _permissionGrantRepository.InsertAsync( + new PermissionGrant( + _guidGenerator.Create(), + "TestEntityManagementPermission", + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + await _permissionGrantRepository.InsertAsync( new PermissionGrant( _guidGenerator.Create(), @@ -57,5 +71,71 @@ public class PermissionTestDataBuilder : ITransientDependency User1Id.ToString() ) ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyDisabledResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyResourcePermission3", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyResourcePermission5", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyResourcePermission6", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); + + await _resourcePermissionGrantRepository.InsertAsync( + new ResourcePermissionGrant( + _guidGenerator.Create(), + "MyResourcePermission5", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey5, + UserPermissionValueProvider.ProviderName, + User1Id.ToString() + ) + ); } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/ResourcePermissionGrantRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/ResourcePermissionGrantRepository_Tests.cs new file mode 100644 index 0000000000..90652683b1 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/ResourcePermissionGrantRepository_Tests.cs @@ -0,0 +1,121 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public abstract class ResourcePermissionGrantRepository_Tests : PermissionManagementTestBase + where TStartupModule : IAbpModule +{ + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected ResourcePermissionGrantRepository_Tests() + { + ResourcePermissionGrantRepository = GetRequiredService(); + } + + [Fact] + public async Task FindAsync() + { + (await ResourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString())).ShouldNotBeNull(); + + (await ResourcePermissionGrantRepository.FindAsync( + "Undefined-Permission", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString())).ShouldBeNull(); + + (await ResourcePermissionGrantRepository.FindAsync( + "MyResourcePermission1", + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1, + "Undefined-Provider", + "Unknown-Id")).ShouldBeNull(); + } + + [Fact] + public async Task GetList4Async() + { + var permissionGrants = + await ResourcePermissionGrantRepository.GetListAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission3"); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission5"); + } + + [Fact] + public async Task GetList5Async() + { + var permissionGrants = + await ResourcePermissionGrantRepository.GetListAsync( + new[] { "MyResourcePermission1", "MyResourcePermission3", "MyResourcePermission5" }, + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey3, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + permissionGrants.ShouldNotContain(p => p.Name == "MyResourcePermission1"); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission3"); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission5"); + } + + [Fact] + public async Task GetList2Async() + { + var permissionGrants = + await ResourcePermissionGrantRepository.GetListAsync( + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission1" && p.ResourceKey == TestEntityResource.ResourceKey1 && p.ResourceName == TestEntityResource.ResourceName); + permissionGrants.ShouldContain(p => p.Name == "MyDisabledResourcePermission1" && p.ResourceKey == TestEntityResource.ResourceKey1 && p.ResourceName == TestEntityResource.ResourceName); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission3" && p.ResourceKey == TestEntityResource.ResourceKey3 && p.ResourceName == TestEntityResource.ResourceName); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission5" && p.ResourceKey == TestEntityResource.ResourceKey3 && p.ResourceName == TestEntityResource.ResourceName); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission5" && p.ResourceKey == TestEntityResource.ResourceKey5 && p.ResourceName == TestEntityResource.ResourceName); + + permissionGrants = + await ResourcePermissionGrantRepository.GetListAsync( + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User2Id.ToString()); + + permissionGrants.ShouldBeEmpty(); + } + + [Fact] + public async Task GetPermissionsAsync() + { + var permissionGrants = + await ResourcePermissionGrantRepository.GetPermissionsAsync( + TestEntityResource.ResourceName, + TestEntityResource.ResourceKey1); + + permissionGrants.Count.ShouldBe(2); + permissionGrants.ShouldContain(p => p.Name == "MyResourcePermission1"); + permissionGrants.ShouldContain(p => p.Name == "MyDisabledResourcePermission1"); + } + + [Fact] + public async Task GetResourceKeys() + { + var permissionGrants = + await ResourcePermissionGrantRepository.GetResourceKeys( + TestEntityResource.ResourceName, + "MyResourcePermission5"); + + permissionGrants.Count.ShouldBe(2); + permissionGrants.ShouldContain(p => p.ResourceKey == TestEntityResource.ResourceKey3); + permissionGrants.ShouldContain(p => p.ResourceKey == TestEntityResource.ResourceKey5); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestEntityResource.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestEntityResource.cs new file mode 100644 index 0000000000..9f631b123d --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestEntityResource.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.PermissionManagement; + +public class TestEntityResource +{ + public static readonly string ResourceName = typeof(TestEntityResource).FullName; + + public static readonly string ResourceKey1 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey2 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey3 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey4 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey5 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey6 = Guid.NewGuid().ToString(); + public static readonly string ResourceKey7 = Guid.NewGuid().ToString(); +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionDefinitionProvider.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionDefinitionProvider.cs new file mode 100644 index 0000000000..2d5a4d5d99 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionDefinitionProvider.cs @@ -0,0 +1,28 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public class TestResourcePermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + context.AddGroup("TestEntityManagementPermissionGroup").AddPermission("TestEntityManagementPermission"); + + context.AddResourcePermission("MyResourcePermission1", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourceDisabledPermission1", TestEntityResource.ResourceName, "TestEntityManagementPermission", isEnabled: false); + context.AddResourcePermission("MyResourcePermission2", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission3", TestEntityResource.ResourceName, "TestEntityManagementPermission", multiTenancySide: MultiTenancySides.Host); + context.AddResourcePermission("MyResourcePermission4", TestEntityResource.ResourceName, "TestEntityManagementPermission", multiTenancySide: MultiTenancySides.Host).WithProviders(UserPermissionValueProvider.ProviderName); + + var myPermission5 = context.AddResourcePermission("MyResourcePermission5", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + myPermission5.StateCheckers.Add(new TestRequireRolePermissionStateProvider("super-admin")); + + context.AddResourcePermission("MyResourcePermission6", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + + context.AddResourcePermission("MyResourceDisabledPermission2", TestEntityResource.ResourceName, "TestEntityManagementPermission", isEnabled: false); + + context.AddResourcePermission("MyResourcePermission7", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + context.AddResourcePermission("MyResourcePermission8", TestEntityResource.ResourceName, "TestEntityManagementPermission"); + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionManagementProvider.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..e555c6133d --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionManagementProvider.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public class TestResourcePermissionManagementProvider : ResourcePermissionManagementProvider +{ + public override string Name => "Test"; + + public TestResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant) + : base( + resourcePermissionGrantRepository, + guidGenerator, + currentTenant) + { + + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionProviderKeyLookupService.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionProviderKeyLookupService.cs new file mode 100644 index 0000000000..f42a204f7a --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionProviderKeyLookupService.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace Volo.Abp.PermissionManagement; + +public class TestResourcePermissionProviderKeyLookupService : IResourcePermissionProviderKeyLookupService, ITransientDependency +{ + public string Name => "Test"; + + public ILocalizableString DisplayName => new LocalizableString("Test", "TestResource"); + + public Task> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default) + { + throw new System.NotImplementedException(); + } + + public Task> SearchAsync(string[] keys, CancellationToken cancellationToken = default) + { + throw new System.NotImplementedException(); + } +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs index afce2e0809..9aad8753f6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainModule.cs @@ -28,7 +28,7 @@ public class AbpTenantManagementDomainModule : AbpModule Configure(options => { - options.EtoMappings.Add(); + options.EtoMappings.Add(typeof(AbpTenantManagementDomainModule)); }); } diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IRoleData.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IRoleData.cs new file mode 100644 index 0000000000..37656f6588 --- /dev/null +++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IRoleData.cs @@ -0,0 +1,19 @@ +using System; +using Volo.Abp.Data; + +namespace Volo.Abp.Users; + +public interface IRoleData : IHasExtraProperties +{ + Guid Id { get; } + + Guid? TenantId { get; } + + string Name { get; } + + bool IsDefault { get; } + + bool IsStatic { get; } + + bool IsPublic { get; } +} diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/RoleData.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/RoleData.cs new file mode 100644 index 0000000000..960a3dfcc7 --- /dev/null +++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/RoleData.cs @@ -0,0 +1,56 @@ +using System; +using JetBrains.Annotations; +using Volo.Abp.Data; + +namespace Volo.Abp.Users; + +public class RoleData : IRoleData +{ + public Guid Id { get; set; } + + public Guid? TenantId { get; set; } + + public string Name { get; set; } + + public bool IsDefault { get; set; } + + public bool IsStatic { get; set; } + + public bool IsPublic { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; } + + public RoleData() + { + + } + + public RoleData(IRoleData roleData) + { + Id = roleData.Id; + Name = roleData.Name; + IsDefault = roleData.IsDefault; + IsStatic = roleData.IsStatic; + IsPublic = roleData.IsPublic; + TenantId = roleData.TenantId; + ExtraProperties = roleData.ExtraProperties; + } + + public RoleData( + Guid id, + [NotNull] string name, + bool isDefault = false, + bool isStatic = false, + bool isPublic = false, + Guid? tenantId = null, + ExtraPropertyDictionary extraProperties = null) + { + Id = id; + Name = name; + IsDefault = isDefault; + IsStatic = isStatic; + IsPublic = isPublic; + TenantId = tenantId; + ExtraProperties = extraProperties; + } +} diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index ece0404dcb..414f4d0a31 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -1,7 +1,7 @@ import { registerLocaleData } from '@angular/common'; import { inject, Injector } from '@angular/core'; import { tap, catchError } from 'rxjs/operators'; -import { lastValueFrom, throwError } from 'rxjs'; +import { firstValueFrom, lastValueFrom, of, throwError, timeout } from 'rxjs'; import { ABP } from '../models/common'; import { Environment } from '../models/environment'; import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models'; @@ -10,10 +10,11 @@ import { EnvironmentService } from '../services/environment.service'; import { SessionStateService } from '../services/session-state.service'; import { CORE_OPTIONS } from '../tokens/options.token'; import { APP_INIT_ERROR_HANDLERS } from '../tokens/app-config.token'; +import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state'; +import { APP_STARTED_WITH_SSR } from '../tokens/ssr-state.token'; import { getRemoteEnv } from './environment-utils'; import { parseTenantFromUrl } from './multi-tenancy-utils'; import { AuthService } from '../abstracts'; -import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state'; import { noop } from './common-utils'; export async function getInitialData() { @@ -21,6 +22,7 @@ export async function getInitialData() { const environmentService = injector.get(EnvironmentService); const configState = injector.get(ConfigStateService); const options = injector.get(CORE_OPTIONS) as ABP.Root; + const appStartedWithSSR = injector.get(APP_STARTED_WITH_SSR); environmentService.setState(options.environment as Environment); await getRemoteEnv(injector, options.environment); @@ -49,8 +51,18 @@ export async function getInitialData() { return throwError(() => error); }), ); - // TODO: Not working with SSR - // await lastValueFrom(result$); + + if (appStartedWithSSR) { + await firstValueFrom( + result$.pipe( + timeout(0), + catchError(() => of(null)), + ), + ); + } else { + await lastValueFrom(result$); + } + await localeInitializer(injector); } diff --git a/templates/app/angular/src/app/app.config.ts b/templates/app/angular/src/app/app.config.ts index 0afccfde31..1baf8e50ae 100644 --- a/templates/app/angular/src/app/app.config.ts +++ b/templates/app/angular/src/app/app.config.ts @@ -1,3 +1,9 @@ +import { + withValidationBluePrint, + provideAbpThemeShared, + provideLogo, + withEnvironmentOptions, +} from '@abp/ng.theme.shared'; import { ApplicationConfig } from '@angular/core'; import { provideRouter } from '@angular/router'; import { provideAnimations } from '@angular/platform-browser/animations'; @@ -6,9 +12,8 @@ import { appRoutes } from './app.routes'; import { APP_ROUTE_PROVIDER } from './route.provider'; import { provideAbpCore, withOptions } from '@abp/ng.core'; import { environment } from '../environments/environment'; -import { registerLocale } from '@abp/ng.core/locale'; +import { registerLocaleForEsBuild } from '@abp/ng.core/locale'; import { provideAbpOAuth } from '@abp/ng.oauth'; -import { provideAbpThemeShared, provideLogo, withEnvironmentOptions} from '@abp/ng.theme.shared'; import { provideSettingManagementConfig } from '@abp/ng.setting-management/config'; import { provideAccountConfig } from '@abp/ng.account/config'; import { provideIdentityConfig } from '@abp/ng.identity/config'; @@ -24,13 +29,12 @@ export const appConfig: ApplicationConfig = { provideAbpCore( withOptions({ environment, - registerLocaleFn: registerLocale(), + registerLocaleFn: registerLocaleForEsBuild(), }) ), provideThemeLeptonX(), provideSideMenuLayout(), provideAbpOAuth(), - provideAbpThemeShared(), provideSettingManagementConfig(), provideAccountConfig(), provideIdentityConfig(), @@ -38,5 +42,10 @@ export const appConfig: ApplicationConfig = { provideFeatureManagementConfig(), provideAnimations(), provideLogo(withEnvironmentOptions(environment)), + provideAbpThemeShared( + withValidationBluePrint({ + wrongPassword: 'Please choose 1q2w3E*', + }) + ), ], };