✨ Notification administration APIs
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using DysonNetwork.Sphere.Auth; | ||||
| using DysonNetwork.Sphere.Permission; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| @@ -16,7 +17,7 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C | ||||
|     { | ||||
|         HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); | ||||
|         if (currentUserValue is not Account currentUser) return Unauthorized(); | ||||
|          | ||||
|  | ||||
|         var count = await db.Notifications | ||||
|             .Where(s => s.AccountId == currentUser.Id && s.ViewedAt == null) | ||||
|             .CountAsync(); | ||||
| @@ -95,4 +96,66 @@ public class NotificationController(AppDatabase db, NotificationService nty) : C | ||||
|             ).ExecuteDeleteAsync(); | ||||
|         return Ok(affectedRows); | ||||
|     } | ||||
|  | ||||
|     public class NotificationRequest | ||||
|     { | ||||
|         [Required] [MaxLength(1024)] public string Topic { get; set; } = null!; | ||||
|         [Required] [MaxLength(1024)] public string Title { get; set; } = null!; | ||||
|         [MaxLength(2048)] public string? Subtitle { get; set; } | ||||
|         [Required] [MaxLength(4096)] public string Content { get; set; } = null!; | ||||
|         public Dictionary<string, object>? Meta { get; set; } | ||||
|         public int Priority { get; set; } = 10; | ||||
|     } | ||||
|  | ||||
|     [HttpPost("broadcast")] | ||||
|     [Authorize] | ||||
|     [RequiredPermission("global", "notifications.broadcast")] | ||||
|     public async Task<ActionResult> BroadcastNotification( | ||||
|         [FromBody] NotificationRequest request, | ||||
|         [FromQuery] bool save = false | ||||
|     ) | ||||
|     { | ||||
|         await nty.BroadcastNotification( | ||||
|             new Notification | ||||
|             { | ||||
|                 Topic = request.Topic, | ||||
|                 Title = request.Title, | ||||
|                 Subtitle = request.Subtitle, | ||||
|                 Content = request.Content, | ||||
|                 Meta = request.Meta, | ||||
|                 Priority = request.Priority, | ||||
|             }, | ||||
|             save | ||||
|         ); | ||||
|         return Ok(); | ||||
|     } | ||||
|  | ||||
|     public class NotificationWithAimRequest : NotificationRequest | ||||
|     { | ||||
|         [Required] public List<Guid> AccountId { get; set; } = null!; | ||||
|     } | ||||
|      | ||||
|     [HttpPost("send")] | ||||
|     [Authorize] | ||||
|     [RequiredPermission("global", "notifications.send")] | ||||
|     public async Task<ActionResult> SendNotification( | ||||
|         [FromBody] NotificationWithAimRequest request, | ||||
|         [FromQuery] bool save = false | ||||
|     ) | ||||
|     { | ||||
|         var accounts = await db.Accounts.Where(a => request.AccountId.Contains(a.Id)).ToListAsync(); | ||||
|         await nty.SendNotificationBatch( | ||||
|             new Notification | ||||
|             { | ||||
|                 Topic = request.Topic, | ||||
|                 Title = request.Title, | ||||
|                 Subtitle = request.Subtitle, | ||||
|                 Content = request.Content, | ||||
|                 Meta = request.Meta, | ||||
|             }, | ||||
|             accounts, | ||||
|             save | ||||
|         ); | ||||
|         return Ok(); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| using CorePush.Apple; | ||||
| using CorePush.Firebase; | ||||
| using DysonNetwork.Sphere.Connection; | ||||
| using EFCore.BulkExtensions; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NodaTime; | ||||
|  | ||||
| @@ -152,6 +153,57 @@ public class NotificationService | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     public async Task BroadcastNotification(Notification notification, bool save = false) | ||||
|     { | ||||
|         if (save) | ||||
|         { | ||||
|             var accounts = await _db.Accounts.ToListAsync(); | ||||
|             var notifications = accounts.Select(x => | ||||
|             { | ||||
|                 notification.Account = x; | ||||
|                 notification.AccountId = x.Id; | ||||
|                 return notification; | ||||
|             }).ToList(); | ||||
|             await _db.BulkInsertAsync(notifications); | ||||
|         } | ||||
|          | ||||
|         var subscribers = await _db.NotificationPushSubscriptions | ||||
|             .ToListAsync(); | ||||
|         var tasks = new List<Task>(); | ||||
|         foreach (var subscriber in subscribers) | ||||
|         { | ||||
|             notification.AccountId = subscriber.AccountId; | ||||
|             tasks.Add(_PushSingleNotification(notification, subscriber)); | ||||
|         } | ||||
|         await Task.WhenAll(tasks); | ||||
|     } | ||||
|  | ||||
|     public async Task SendNotificationBatch(Notification notification, List<Account> accounts, bool save = false) | ||||
|     { | ||||
|         if (save) | ||||
|         { | ||||
|             var notifications = accounts.Select(x => | ||||
|             { | ||||
|                 notification.Account = x; | ||||
|                 notification.AccountId = x.Id; | ||||
|                 return notification; | ||||
|             }).ToList(); | ||||
|             await _db.BulkInsertAsync(notifications); | ||||
|         } | ||||
|          | ||||
|         var accountsId = accounts.Select(x => x.Id).ToList(); | ||||
|         var subscribers = await _db.NotificationPushSubscriptions | ||||
|             .Where(s => accountsId.Contains(s.AccountId)) | ||||
|             .ToListAsync(); | ||||
|         var tasks = new List<Task>(); | ||||
|         foreach (var subscriber in subscribers) | ||||
|         { | ||||
|             notification.AccountId = subscriber.AccountId; | ||||
|             tasks.Add(_PushSingleNotification(notification, subscriber)); | ||||
|         } | ||||
|         await Task.WhenAll(tasks); | ||||
|     } | ||||
|  | ||||
|     private async Task _PushSingleNotification(Notification notification, NotificationPushSubscription subscription) | ||||
|     { | ||||
|         switch (subscription.Provider) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user