diff --git a/BTCPayServer/Controllers/NotificationsController.cs b/BTCPayServer/Controllers/NotificationsController.cs index 3245d91c8..1ef324ecf 100644 --- a/BTCPayServer/Controllers/NotificationsController.cs +++ b/BTCPayServer/Controllers/NotificationsController.cs @@ -47,7 +47,7 @@ namespace BTCPayServer.Controllers .OrderByDescending(a => a.Created) .Skip(skip).Take(count) .Where(a => a.ApplicationUserId == userId) - .Select(a => a.ViewModel()) + .Select(a => a.ToViewModel()) .ToList(), Total = _db.Notifications.Where(a => a.ApplicationUserId == userId).Count() }; diff --git a/BTCPayServer/Models/NotificationViewModels/IndexViewModel.cs b/BTCPayServer/Models/NotificationViewModels/IndexViewModel.cs index 093b1cde0..a924a3fef 100644 --- a/BTCPayServer/Models/NotificationViewModels/IndexViewModel.cs +++ b/BTCPayServer/Models/NotificationViewModels/IndexViewModel.cs @@ -30,22 +30,26 @@ namespace BTCPayServer.Models.NotificationViewModels public static class NotificationViewModelExt { - public static NotificationViewModel ViewModel(this NotificationData data) + static Dictionary _NotificationTypes; + static NotificationViewModelExt() { - var baseType = typeof(BaseNotification); + _NotificationTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Select(t => (t, NotificationType: t.GetCustomAttribute()?.NotificationType)) + .Where(t => t.NotificationType is string) + .ToDictionary(o => o.NotificationType, o => o.t); + } - var fullTypeName = baseType.FullName.Replace(nameof(BaseNotification), data.NotificationType, StringComparison.OrdinalIgnoreCase); - var parsedType = baseType.Assembly.GetType(fullTypeName); - - var casted = (BaseNotification)JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), parsedType); + 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(ref obj); + casted.FillViewModel(obj); return obj; } diff --git a/BTCPayServer/Services/Notifications/Blobs/BaseNotification.cs b/BTCPayServer/Services/Notifications/Blobs/BaseNotification.cs index 5c75647c9..4a2f56754 100644 --- a/BTCPayServer/Services/Notifications/Blobs/BaseNotification.cs +++ b/BTCPayServer/Services/Notifications/Blobs/BaseNotification.cs @@ -10,6 +10,6 @@ namespace BTCPayServer.Services.Notifications.Blobs // IndexViewModel.cs#32 public abstract class BaseNotification { - public abstract void FillViewModel(ref NotificationViewModel data); + public abstract void FillViewModel(NotificationViewModel data); } } diff --git a/BTCPayServer/Services/Notifications/Blobs/NewVersionNotification.cs b/BTCPayServer/Services/Notifications/Blobs/NewVersionNotification.cs index e29acb105..92f3885ff 100644 --- a/BTCPayServer/Services/Notifications/Blobs/NewVersionNotification.cs +++ b/BTCPayServer/Services/Notifications/Blobs/NewVersionNotification.cs @@ -4,9 +4,9 @@ using Newtonsoft.Json; namespace BTCPayServer.Services.Notifications.Blobs { + [Notification("newversion")] internal class NewVersionNotification : BaseNotification { - internal override string NotificationType => "NewVersionNotification"; public NewVersionNotification() { @@ -17,7 +17,7 @@ namespace BTCPayServer.Services.Notifications.Blobs } public string Version { get; set; } - public override void FillViewModel(ref NotificationViewModel vm) + public override void FillViewModel(NotificationViewModel vm) { vm.Body = $"New version {Version} released!"; vm.ActionLink = $"https://github.com/btcpayserver/btcpayserver/releases/tag/v{Version}"; diff --git a/BTCPayServer/Services/Notifications/Blobs/NotificationAttribute.cs b/BTCPayServer/Services/Notifications/Blobs/NotificationAttribute.cs new file mode 100644 index 000000000..5b1b6d9de --- /dev/null +++ b/BTCPayServer/Services/Notifications/Blobs/NotificationAttribute.cs @@ -0,0 +1,17 @@ +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; } + } +} diff --git a/BTCPayServer/Services/Notifications/NotificationManager.cs b/BTCPayServer/Services/Notifications/NotificationManager.cs index c3f0b3781..e571982fa 100644 --- a/BTCPayServer/Services/Notifications/NotificationManager.cs +++ b/BTCPayServer/Services/Notifications/NotificationManager.cs @@ -55,7 +55,7 @@ namespace BTCPayServer.Services.Notifications .Where(a => a.ApplicationUserId == userId && !a.Seen) .OrderByDescending(a => a.Created) .Take(5) - .Select(a => a.ViewModel()) + .Select(a => a.ToViewModel()) .ToList(); } catch (System.IO.InvalidDataException) diff --git a/BTCPayServer/Services/Notifications/NotificationSender.cs b/BTCPayServer/Services/Notifications/NotificationSender.cs index 2ed534314..35f616ea2 100644 --- a/BTCPayServer/Services/Notifications/NotificationSender.cs +++ b/BTCPayServer/Services/Notifications/NotificationSender.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using BTCPayServer.Data; using BTCPayServer.Events; @@ -24,6 +26,10 @@ namespace BTCPayServer.Services.Notifications public async Task SendNotification(NotificationScope scope, BaseNotification notification) { + if (scope == null) + throw new ArgumentNullException(nameof(scope)); + if (notification == null) + throw new ArgumentNullException(nameof(notification)); var users = await GetUsers(scope); using (var db = _contextFactory.CreateContext()) { @@ -35,7 +41,7 @@ namespace BTCPayServer.Services.Notifications Id = Guid.NewGuid().ToString(), Created = DateTimeOffset.UtcNow, ApplicationUserId = uid, - NotificationType = notification.NotificationType, + NotificationType = GetNotificationTypeString(notification.GetType()), Blob = ZipUtils.Zip(obj), Seen = false }; @@ -46,6 +52,14 @@ namespace BTCPayServer.Services.Notifications } } + private string GetNotificationTypeString(Type type) + { + var str = type.GetCustomAttribute()?.NotificationType; + if (str is null) + throw new NotSupportedException($"{type} is not a notification"); + return str; + } + private async Task GetUsers(NotificationScope scope) { if (scope is AdminScope) diff --git a/BTCPayServer/Views/Account/Login.cshtml b/BTCPayServer/Views/Account/Login.cshtml index b7eaadeca..b899dc9b7 100644 --- a/BTCPayServer/Views/Account/Login.cshtml +++ b/BTCPayServer/Views/Account/Login.cshtml @@ -2,7 +2,6 @@ @inject BTCPayServer.HostedServices.CssThemeManager themeManager @{ ViewData["Title"] = "Log in"; - Layout = "_LayoutWelcome"; } @if (TempData.HasStatusMessage()) {