From bd7e589681a6a7e1040bd6ce03709d54c0b5f430 Mon Sep 17 00:00:00 2001
From: LittleSheep <littlesheep.code@hotmail.com>
Date: Sun, 27 Apr 2025 23:52:41 +0800
Subject: [PATCH] :sparkles: Notification APIs

---
 DysonNetwork.Sphere/Account/Notification.cs   |  1 +
 .../Account/NotificationController.cs         | 59 +++++++++++++++++++
 .../Account/NotificationService.cs            |  2 +
 DysonNetwork.Sphere/Post/PostController.cs    |  2 +
 4 files changed, 64 insertions(+)
 create mode 100644 DysonNetwork.Sphere/Account/NotificationController.cs

diff --git a/DysonNetwork.Sphere/Account/Notification.cs b/DysonNetwork.Sphere/Account/Notification.cs
index 7015d4c..2a0ab55 100644
--- a/DysonNetwork.Sphere/Account/Notification.cs
+++ b/DysonNetwork.Sphere/Account/Notification.cs
@@ -9,6 +9,7 @@ namespace DysonNetwork.Sphere.Account;
 public class Notification : ModelBase
 {
     public Guid Id { get; set; } = Guid.NewGuid();
+    [MaxLength(1024)] public string Topic { get; set; } = null!;
     [MaxLength(1024)] public string? Title { get; set; }
     [MaxLength(2048)] public string? Subtitle { get; set; }
     [MaxLength(4096)] public string? Content { get; set; }
diff --git a/DysonNetwork.Sphere/Account/NotificationController.cs b/DysonNetwork.Sphere/Account/NotificationController.cs
new file mode 100644
index 0000000..f5cafe2
--- /dev/null
+++ b/DysonNetwork.Sphere/Account/NotificationController.cs
@@ -0,0 +1,59 @@
+using System.ComponentModel.DataAnnotations;
+using DysonNetwork.Sphere.Post;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace DysonNetwork.Sphere.Account;
+
+[ApiController]
+[Route("/notifications")]
+public class NotificationController(AppDatabase db, NotificationService nty) : ControllerBase
+{
+    [HttpGet]
+    [Authorize]
+    public async Task<ActionResult<List<Notification>>> ListNotifications([FromQuery] int offset = 0,
+        [FromQuery] int take = 20)
+    {
+        HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
+        var currentUser = currentUserValue as Account;
+        if (currentUser == null) return Unauthorized();
+
+        var totalCount = await db.Notifications
+            .Where(s => s.AccountId == currentUser.Id)
+            .CountAsync();
+        var notifications = await db.Notifications
+            .Where(s => s.AccountId == currentUser.Id)
+            .OrderByDescending(e => e.CreatedAt)
+            .Skip(offset)
+            .Take(take)
+            .ToListAsync();
+
+        Response.Headers["X-Total"] = totalCount.ToString();
+
+        return Ok(notifications);
+    }
+
+    public class PushNotificationSubscribeRequest
+    {
+        [MaxLength(4096)] public string DeviceId { get; set; } = null!;
+        [MaxLength(4096)] public string DeviceToken { get; set; } = null!;
+        public NotificationPushProvider Provider { get; set; }
+    }
+
+    [HttpPut("subscription")]
+    [Authorize]
+    public async Task<ActionResult<NotificationPushSubscription>> SubscribeToPushNotification(
+        [FromBody] PushNotificationSubscribeRequest request
+    )
+    {
+        HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
+        var currentUser = currentUserValue as Account;
+        if (currentUser == null) return Unauthorized();
+
+        var result =
+            await nty.SubscribePushNotification(currentUser, request.Provider, request.DeviceId, request.DeviceToken);
+
+        return Ok(result);
+    }
+}
\ No newline at end of file
diff --git a/DysonNetwork.Sphere/Account/NotificationService.cs b/DysonNetwork.Sphere/Account/NotificationService.cs
index 0082f1f..1317b8b 100644
--- a/DysonNetwork.Sphere/Account/NotificationService.cs
+++ b/DysonNetwork.Sphere/Account/NotificationService.cs
@@ -42,6 +42,8 @@ public class NotificationService
                     : ApnServerType.Development
             }, clientFactory.CreateClient());
     }
+    
+    // TODO remove all push notification with this device id when this device is logged out
 
     public async Task<NotificationPushSubscription> SubscribePushNotification(
         Account account,
diff --git a/DysonNetwork.Sphere/Post/PostController.cs b/DysonNetwork.Sphere/Post/PostController.cs
index 5f1ac9d..bf9b8f7 100644
--- a/DysonNetwork.Sphere/Post/PostController.cs
+++ b/DysonNetwork.Sphere/Post/PostController.cs
@@ -17,6 +17,7 @@ public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer)
         var currentUser = currentUserValue as Account.Account;
 
         var totalCount = await db.Posts
+            .FilterWithVisibility(currentUser, isListing: true)
             .CountAsync();
         var posts = await db.Posts
             .Include(e => e.Publisher)
@@ -77,6 +78,7 @@ public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer)
 
         var totalCount = await db.Posts
             .Where(e => e.RepliedPostId == post.Id)
+            .FilterWithVisibility(currentUser, isListing: true)
             .CountAsync();
         var posts = await db.Posts
             .Where(e => e.RepliedPostId == id)