Base solution for your next web application

Activities of "dmux"

Absolute legend. Great catch, thanks. That worked.

I regretted using People as the plural, and I'd forgotten how many things work on matching the names.

Anyway, that's got me past the big roadblock. Cheers.

I had the same issue. The steps from @AuroraBMS worked for me.

Thanks very much @marble68, I've never bothered going under the bonnet before into the ABP code, and it's interesting!

In the end I stuck with what I've got available out of the box. In my background task I now have this:

List<int> tenants = _tenantRepository.GetAll()
                       .Where(t => !t.IsDeleted && t.IsActive)
                       .Select(t => t.Id)
                       .ToList();

foreach (int tenantId in tenants)
{
    using (var unitOfWork = _unitOfWorkManager.Begin())
    {
        using (_unitOfWorkManager.Current.SetTenantId(tenantId))
        {
            var users = _userRepository.GetAllList();
            foreach (var user in users)
            {
                _notificationStore.DeleteAllUserNotifications(user.ToUserIdentifier(), UserNotificationState.Read, Clock.Now.AddYears(-10), Clock.Now.AddDays(-7));
                _notificationStore.DeleteAllUserNotifications(user.ToUserIdentifier(), UserNotificationState.Unread, Clock.Now.AddYears(-10), Clock.Now.AddDays(-30));
            }
        }
        unitOfWork.Complete();
    }
}

<br> ... so I'm iterating through the tenancies, then the users in each tenancy, and for each user just calling the INotificationStore delete method with parameters. Raw SQL would be much more efficient, but this works great, and I do like to work through the framework where I can.

Thanks again for your ideas and help.

Hi @marble68, thanks for your suggestion!

I think you're right - DeleteAllUserNotifications() will be part of the solution. It even lets me specify a date range. Unfortunately it only allows me to operate on notifications for a single user at a time, though. So what I now need is a way to iterate over all the users, so I can run DeleteAllUserNotifications for each one.

I can't see a way to enumerate users. Is there an Abp function for this?

What I meant was if I could use IRepository<UserNotification>, I could just delete the records older than a certain date.

In IUserNotification I can see there is a delete function, but I have to specify a user. What I need to do is iterate over all the users and get all the notifications older than a certain time, then delete them. I guess if I could iterate over all users I could use IUserNotification to get all notifications and then delete the older ones.

Is there a way I can iterate over all users? Even just all users in one tenancy (because I can iterate through tenancies)?

Hi @ismcahdas,

I'm not exactly sure what your question means. I don't think there is a way to make more than one language the default. English (UK) is set to default.

Anyway I finally solved it when I noticed the English (US) had the code "en". I changed it to have "en-us" and then disabled it in the host. Now the UK one is the only one enabled and is the default, and it's working in the tenant.

Thanks, Kevin

Disregard this. I found the answer here:

https://github.com/ng-bootstrap/ng-bootstrap/issues/1522

Essentially, just add

.modal { overflow-y: auto !important; }

... to the css for the modal.

Hi @maliming,

Thank you for that document. I have been through it and tested Chrome by enabling "SameSite by default cookies" as it suggests. It appears to make no difference to how the app works. So maybe nothing is going to break in two weeks time. Is that right?

The only cookies that are SameSite and not Secure appear to be set by the ASPNETZero base code:

I really just need to know if the standard ASPNETZero platform (v8.0 CORE MVC) will stop working in two weeks or not. Please advise.

Thanks kindly!

Hi ismcagdas,

Thank you for following up.

I have had a chance to dig a bit deeper and I think I have found the issue.

In Core/DashboardCustomization/Definitions/DashboardConfiguration.cs this is the pattern provided in the default project:

var tenantWidgetsDefaultPermission = new List
{
AppPermissions\.Pages\_Tenant\_Dashboard
};

var dailySales = new WidgetDefinition(
    WebPortalDashboardCustomizationConsts.Widgets.Tenant.DailySales,
    "WidgetDailySales",
    side: MultiTenancySides.Tenant,
    usedWidgetFilters: new List<string> { dateRangeFilter.Id },
    permissions: tenantWidgetsDefaultPermission
);

var generalStats = new WidgetDefinition(
    WebPortalDashboardCustomizationConsts.Widgets.Tenant.GeneralStats,
    "WidgetGeneralStats",
    side: MultiTenancySides.Tenant,
    permissions: tenantWidgetsDefaultPermission
    );

generalStats.Permissions.Add(AppPermissions.Pages_Administration_AuditLogs);

... and so forth. I haven't yet removed all thses default widgets from my project so they are all still there.

What happens is that each new widget definition sets its "permissions" to be a pointer to the list called "tenantWidgetsDefaultPermission". The result is that all widgets end up with the same list, which includes any added permissions like the one listed on the last line here. This is why all my widget users required AuditLogs permission for every widget, when they should only require that permission for GeneralStats.

What I did to stop this behaviour is I added ".ToList()" when setting the widget "permissions" property, so that the permissions list would be a new object. This resolved the issue, like this:

var generalStats = new WidgetDefinition(
    WebPortalDashboardCustomizationConsts.Widgets.Tenant.GeneralStats,
    "WidgetGeneralStats",
    side: MultiTenancySides.Tenant,
    permissions: tenantWidgetsDefaultPermission.ToList()
    );

There might be nicer ways to do it, but this works for me for the moment.

Hi Maliming,

Thanks for replying. I don't know where "plugins" is...

But I went back and did some more experimenting. I have added the clockface.css to view-resources/Areas/App/Views/-Bundles/customizable-dashboard-libs.min.css, because that comes further down in the list of included bundles. That worked ok.

Now I can use the clockface in any of my widgets and their modals because they all load that bundle. That's good enough for me.

Thanks again.

Showing 1 to 10 of 18 entries