Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC

Activities of "BobIngham"

Are there any plans to add host users with access to limited tenants? Typically this would involve a lesser role than admin which we would keep for ourselves and then an additional role for, say, tenant admin. A user in the admin role could apply access to different tenants for users in the tenant admin role? If you feel this a good idea could you add it to the backlog? If not let me know and I will try implement myself.

Question

I have an hourly job invoked from Hangfire which loops through each tenant and makes DisplayName unique for each entity in a given OrganizationUnit

public void MakeNcEntityDisplayNameUnique(int tenantId)
{
    var adminUsers = _userManager.GetUsersInRoleAsync("Admin").GetAwaiter().GetResult();
    var userId = adminUsers.Select(m => m.Id).FirstOrDefault();

    using (_abpSession.Use(tenantId, userId))
    {
        var organizationUnits = _organizationUnitRepository.GetAllList();
        foreach (var organizationUnit in organizationUnits)
        {
            var entities = _ncEntityRepository.GetAllList(e => e.OrganizationUnitId == organizationUnit.Id);
            var duplicates = entities.GroupBy(x => x.DisplayName)
                                    .Where(g => g.Count() > 1)
                                    .Select(y => y.Key)
                                    .ToList();


            foreach (var duplicate in duplicates)
            {
                foreach (var entity in _ncEntityRepository.GetAllList(e => e.DisplayName == duplicate && e.OrganizationUnitId == organizationUnit.Id))
                {
                    var surname = entity.GetData<AttributeDataDto>("Surname").Value;
                    var newDisplayName = entity.DisplayName + " " + surname.Substring(0, 1);
                    var entityExists = _ncEntityRepository.FirstOrDefault(e => e.DisplayName == newDisplayName && e.OrganizationUnitId == organizationUnit.Id);
                    if (entityExists != null)
                    {
                        entity.DisplayName = entity.DisplayName + " " + surname;
                    }
                    else
                    {
                        entity.DisplayName = newDisplayName;
                    }
                    _ncEntityRepository.Update(entity);
                }
            }
        }
        return;
    }
}

When the update is persisted for each entity the value of LastModifierUserId is 1 - the admin of the host. I have attempted to set the session UserId in the first two lines of the code block. How do I get the value AbpSession.UserId to persist as the LastModifierUserId?

When creating a new tenant with TenantManager.CreateWithAdminUserAsync what is the best practise for creating permissions following the creation of static roles? The method creates my static roles thus:

CheckErrors(await _roleManager.CreateStaticRoles(tenant.Id));
await _unitOfWorkManager.Current.SaveChangesAsync(); //To get static role ids

I have a static role called "Carer" and in my TenantRoleAndUserBuilder.CreateRolesAndUsers method I have the following code block:

var carerRole = _context.Roles.IgnoreQueryFilters().FirstOrDefault(r => r.TenantId == _tenantId && r.Name == StaticRoleNames.Tenants.Carer);
if (carerRole == null)
{
    carerRole = _context.Roles.Add(new Role(_tenantId, StaticRoleNames.Tenants.Carer, StaticRoleNames.Tenants.Carer) { IsStatic = true, IsDefault = true }).Entity;
    _context.SaveChanges();

    //Grant selected permissions to carer role
    var permissions = PermissionFinder
        .GetAllPermissions(new AppAuthorizationProvider(false))
        .Where(p => p.MultiTenancySides.HasFlag(MultiTenancySides.Tenant))
        .ToList();

    foreach (var permission in permissions.OrderBy(m => m.Name))
    {
        if (
            permission.Name == "Pages.Tenant.Dashboard" ||
            permission.Name == "Pages.Tenant.Dashboard.FormSubmissionActivityChart" ||
            permission.Name == "Pages.NcEntities" ||
            permission.Name == "Pages.NcEntity.Display" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.FluidPieChart" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.FoodChart" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.SSkinCareBundle" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.FormSubmissionActivityChart" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.FormSubmissionActivityByStaffChart" ||
            permission.Name == "Pages.NcEntity.Display.Dashboard.WarningsBarChart" ||
            permission.Name == "Pages.NcEntity.Display.Profile" ||
            permission.Name == "Pages.NcEntity.Display.Profile.Metrics" ||
            permission.Name == "Pages.NcEntity.NcCarePlans" ||
            permission.Name == "Pages.NcEntity.NcCarePlan.Display" ||
            permission.Name == "Pages.NcEntity.NcWarnings" ||
            permission.Name == "Pages.NcEntity.NcWarning.Display" ||
            permission.Name == "Pages.NcEntity.Display.FormSubmissions" ||
            permission.Name == "Pages.NcEntity.Display.Media")
        {
            _context.Permissions.Add(
                new RolePermissionSetting
                {
                    TenantId = _tenantId,
                    Name = permission.Name,
                    IsGranted = true,
                    RoleId = carerRole.Id
                });
        }
    }
    _context.SaveChanges();
}

Using DRY principles, what is the best way to refactor this code?

Methinks perhaps one for @ismcagdas;

What is the business case for linked users? Under what circumstances do I need to link to a user when I can simply login as a user? I am sure this functionality would be useful to me but I cannot see the circumstances under which I would need to use it.

Cheers, Bob

Question

I can find no way of passing AbpSession.TenantId to my own AuditingStore implementation. As background I must point out that the call is coming from a copy of TokenAuthController which is used to handle the vagaries of logins from an Ionic app. The app passes tenantId in every call to the system. When a user uses incorrect credentials to sign in I need the audit log to capture tenantId but my efforts so far have been unsuccessful. Let me explain...

The app connects to AppTokenAuthController.AppAuthenticate (my own copy of TokenAuthController.Authenticate) . I wrap my code in the following use block:

using (_unitOfWorkManager.Current.SetTenantId(model.TenantId))

and I call:

var loginResult = await GetLoginResultAsync(
    model.UserNameOrEmailAddress,
    model.Password,
    await GetTenancyNameFromTenantId(model.TenantId)
);

The call is unsuccessful because of incorrect credentials and AuditingStore.SaveAsync() is called. At this stage AbpSession is null. The result is that the audit log gets written to the audit log for the host. Bugger. AuditingStore is in the Core project. My AppTokenAuthController is in the Web.Core project, is there any reason why session is not being persisted? How do I set it in AppTokenAuthController? I have tried the following to no avail:

AbpSession.Use(model.TenantId, null);

Any suggestions gratefully received.

Question

asp-net core, angular, 6.4.0 I am getting ready to upgrade my system to 6.5.0 (waiting for recurring payments) and have downloaded 6.4.0. I use Kendo components in my solution and have a problem with drop-downs in grids not showing. I have modifed my code in line with the latest release:

<ng-template kendoGridCellTemplate let-dataItem>
  <tr>
    <td>
      <div class="btn-group dropdown" dropdown>
        <button dropdownToggle class="dropdown-toggle btn btn-primary btn-sm dropdown-toggle">
          <i class="fa fa-cog"></i><span class="caret"></span> {{l("Actions")}}</button>
            <ul class="dropdown-menu" *dropdownMenu>
              <li>
                <a href="javascript:;" (click)="read(dataItem.id)">Display</a>
              </li>
              <li>
                <a href="javascript:;" *ngIf="permission.isGranted('Pages.Administration.NcForms.Edit')"(click)="edit(dataItem.id)">{{l('Edit')}}</a>
              </li>
              <li>
                <a href="javascript:;" *ngIf="permission.isGranted('Pages.Administration.NcForms.Delete')" (click)="delete(dataItem)">{{l('Delete')}}</a>
              </li>
            </ul>
          </div>
        </td>
      </tr>
    </ng-template>

But the drop-down is hidden. I seem to remember a similar problem when I had to implement some jquery in my router but the new template has no jquery. The above image shows that the drop-down is activated but is simply not shown. Any ideas anyone?

This is probably not a Zero problem but perhaps someone can suggest a way i can configure something to get rid of the errors I am getting... In a fresh angular install I have successfully implemented Telerik reporting with no problems. Using the same methods used in the test project I simply add Telerik reporting:

npm install @progress/telerik-angular-report-viewer

As soon as i import the module into my app.module:

import { TelerikReportingModule } from '@progress/telerik-angular-report-viewer';

and apply it to my imports array the Zero system throws the following error in the console of the login page and the page remains blocked to the user:

ERROR TypeError: $.unblockUI is not a function at Object.abp.ui.unblock (abp.blockUI.js:28)

I then took the import away from the app.module and imported it into my project.module which is lazy-loaded. Now I can login but when I select a menu item invoking my lazy-loaded module the same error is thrown.

Does anyone have any idea as to why a third party component should play havoc with Abp? btw - I will post a similar entry on the Telerik forum.

dotnet-core, angular, 5.4.1 - One for Aaron. I think. Hi Aaron, If you remember I implemented my own EntityHistoryStore inheriting from IEntityHistoryStore to write entity change history to Mongodb. This works well but the other day Azure reconfigured my outgoing Ip's for some reason and the new IP's were not configured in my Mongodb Atlas whitelist. I fixed this issue but realised that I would need a fallback should, for any reason, my Mongodb data store become unavailable. I implemented the following fallback code in my implementation of EntityHistoryStore:

try
{
    //standard timeout for Mpongodb is 30 seconds, here we need to the system to return to the client as quickly as possible
    using (var timeoutCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(2000)))
    {
        await collection.InsertOneAsync(document);
    }
}
catch (Exception ex)
{
    logger.Error("Mongodb: " + ex.GetType(), ex);
    //fallback and save to SQL Server until Mongodb is back up and running
    await _fallbackEntityHistoryStore.SaveAsync(changeSet);
}

If I cannot write to Mongodb the system will fallback to my FallbackEntityHistoryStore which is simple in implementation:

public class FallbackEntityHistoryStore : IFallbackEntityHistoryStore, ITransientDependency
{
    private readonly IRepository<EntityChangeSet, long> _changeSetRepository;
    private readonly IUnitOfWorkManager _unitOfWorkManager;

    public FallbackEntityHistoryStore(
        IRepository<EntityChangeSet, long> changeSetRepository,
        IUnitOfWorkManager unitOfWorkManager
        )
    {
        _changeSetRepository = changeSetRepository;
        _unitOfWorkManager = unitOfWorkManager;
    }

    public async Task SaveAsync(EntityChangeSet changeSet)
    {
        using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
        {
            await _changeSetRepository.InsertAsync(changeSet);
            await uow.CompleteAsync();
        }
    }
}

This works well on the first call but then fails on subsequent calls with the message:

Cannot insert explicit value for identity column in table '[dbo].[AbpEntityChangeSets]' when IDENTITY_INSERT is set to OFF.

I can reset the identity_insert value in the database directly with SET IDENTITY_INSERT dbo.AbpEntityChangeSets ON and the next iteration will work again but it sets the identity_insert value of the table back to OFF.

Is there some piece of magic which you use in your solution that I can implement in my solution? I have searched your source code on github but I can see nothing you are doing different. Googling the issue suggests I should change data annotations on the models but I don't remember changing any of your models, I built new ones to support Mongdb Bson documents.

Any pointers what to do next? Cheers, Bob

.net core, angular, 5.4.1 I have a multi-tenanted solution set up at [websitehere]. The system is hosted on azure [websitehere.azurewebsites.net] and my domains are held at GoDaddy. I set up a new tenant and send the link to my customer by email.

When the customer clicks on the link s/he is directed to the website and although we can see the sub-domain in the browser bar:"subdomain.website.api" the tenant is not picked up by the system and the customer is unable to login. However, I can sit with the customer and login using the host admin details with the sub-domain showing in the browser bar which logs me into the host account. I can then impersonate a user in the tenant account, return to my host account and logout. Now when the user traverses to "subdomain.website.api" the tenant is found and the customer is able to login. I have spent a few calls and hours with GoDaddy and they confirm my DNS settings are correct:

I am told my Azure settings are also fine:

My appconfig.json is setup as standard:

{
  "remoteServiceBaseUrl": "https://projectname.api",
  "appBaseUrl": "https://{TENANCY_NAME}.projectname.ui",
  "localeMappings": [
    {
      "from": "pt-BR",
      "to": "pt"
    },
    {
      "from": "zh-CN",
      "to": "zh"
    }
  ]
}

Everything points to a code problem and i have placed comments in account.component.htm,l to verify the tenant is not found on first visit to the sub-domain. Why is the tenant not being picked up on first visit to the page, subdomain.website.api? Any help much appreciated because this is becoming a bit of a show-stopper for me.

I am trying to introduce a new set of roles for each tenant through the Nuagecare.Migrations.Seed.SeedHelper method. How do I get all tenants in the static SeedHelper class?

public static void SeedHostDb(NuagecareDbContext context)
{
    context.SuppressAutoSetTenantId = true;

    //Host seed
    new InitialHostDbBuilder(context).Create();

    //Default tenant seed (in host database).
    new DefaultTenantBuilder(context).Create();

    //how do I get all tenants here?
    //foreach (var tenant in tenants)....
    new TenantRoleAndUserBuilder(context, tenant.id).Create();
    new DefaultTenantDataBuilder(context, tenant.id).Create();
}
Showing 81 to 90 of 142 entries