Files
.github
.idx
DysonNetwork.Sphere
Account
Account.cs
AccountController.cs
AccountCurrentController.cs
AccountEventService.cs
AccountService.cs
ActionLog.cs
ActionLogService.cs
Badge.cs
Event.cs
MagicSpell.cs
MagicSpellController.cs
MagicSpellService.cs
Notification.cs
NotificationController.cs
NotificationService.cs
Relationship.cs
RelationshipController.cs
RelationshipService.cs
Activity
Auth
Chat
Connection
Developer
Email
Localization
Migrations
Pages
Permission
Post
Properties
Publisher
Realm
Resources
Sticker
Storage
Wallet
wwwroot
.DS_Store
.gitignore
AppDatabase.cs
Dockerfile
DysonNetwork.Sphere.csproj
DysonNetwork.Sphere.csproj.DotSettings.user
DysonNetwork.Sphere.http
Program.cs
appsettings.json
package.json
postcss.config.js
tailwind.config.js
.dockerignore
.gitignore
DysonNetwork.sln
DysonNetwork.sln.DotSettings.user
compose.yaml
Swarm/DysonNetwork.Sphere/Account/NotificationController.cs

166 lines
5.9 KiB
C#

using System.ComponentModel.DataAnnotations;
using DysonNetwork.Sphere.Auth;
using DysonNetwork.Sphere.Permission;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Sphere.Account;
[ApiController]
[Route("/notifications")]
public class NotificationController(AppDatabase db, NotificationService nty) : ControllerBase
{
[HttpGet("count")]
[Authorize]
public async Task<ActionResult<int>> CountUnreadNotifications()
{
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();
return Ok(count);
}
[HttpGet]
[Authorize]
public async Task<ActionResult<List<Notification>>> ListNotifications(
[FromQuery] int offset = 0,
// The page size set to 5 is to avoid the client pulled the notification
// but didn't render it in the screen-viewable region.
[FromQuery] int take = 5
)
{
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
if (currentUserValue is not Account currentUser) 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();
await nty.MarkNotificationsViewed(notifications);
return Ok(notifications);
}
public class PushNotificationSubscribeRequest
{
[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("CurrentSession", out var currentSessionValue);
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
var currentUser = currentUserValue as Account;
if (currentUser == null) return Unauthorized();
var currentSession = currentSessionValue as Session;
if (currentSession == null) return Unauthorized();
var result =
await nty.SubscribePushNotification(currentUser, request.Provider, currentSession.Challenge.DeviceId!,
request.DeviceToken);
return Ok(result);
}
[HttpDelete("subscription")]
[Authorize]
public async Task<ActionResult<int>> UnsubscribeFromPushNotification()
{
HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue);
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
var currentUser = currentUserValue as Account;
if (currentUser == null) return Unauthorized();
var currentSession = currentSessionValue as Session;
if (currentSession == null) return Unauthorized();
var affectedRows = await db.NotificationPushSubscriptions
.Where(s =>
s.AccountId == currentUser.Id &&
s.DeviceId == currentSession.Challenge.DeviceId
).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
{
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
UpdatedAt = SystemClock.Instance.GetCurrentInstant(),
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
{
CreatedAt = SystemClock.Instance.GetCurrentInstant(),
UpdatedAt = SystemClock.Instance.GetCurrentInstant(),
Topic = request.Topic,
Title = request.Title,
Subtitle = request.Subtitle,
Content = request.Content,
Meta = request.Meta,
},
accounts,
save
);
return Ok();
}
}