Activities of "Navneet@aol.com.au"

Answer

Hi liangshiwei,

Many thx for your help.

Final question, should I remove Tenant Management and Edition Management module so that my client not able to enable it without my permission

Answer

Hi,

You can add the CompanyName to the user's claims.

https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory https://docs.abp.io/en/abp/latest/Modules/OpenIddict#updating-claims-in-access_token-and-id_token

protected override Expression> CreateFilterExpression() 
{ 
    var expression = base.CreateFilterExpression(); 
     
    var companyName = currentUser.FindClaimValue("....") 
 
    if (typeof(ICompany).IsAssignableFrom(typeof(TEntity))) 
    { 
        Expression> isCompanyFilter = e => !IsCompanyFilterEnabled ||  
             EF.Property(e, "ICompany").where(e.CompanyName == companyName); 
              
        expression = expression == null  
            ? isCompanyFilter  
            : QueryFilterExpressionHelper.CombineExpressions(expression, isCompanyFilter); 
    } 
 
    return expression; 
} 

Hi liangshiwei,

We follow ABP modular practice (Instead of Application Template, we develop Module Template), so what is the correct place to put the above Custom Filter, IN Module.EntityFrameworkCore or my Tiered Application.EntityFrameworkCore?

Also, how can I make sure that when I am creating a Module and Tiered Application via ABP SUITE, it is Host-only and does not have Tenant or Edition?

By default does the ABP suite include Tenant Management & Edition Management in the application?

Thanks, Navneet

Answer

Another idea is to remove multi-tenancy and create a "Company Id" and somehow I filter uses of one company who buy license and VPS servers, if I follow this path, any suggestion how can I filter it

You can check the document: https://docs.abp.io/en/abp/latest/Data-Filtering#defining-custom-filters

Many thanks liangshiwei,

We have decided to use your above suggestion, it is easy to set a global filter, however not sure how to convert bool to a company filter?

could you please suggest?

I created an interface as ICompany

public interface ICompany
{
 string CompanyName { get; }
}

what am I missing below? how can I filter as e.CompanyName == _user.CompanyName

protected bool IsCompanyFilterEnabled => DataFilter?.IsEnabled<ICompany>() ?? false;

protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
    if (typeof(ICompany).IsAssignableFrom(typeof(TEntity)))
    {
        return true;
    }

    return base.ShouldFilterEntity<TEntity>(entityType);
}

protected override Expression<Func<TEntity, string>> CreateFilterExpression<TEntity>()
{
    var expression = base.CreateFilterExpression<TEntity>();

    if (typeof(ICompany).IsAssignableFrom(typeof(TEntity)))
    {
        Expression<Func<TEntity, string>> isCompanyFilter = e => !IsCompanyFilterEnabled || 
             EF.Property<string>(e, "ICompany").where(e.CompanyName == _user.CompanyName);
             
        expression = expression == null 
            ? isCompanyFilter 
            : QueryFilterExpressionHelper.CombineExpressions(expression, isCompanyFilter);
    }

    return expression;
}

Answer

Also, Is there anyway, I can manage Tenant roles where I as a host create delete and update, however Tenant only able to see pre seeded/created roles?

You can set role create, delete, and edit permissions to only apply to the host.

And create a new manage tenant roles page for the host:

public class CreateTenantRoleInput 
{ 
    public string TenantName {get; set;} 
     
    .... 
} 
public class ManageTenantRolesAppService:... 
{ 
     public async Task CreateAsync(CreateTenantRoleInput input) 
     { 
           var tenant = await _tenantStore.FindAsync(input.Tenant); 
            
           using(currentTenant.Change(tenant.Id)) 
           { 
                _roleRepositpry.InsertAsync(..); 
           } 
     } 
} 

Hi liangshiwei,

I tried to investigate your solution, however, I believe I am may complicating it further while trying to adjust my project. I have below options and may be you can help me with another idea

  1. Remove multi tenancy completely and control Users actions by defining roles permission
  2. Another idea is to remove multi-tenancy and create a "Company Id" and somehow I filter uses of one company who buy license and VPS servers, if I follow this path, any suggestion how can I filter it
  3. Third option is keep it multi-tenant and try to build custom pages for roles and users similar to your suggestions above

Any other idea??

Answer

Hi,

ABP supports multi-tenancy as a first class citizen. You can define multi-tenancy side option while defining a new permission. It gets one of the three values defined below:

Host: The permission is available only for the host side. Tenant: The permission is available only for the tenant side. Both (default): The permission is available both for tenant and host sides.

https://docs.abp.io/en/abp/latest/Authorization#multi-tenancy

You can set the create, edit, and delete permission definitions to host, in this way, the tenant will not have permissions

Hi liangshiwei,

Thanks for your suggestion, that was easy to implement.

As I have complex query to run, how can i determine if current uses is from Host or Tenant? one idea is to inject ICurrentUser and query as ( _currentUser.TenantId == null ) to determine, Is this correct way or are there any other way?

Question
  • ABP Framework version: v8.0.4
  • UI Type: MVC
  • Database System: MySQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no

Hi Abp team,

I am building a license management and Virtual Server Provisioning system. below are few entity I have created Product.cs ProductVersion.cs ProductFeature.cs License.cs ServerDetail.cs ServerFeature.cs Plan.cs Pricing.cs

The challenge, I am facing is that I want my tenant to only ReadOnly Access of entities (not allowing to add / update or delete). and only want them to add an entry in Plan.cs entity, how can i control as the Host user? Also, Is there anyway, I can manage Tenant roles where I as a host create delete and update, however Tenant only able to see pre seeded/created roles?

many thx, Nav

Hi Maliming,

Many thx for your help. Enjoy rest of your day

hi

Please share the logs of this error.

Btw we have changed the OnDelete(DeleteBehavior(DeleteBehavior.NoAction) to OnDelete(DeleteBehavior.Cascade)

If you have similar code you can change it.

Hi maliming,

You are correct the default template had OnDelete(DeleteBehavior(DeleteBehavior.NoAction), once I change it to OnDelete(DeleteBehavior.Cascade), eveything is working perfectly.

When can we expect this to be fixed?

Also, can you please refund the ticket?

Thanks

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, and please first use the search on the homepage. Provide us with the following info:

  • ABP Framework version: v8.0.4
  • UI Type: Angular / MVC / Blazor WASM / Blazor Server
  • Database System: MySQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no
  • Exception message and full stack trace:

Hello Team,

I am getting error while deleting items from Many to Many popup box. Looks like it is bug. After debugging I believe it is failing at

UI guide to produce error Delete one item Click on save

  • Steps to reproduce the issue:
  1. Create a new Module application from ABP suite
  2. Create two entity and N-N navigation.
  3. Below I have copy past my two suite entities if you want to use
  4. Use Host --> Web.Unified to do migration and run the application

ProductVersion.json

{
  "Id": "c9c0e8de-7201-48ad-985c-a15ea7a27a54",
  "Name": "ProductVersion",
  "OriginalName": "ProductVersion",
  "NamePlural": "ProductVersions",
  "DatabaseTableName": "ProductVersions",
  "Namespace": "ProductVersions",
  "Type": 1,
  "MasterEntityName": null,
  "MasterEntity": null,
  "BaseClass": "FullAuditedAggregateRoot",
  "MenuIcon": "file-alt",
  "PrimaryKeyType": "Guid",
  "PreserveCustomCode": true,
  "IsMultiTenant": true,
  "CheckConcurrency": true,
  "ShouldCreateUserInterface": true,
  "ShouldCreateBackend": true,
  "ShouldExportExcel": false,
  "ShouldAddMigration": true,
  "ShouldUpdateDatabase": true,
  "CreateTests": false,
  "Properties": [
    {
      "Id": "a25033bf-ace9-48ac-b85b-0ca1b46aa93f",
      "Name": "VersionName",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "AllowEmptyStrings": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "1caed050-5639-4702-967e-7802e0772fbc",
      "Name": "IsActive",
      "Type": "bool",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": "true",
      "IsNullable": false,
      "IsRequired": false,
      "AllowEmptyStrings": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "902ce3e5-44df-4155-8e2f-f29db8b207bf",
      "Name": "VersionNumber",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "AllowEmptyStrings": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    }
  ],
  "NavigationProperties": [],
  "NavigationConnections": [],
  "ChildEntities": [],
  "PhysicalFileName": "ProductVersion.json"
}

ProductFeature.json

{
  "Id": "473fe992-54e4-41d8-978a-a26be9ea5bb3",
  "Name": "ProductFeature",
  "OriginalName": "ProductFeature",
  "NamePlural": "ProductFeatures",
  "DatabaseTableName": "ProductFeatures",
  "Namespace": "ProductFeatures",
  "Type": 1,
  "MasterEntityName": null,
  "MasterEntity": null,
  "BaseClass": "FullAuditedAggregateRoot",
  "MenuIcon": "file-alt",
  "PrimaryKeyType": "Guid",
  "PreserveCustomCode": true,
  "IsMultiTenant": true,
  "CheckConcurrency": true,
  "ShouldCreateUserInterface": true,
  "ShouldCreateBackend": true,
  "ShouldExportExcel": false,
  "ShouldAddMigration": true,
  "ShouldUpdateDatabase": true,
  "CreateTests": false,
  "Properties": [
    {
      "Id": "7ada5c2a-14d7-44d5-b115-ed2666e2fc8e",
      "Name": "FeatureName",
      "Type": "string",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": null,
      "IsNullable": false,
      "IsRequired": false,
      "AllowEmptyStrings": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    },
    {
      "Id": "17a84907-6f5b-4104-a063-626fed74c59e",
      "Name": "IsActive",
      "Type": "bool",
      "EnumType": "",
      "EnumNamespace": "",
      "EnumAngularImport": "shared/enums",
      "EnumFilePath": null,
      "DefaultValue": "true",
      "IsNullable": false,
      "IsRequired": false,
      "AllowEmptyStrings": false,
      "IsTextArea": false,
      "MinLength": null,
      "MaxLength": null,
      "SortOrder": 0,
      "SortType": 0,
      "Regex": "",
      "EmailValidation": false,
      "ShowOnList": true,
      "ShowOnCreateModal": true,
      "ShowOnEditModal": true,
      "ReadonlyOnEditModal": false,
      "EnumValues": null,
      "IsSelected": true,
      "OrdinalIndex": 0
    }
  ],
  "NavigationProperties": [],
  "NavigationConnections": [
    {
      "Name": "ProductVersions",
      "DisplayProperty": "VersionName",
      "Namespace": "ABP.IO.Test.ProductVersions",
      "EntityName": "ProductVersion",
      "EntitySetName": "ProductVersions",
      "DtoNamespace": "ABP.IO.Test.ProductVersions",
      "DtoEntityName": "ProductVersionDto",
      "Type": "Guid"
    }
  ],
  "ChildEntities": [],
  "PhysicalFileName": "ProductFeature.json"
}

Thanks Nav

Hi gterdem and Nico,

Thank you both for giving me extensive help; it took me a little while to digest.

@gtendem: I agree with you that Authorization in Web API is not straight and after discussing with the client, we have decided that the client with handle Authorization by themself, I will be helping them only with Authentication. So, your above steps work perfectly to Authenticate.

@Nico: your suggestion to create an entity to assign User/Role to ~~Application or~~ Scope is perfect, as it supports the below scenario.

Is Controller right place to check if user/role has assigned scope?

Regards,

Showing 1 to 10 of 53 entries
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11