mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 14:22:40 +01:00
Merge pull request #1670 from btcpayserver/refactor/notifications2
Introduce INotificationHandler
This commit is contained in:
commit
9f12fe7e0a
9 changed files with 85 additions and 83 deletions
|
@ -27,13 +27,19 @@ namespace BTCPayServer.Controllers
|
|||
private readonly ApplicationDbContext _db;
|
||||
private readonly NotificationSender _notificationSender;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly NotificationManager _notificationManager;
|
||||
|
||||
public NotificationsController(BTCPayServerEnvironment env, ApplicationDbContext db, NotificationSender notificationSender, UserManager<ApplicationUser> userManager)
|
||||
public NotificationsController(BTCPayServerEnvironment env,
|
||||
ApplicationDbContext db,
|
||||
NotificationSender notificationSender,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
NotificationManager notificationManager)
|
||||
{
|
||||
_env = env;
|
||||
_db = db;
|
||||
_notificationSender = notificationSender;
|
||||
_userManager = userManager;
|
||||
_notificationManager = notificationManager;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
@ -50,7 +56,7 @@ namespace BTCPayServer.Controllers
|
|||
.OrderByDescending(a => a.Created)
|
||||
.Skip(skip).Take(count)
|
||||
.Where(a => a.ApplicationUserId == userId)
|
||||
.Select(a => a.ToViewModel())
|
||||
.Select(a => _notificationManager.ToViewModel(a))
|
||||
.ToList(),
|
||||
Total = _db.Notifications.Where(a => a.ApplicationUserId == userId).Count()
|
||||
};
|
||||
|
|
|
@ -47,6 +47,7 @@ using Serilog;
|
|||
using BTCPayServer.Security.GreenField;
|
||||
using BTCPayServer.Services.Labels;
|
||||
using BTCPayServer.Services.Notifications;
|
||||
using BTCPayServer.Services.Notifications.Blobs;
|
||||
|
||||
namespace BTCPayServer.Hosting
|
||||
{
|
||||
|
@ -220,6 +221,7 @@ namespace BTCPayServer.Hosting
|
|||
services.AddSingleton<IBackgroundJobClient, BackgroundJobClient>();
|
||||
services.AddScoped<IAuthorizationHandler, CookieAuthorizationHandler>();
|
||||
services.AddScoped<IAuthorizationHandler, BitpayAuthorizationHandler>();
|
||||
services.AddSingleton<INotificationHandler, NewVersionNotification.Handler>();
|
||||
|
||||
services.TryAddSingleton<ExplorerClientProvider>();
|
||||
services.TryAddSingleton<Bitpay>(o =>
|
||||
|
|
|
@ -27,31 +27,4 @@ namespace BTCPayServer.Models.NotificationViewModels
|
|||
public string ActionLink { get; set; }
|
||||
public bool Seen { get; set; }
|
||||
}
|
||||
|
||||
public static class NotificationViewModelExt
|
||||
{
|
||||
static Dictionary<string, Type> _NotificationTypes;
|
||||
static NotificationViewModelExt()
|
||||
{
|
||||
_NotificationTypes = Assembly.GetExecutingAssembly()
|
||||
.GetTypes()
|
||||
.Select(t => (t, NotificationType: t.GetCustomAttribute<NotificationAttribute>()?.NotificationType))
|
||||
.Where(t => t.NotificationType is string)
|
||||
.ToDictionary(o => o.NotificationType, o => o.t);
|
||||
}
|
||||
|
||||
public static NotificationViewModel ToViewModel(this NotificationData data)
|
||||
{
|
||||
var casted = (BaseNotification)JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), _NotificationTypes[data.NotificationType]);
|
||||
var obj = new NotificationViewModel
|
||||
{
|
||||
Id = data.Id,
|
||||
Created = data.Created,
|
||||
Seen = data.Seen
|
||||
};
|
||||
casted.FillViewModel(obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models.NotificationViewModels;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Services.Notifications.Blobs
|
||||
{
|
||||
// Make sure to keep all Blob Notification classes in same namespace
|
||||
// because of dependent initialization and parsing to view models logic
|
||||
// IndexViewModel.cs#32
|
||||
public abstract class BaseNotification
|
||||
{
|
||||
public abstract void FillViewModel(NotificationViewModel data);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,17 @@ using Newtonsoft.Json;
|
|||
|
||||
namespace BTCPayServer.Services.Notifications.Blobs
|
||||
{
|
||||
[Notification("newversion")]
|
||||
internal class NewVersionNotification : BaseNotification
|
||||
internal class NewVersionNotification
|
||||
{
|
||||
internal class Handler : NotificationHandler<NewVersionNotification>
|
||||
{
|
||||
public override string NotificationType => "newversion";
|
||||
protected override void FillViewModel(NewVersionNotification notification, NotificationViewModel vm)
|
||||
{
|
||||
vm.Body = $"New version {notification.Version} released!";
|
||||
vm.ActionLink = $"https://github.com/btcpayserver/btcpayserver/releases/tag/v{notification.Version}";
|
||||
}
|
||||
}
|
||||
public NewVersionNotification()
|
||||
{
|
||||
|
||||
|
@ -16,11 +24,5 @@ namespace BTCPayServer.Services.Notifications.Blobs
|
|||
Version = version;
|
||||
}
|
||||
public string Version { get; set; }
|
||||
|
||||
public override void FillViewModel(NotificationViewModel vm)
|
||||
{
|
||||
vm.Body = $"New version {Version} released!";
|
||||
vm.ActionLink = $"https://github.com/btcpayserver/btcpayserver/releases/tag/v{Version}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Services.Notifications.Blobs
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class NotificationAttribute : Attribute
|
||||
{
|
||||
public NotificationAttribute(string notificationType)
|
||||
{
|
||||
NotificationType = notificationType;
|
||||
}
|
||||
public string NotificationType { get; }
|
||||
}
|
||||
}
|
25
BTCPayServer/Services/Notifications/INotificationHandler.cs
Normal file
25
BTCPayServer/Services/Notifications/INotificationHandler.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Models.NotificationViewModels;
|
||||
|
||||
namespace BTCPayServer.Services.Notifications
|
||||
{
|
||||
public interface INotificationHandler
|
||||
{
|
||||
string NotificationType { get; }
|
||||
Type NotificationBlobType { get; }
|
||||
void FillViewModel(object notification, NotificationViewModel vm);
|
||||
}
|
||||
public abstract class NotificationHandler<TNotification> : INotificationHandler
|
||||
{
|
||||
public abstract string NotificationType { get; }
|
||||
Type INotificationHandler.NotificationBlobType => typeof(TNotification);
|
||||
void INotificationHandler.FillViewModel(object notification, NotificationViewModel vm)
|
||||
{
|
||||
FillViewModel((TNotification)notification, vm);
|
||||
}
|
||||
protected abstract void FillViewModel(TNotification notification, NotificationViewModel vm);
|
||||
}
|
||||
}
|
|
@ -6,8 +6,10 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models.NotificationViewModels;
|
||||
using Google.Apis.Storage.v1.Data;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Services.Notifications
|
||||
{
|
||||
|
@ -16,12 +18,16 @@ namespace BTCPayServer.Services.Notifications
|
|||
private readonly ApplicationDbContextFactory _factory;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly Dictionary<string, INotificationHandler> _handlersByNotificationType;
|
||||
private readonly Dictionary<Type, INotificationHandler> _handlersByBlobType;
|
||||
|
||||
public NotificationManager(ApplicationDbContextFactory factory, UserManager<ApplicationUser> userManager, IMemoryCache memoryCache)
|
||||
public NotificationManager(ApplicationDbContextFactory factory, UserManager<ApplicationUser> userManager, IMemoryCache memoryCache, IEnumerable<INotificationHandler> handlers)
|
||||
{
|
||||
_factory = factory;
|
||||
_userManager = userManager;
|
||||
_memoryCache = memoryCache;
|
||||
_handlersByNotificationType = handlers.ToDictionary(h => h.NotificationType);
|
||||
_handlersByBlobType = handlers.ToDictionary(h => h.NotificationBlobType);
|
||||
}
|
||||
|
||||
private const int _cacheExpiryMs = 5000;
|
||||
|
@ -55,7 +61,7 @@ namespace BTCPayServer.Services.Notifications
|
|||
.Where(a => a.ApplicationUserId == userId && !a.Seen)
|
||||
.OrderByDescending(a => a.Created)
|
||||
.Take(5)
|
||||
.Select(a => a.ToViewModel())
|
||||
.Select(a => ToViewModel(a))
|
||||
.ToList();
|
||||
}
|
||||
catch (System.IO.InvalidDataException)
|
||||
|
@ -77,6 +83,33 @@ namespace BTCPayServer.Services.Notifications
|
|||
|
||||
return resp;
|
||||
}
|
||||
|
||||
public NotificationViewModel ToViewModel(NotificationData data)
|
||||
{
|
||||
var handler = GetHandler(data.NotificationType);
|
||||
var notification = JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), handler.NotificationBlobType);
|
||||
var obj = new NotificationViewModel
|
||||
{
|
||||
Id = data.Id,
|
||||
Created = data.Created,
|
||||
Seen = data.Seen
|
||||
};
|
||||
handler.FillViewModel(notification, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public INotificationHandler GetHandler(string notificationId)
|
||||
{
|
||||
if (_handlersByNotificationType.TryGetValue(notificationId, out var h))
|
||||
return h;
|
||||
throw new InvalidOperationException($"No INotificationHandler found for {notificationId}");
|
||||
}
|
||||
public INotificationHandler GetHandler(Type blobType)
|
||||
{
|
||||
if (_handlersByBlobType.TryGetValue(blobType, out var h))
|
||||
return h;
|
||||
throw new InvalidOperationException($"No INotificationHandler found for {blobType.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationSummaryViewModel
|
||||
|
|
|
@ -16,15 +16,17 @@ namespace BTCPayServer.Services.Notifications
|
|||
private readonly ApplicationDbContextFactory _contextFactory;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
private readonly NotificationManager _notificationManager;
|
||||
|
||||
public NotificationSender(ApplicationDbContextFactory contextFactory, UserManager<ApplicationUser> userManager, EventAggregator eventAggregator)
|
||||
public NotificationSender(ApplicationDbContextFactory contextFactory, UserManager<ApplicationUser> userManager, EventAggregator eventAggregator, NotificationManager notificationManager)
|
||||
{
|
||||
_contextFactory = contextFactory;
|
||||
_userManager = userManager;
|
||||
_eventAggregator = eventAggregator;
|
||||
_notificationManager = notificationManager;
|
||||
}
|
||||
|
||||
public async Task SendNotification(NotificationScope scope, BaseNotification notification)
|
||||
public async Task SendNotification(NotificationScope scope, object notification)
|
||||
{
|
||||
if (scope == null)
|
||||
throw new ArgumentNullException(nameof(scope));
|
||||
|
@ -41,25 +43,16 @@ namespace BTCPayServer.Services.Notifications
|
|||
Id = Guid.NewGuid().ToString(),
|
||||
Created = DateTimeOffset.UtcNow,
|
||||
ApplicationUserId = uid,
|
||||
NotificationType = GetNotificationTypeString(notification.GetType()),
|
||||
NotificationType = _notificationManager.GetHandler(notification.GetType()).NotificationType,
|
||||
Blob = ZipUtils.Zip(obj),
|
||||
Seen = false
|
||||
};
|
||||
db.Notifications.Add(data);
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetNotificationTypeString(Type type)
|
||||
{
|
||||
var str = type.GetCustomAttribute<NotificationAttribute>()?.NotificationType;
|
||||
if (str is null)
|
||||
throw new NotSupportedException($"{type} is not a notification");
|
||||
return str;
|
||||
}
|
||||
|
||||
private async Task<string[]> GetUsers(NotificationScope scope)
|
||||
{
|
||||
if (scope is AdminScope)
|
||||
|
|
Loading…
Add table
Reference in a new issue