2020-06-28 21:44:35 -05:00
|
|
|
using System;
|
2020-10-20 13:09:09 +02:00
|
|
|
using System.Collections.Generic;
|
2020-06-15 16:45:29 +09:00
|
|
|
using System.Linq;
|
2020-05-27 18:41:00 -05:00
|
|
|
using System.Threading.Tasks;
|
2020-11-17 13:46:23 +01:00
|
|
|
using BTCPayServer.Abstractions.Contracts;
|
2020-06-11 23:52:46 -05:00
|
|
|
using BTCPayServer.Data;
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
2020-10-20 13:09:09 +02:00
|
|
|
using Microsoft.EntityFrameworkCore;
|
2020-06-15 16:45:29 +09:00
|
|
|
using Newtonsoft.Json;
|
2020-05-27 18:41:00 -05:00
|
|
|
|
2020-06-14 23:47:11 -05:00
|
|
|
namespace BTCPayServer.Services.Notifications
|
2020-05-27 18:41:00 -05:00
|
|
|
{
|
2020-06-24 10:23:16 +02:00
|
|
|
public class UserNotificationsUpdatedEvent
|
|
|
|
{
|
|
|
|
public string UserId { get; set; }
|
2020-12-11 21:14:50 -08:00
|
|
|
public override string ToString()
|
|
|
|
{
|
|
|
|
return string.Empty;
|
|
|
|
}
|
2020-06-24 10:23:16 +02:00
|
|
|
}
|
2020-06-11 23:52:46 -05:00
|
|
|
public class NotificationSender
|
2020-05-27 18:41:00 -05:00
|
|
|
{
|
2020-06-15 01:25:55 -05:00
|
|
|
private readonly ApplicationDbContextFactory _contextFactory;
|
2020-06-11 23:52:46 -05:00
|
|
|
private readonly UserManager<ApplicationUser> _userManager;
|
2020-06-16 23:29:25 +09:00
|
|
|
private readonly NotificationManager _notificationManager;
|
2020-06-11 23:52:46 -05:00
|
|
|
|
2020-06-28 17:55:27 +09:00
|
|
|
public NotificationSender(ApplicationDbContextFactory contextFactory, UserManager<ApplicationUser> userManager, NotificationManager notificationManager)
|
2020-05-27 18:41:00 -05:00
|
|
|
{
|
2020-06-15 01:25:55 -05:00
|
|
|
_contextFactory = contextFactory;
|
2020-06-11 23:52:46 -05:00
|
|
|
_userManager = userManager;
|
2020-06-16 23:29:25 +09:00
|
|
|
_notificationManager = notificationManager;
|
2020-06-11 23:52:46 -05:00
|
|
|
}
|
|
|
|
|
2020-10-20 13:09:09 +02:00
|
|
|
public async Task SendNotification(NotificationScope scope, BaseNotification notification)
|
2020-06-11 23:52:46 -05:00
|
|
|
{
|
2021-12-28 17:39:54 +09:00
|
|
|
ArgumentNullException.ThrowIfNull(scope);
|
|
|
|
ArgumentNullException.ThrowIfNull(notification);
|
2020-10-20 13:09:09 +02:00
|
|
|
var users = await GetUsers(scope, notification.Identifier);
|
2020-12-11 15:11:08 +01:00
|
|
|
await using (var db = _contextFactory.CreateContext())
|
2020-06-15 01:22:09 -05:00
|
|
|
{
|
2020-06-15 16:45:29 +09:00
|
|
|
foreach (var uid in users)
|
2020-06-11 23:52:46 -05:00
|
|
|
{
|
2020-06-15 17:18:45 +09:00
|
|
|
var obj = JsonConvert.SerializeObject(notification);
|
2020-06-15 16:45:29 +09:00
|
|
|
var data = new NotificationData
|
|
|
|
{
|
|
|
|
Id = Guid.NewGuid().ToString(),
|
|
|
|
Created = DateTimeOffset.UtcNow,
|
|
|
|
ApplicationUserId = uid,
|
2020-10-20 13:09:09 +02:00
|
|
|
NotificationType = notification.NotificationType,
|
2020-06-15 16:45:29 +09:00
|
|
|
Blob = ZipUtils.Zip(obj),
|
|
|
|
Seen = false
|
|
|
|
};
|
2020-12-11 15:11:08 +01:00
|
|
|
await db.Notifications.AddAsync(data);
|
2020-06-11 23:52:46 -05:00
|
|
|
}
|
2020-06-15 01:22:09 -05:00
|
|
|
await db.SaveChangesAsync();
|
|
|
|
}
|
2020-06-23 03:06:02 +02:00
|
|
|
foreach (string user in users)
|
|
|
|
{
|
|
|
|
_notificationManager.InvalidateNotificationCache(user);
|
|
|
|
}
|
2020-06-15 16:45:29 +09:00
|
|
|
}
|
2020-06-15 01:22:09 -05:00
|
|
|
|
2020-10-20 13:09:09 +02:00
|
|
|
private async Task<string[]> GetUsers(NotificationScope scope, string notificationIdentifier)
|
2020-06-15 16:45:29 +09:00
|
|
|
{
|
2020-10-20 13:09:09 +02:00
|
|
|
await using var ctx = _contextFactory.CreateContext();
|
|
|
|
|
|
|
|
var split = notificationIdentifier.Split('_', StringSplitOptions.None);
|
|
|
|
var terms = new List<string>();
|
|
|
|
foreach (var t in split)
|
2020-06-15 01:22:09 -05:00
|
|
|
{
|
2020-10-20 13:09:09 +02:00
|
|
|
terms.Add(terms.Any() ? $"{terms.Last().TrimEnd(';')}_{t};" : $"{t};");
|
2020-06-15 16:45:29 +09:00
|
|
|
}
|
2020-10-20 13:09:09 +02:00
|
|
|
IQueryable<ApplicationUser> query;
|
|
|
|
switch (scope)
|
2020-06-15 17:18:45 +09:00
|
|
|
{
|
2020-10-20 13:09:09 +02:00
|
|
|
case AdminScope _:
|
2021-12-31 16:59:02 +09:00
|
|
|
{
|
|
|
|
query = _userManager.GetUsersInRoleAsync(Roles.ServerAdmin).Result.AsQueryable();
|
2020-10-20 13:09:09 +02:00
|
|
|
|
2021-12-31 16:59:02 +09:00
|
|
|
break;
|
|
|
|
}
|
2020-10-20 13:09:09 +02:00
|
|
|
case StoreScope s:
|
|
|
|
query = ctx.UserStore
|
|
|
|
.Include(store => store.ApplicationUser)
|
|
|
|
.Where(u => u.StoreDataId == s.StoreId)
|
|
|
|
.Select(u => u.ApplicationUser);
|
|
|
|
break;
|
|
|
|
case UserScope userScope:
|
|
|
|
query = ctx.Users
|
2021-12-31 16:59:02 +09:00
|
|
|
.Where(user => user.Id == userScope.UserId);
|
2020-10-20 13:09:09 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new NotSupportedException("Notification scope not supported");
|
2021-12-31 16:59:02 +09:00
|
|
|
|
|
|
|
|
2020-06-15 17:18:45 +09:00
|
|
|
}
|
2020-10-20 13:09:09 +02:00
|
|
|
query = query.Where(store => store.DisabledNotifications != "all");
|
|
|
|
foreach (string term in terms)
|
|
|
|
{
|
2020-10-27 08:19:41 +01:00
|
|
|
// Cannot specify StringComparison as EF core does not support it and would attempt client-side evaluation
|
|
|
|
// ReSharper disable once CA1307
|
2020-11-19 12:34:56 +09:00
|
|
|
#pragma warning disable CA1307 // Specify StringComparison
|
2021-12-31 16:59:02 +09:00
|
|
|
query = query.Where(user => user.DisabledNotifications == null || !user.DisabledNotifications.Contains(term));
|
2020-11-19 12:34:56 +09:00
|
|
|
#pragma warning restore CA1307 // Specify StringComparison
|
2020-10-20 13:09:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return query.Select(user => user.Id).ToArray();
|
2020-05-27 18:41:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|