Disconnecting NotificationBase from Event, introducing NotificationSender

This commit is contained in:
rockstardev
2020-06-11 23:52:46 -05:00
parent 8876f1f992
commit d1383d78c5
8 changed files with 61 additions and 51 deletions

View File

@@ -22,13 +22,13 @@ namespace BTCPayServer.Controllers
public class NotificationsController : Controller public class NotificationsController : Controller
{ {
private readonly ApplicationDbContext _db; private readonly ApplicationDbContext _db;
private readonly EventAggregator _eventAggregator; private readonly NotificationSender _notificationSender;
private readonly UserManager<ApplicationUser> _userManager; private readonly UserManager<ApplicationUser> _userManager;
public NotificationsController(ApplicationDbContext db, EventAggregator eventAggregator, UserManager<ApplicationUser> userManager) public NotificationsController(ApplicationDbContext db, NotificationSender notificationSender, UserManager<ApplicationUser> userManager)
{ {
_db = db; _db = db;
_eventAggregator = eventAggregator; _notificationSender = notificationSender;
_userManager = userManager; _userManager = userManager;
} }
@@ -54,7 +54,7 @@ namespace BTCPayServer.Controllers
[HttpGet] [HttpGet]
public async Task<IActionResult> Generate() public async Task<IActionResult> Generate()
{ {
_eventAggregator.NoticeNewVersion("1.0.4.4"); await _notificationSender.NoticeNewVersionAsync("1.0.4.4");
// waiting for event handler to catch up // waiting for event handler to catch up
await Task.Delay(1000); await Task.Delay(1000);
return RedirectToAction(nameof(Index)); return RedirectToAction(nameof(Index));

View File

@@ -4,7 +4,7 @@ using Newtonsoft.Json;
namespace BTCPayServer.Events.Notifications namespace BTCPayServer.Events.Notifications
{ {
internal class NewVersionNotification : NotificationEventBase internal class NewVersionNotification : NotificationBase
{ {
public string Version { get; set; } public string Version { get; set; }

View File

@@ -8,17 +8,18 @@ namespace BTCPayServer.Events.Notifications
// Make sure to keep all NotificationEventBase classes in same namespace // Make sure to keep all NotificationEventBase classes in same namespace
// because of dependent initialization and parsing to view models logic // because of dependent initialization and parsing to view models logic
// IndexViewModel.cs#32 // IndexViewModel.cs#32
internal abstract class NotificationEventBase internal abstract class NotificationBase
{ {
internal virtual string NotificationType { get { return GetType().Name; } } internal virtual string NotificationType { get { return GetType().Name; } }
public NotificationData ToData() public NotificationData ToData(string applicationUserId)
{ {
var obj = JsonConvert.SerializeObject(this); var obj = JsonConvert.SerializeObject(this);
var data = new NotificationData var data = new NotificationData
{ {
Created = DateTimeOffset.UtcNow, Id = Guid.NewGuid().ToString(),
ApplicationUserId = applicationUserId,
NotificationType = NotificationType, NotificationType = NotificationType,
Blob = ZipUtils.Zip(obj), Blob = ZipUtils.Zip(obj),
Seen = false Seen = false

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BTCPayServer.Events.Notifications
{
internal class NotificationEvent
{
internal string[] ApplicationUserIds { get; set; }
internal NotificationBase Notification { get; set; }
}
}

View File

@@ -3,17 +3,36 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data;
using Microsoft.AspNetCore.Identity;
namespace BTCPayServer.Events.Notifications namespace BTCPayServer.Events.Notifications
{ {
public static class NotificationsHelperExt public class NotificationSender
{ {
public static void NoticeNewVersion(this EventAggregator aggr, string version) private readonly UserManager<ApplicationUser> _userManager;
private readonly EventAggregator _eventAggregator;
public NotificationSender(UserManager<ApplicationUser> userManager, EventAggregator eventAggregator)
{ {
aggr.Publish(new NewVersionNotification _userManager = userManager;
_eventAggregator = eventAggregator;
}
internal async Task NoticeNewVersionAsync(string version)
{
var admins = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
var adminUids = admins.Select(a => a.Id).ToArray();
var evt = new NotificationEvent
{ {
Version = version ApplicationUserIds = adminUids,
}); Notification = new NewVersionNotification
{
Version = version
}
};
_eventAggregator.Publish(evt);
} }
} }
} }

View File

@@ -15,58 +15,32 @@ namespace BTCPayServer.HostedServices
{ {
public class NotificationDbSaver : EventHostedServiceBase public class NotificationDbSaver : EventHostedServiceBase
{ {
private readonly UserManager<ApplicationUser> _UserManager;
private readonly ApplicationDbContextFactory _ContextFactory; private readonly ApplicationDbContextFactory _ContextFactory;
public NotificationDbSaver(UserManager<ApplicationUser> userManager, public NotificationDbSaver(ApplicationDbContextFactory contextFactory,
ApplicationDbContextFactory contextFactory,
EventAggregator eventAggregator) : base(eventAggregator) EventAggregator eventAggregator) : base(eventAggregator)
{ {
_UserManager = userManager;
_ContextFactory = contextFactory; _ContextFactory = contextFactory;
} }
protected override void SubscribeToEvents() protected override void SubscribeToEvents()
{ {
SubscribeAllChildrenOfNotificationEventBase(); Subscribe<NotificationEvent>();
base.SubscribeToEvents(); base.SubscribeToEvents();
} }
// subscribe all children of NotificationEventBase
public void SubscribeAllChildrenOfNotificationEventBase()
{
var method = this.GetType().GetMethod(nameof(SubscribeHelper));
var notificationTypes = this.GetType().Assembly.GetTypes().Where(a => typeof(NotificationEventBase).IsAssignableFrom(a));
foreach (var notif in notificationTypes)
{
var generic = method.MakeGenericMethod(notif);
generic.Invoke(this, null);
}
}
// we need publicly accessible method for reflection invoke
public void SubscribeHelper<T>() => base.Subscribe<T>();
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken) protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
{ {
if (evt is NotificationEventBase) var casted = evt as NotificationEvent;
using (var db = _ContextFactory.CreateContext())
{ {
var data = (evt as NotificationEventBase).ToData(); foreach (var uid in casted.ApplicationUserIds)
var admins = await _UserManager.GetUsersInRoleAsync(Roles.ServerAdmin);
using (var db = _ContextFactory.CreateContext())
{ {
foreach (var admin in admins) var data = casted.Notification.ToData(uid);
{ db.Notifications.Add(data);
data.Id = Guid.NewGuid().ToString();
data.ApplicationUserId = admin.Id;
db.Notifications.Add(data);
}
await db.SaveChangesAsync();
} }
await db.SaveChangesAsync();
} }
} }
} }

View File

@@ -46,6 +46,7 @@ using BTCPayServer.Security.Bitpay;
using Serilog; using Serilog;
using BTCPayServer.Security.GreenField; using BTCPayServer.Security.GreenField;
using BTCPayServer.Services.Labels; using BTCPayServer.Services.Labels;
using BTCPayServer.Events.Notifications;
namespace BTCPayServer.Hosting namespace BTCPayServer.Hosting
{ {
@@ -202,6 +203,7 @@ namespace BTCPayServer.Hosting
services.AddSingleton<IHostedService, NotificationDbSaver>(); services.AddSingleton<IHostedService, NotificationDbSaver>();
services.AddScoped<NotificationManager>(); services.AddScoped<NotificationManager>();
services.AddScoped<NotificationSender>();
services.AddSingleton<IHostedService, NBXplorerWaiters>(); services.AddSingleton<IHostedService, NBXplorerWaiters>();
services.AddSingleton<IHostedService, InvoiceNotificationManager>(); services.AddSingleton<IHostedService, InvoiceNotificationManager>();

View File

@@ -29,10 +29,10 @@ namespace BTCPayServer.Models.NotificationViewModels
{ {
public static NotificationViewModel ViewModel(this NotificationData data) public static NotificationViewModel ViewModel(this NotificationData data)
{ {
var baseType = typeof(NotificationEventBase); var baseType = typeof(NotificationBase);
var typeName = baseType.FullName.Replace(nameof(NotificationEventBase), data.NotificationType, StringComparison.OrdinalIgnoreCase); var typeName = baseType.FullName.Replace(nameof(NotificationBase), data.NotificationType, StringComparison.OrdinalIgnoreCase);
var instance = Activator.CreateInstance(baseType.Assembly.GetType(typeName)) as NotificationEventBase; var instance = Activator.CreateInstance(baseType.Assembly.GetType(typeName)) as NotificationBase;
return instance.ToViewModel(data); return instance.ToViewModel(data);
} }