✨ Add account statuses
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DysonNetwork.Sphere.Auth;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -15,6 +16,7 @@ public class AccountController(
|
||||
FileService fs,
|
||||
AuthService auth,
|
||||
AccountService accounts,
|
||||
AccountEventService events,
|
||||
MagicSpellService spells
|
||||
) : ControllerBase
|
||||
{
|
||||
@ -203,6 +205,62 @@ public class AccountController(
|
||||
return profile;
|
||||
}
|
||||
|
||||
public class StatusRequest
|
||||
{
|
||||
public StatusAttitude Attitude { get; set; }
|
||||
public bool IsInvisible { get; set; }
|
||||
public bool IsNotDisturb { get; set; }
|
||||
[MaxLength(1024)] public string? Label { get; set; }
|
||||
public Instant? ClearedAt { get; set; }
|
||||
}
|
||||
|
||||
[HttpGet("me/statuses")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<Status>> GetCurrentStatus()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
var status = await events.GetStatus(currentUser.Id);
|
||||
return Ok(status);
|
||||
}
|
||||
|
||||
[HttpPost("me/statuses")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "accounts.statuses.create")]
|
||||
public async Task<ActionResult<Status>> CreateStatus([FromBody] StatusRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
|
||||
var status = new Status
|
||||
{
|
||||
AccountId = currentUser.Id,
|
||||
Attitude = request.Attitude,
|
||||
IsInvisible = request.IsInvisible,
|
||||
IsNotDisturb = request.IsNotDisturb,
|
||||
Label = request.Label,
|
||||
ClearedAt = request.ClearedAt
|
||||
};
|
||||
|
||||
return await events.CreateStatus(currentUser, status);
|
||||
}
|
||||
|
||||
[HttpDelete("me/statuses")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult> DeleteStatus()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var status = await db.AccountStatuses
|
||||
.Where(s => s.AccountId == currentUser.Id)
|
||||
.Where(s => s.ClearedAt == null || s.ClearedAt > now)
|
||||
.OrderByDescending(s => s.CreatedAt)
|
||||
.FirstOrDefaultAsync();
|
||||
if (status is null) return NotFound();
|
||||
|
||||
await events.ClearStatus(currentUser, status);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpGet("search")]
|
||||
public async Task<List<Account>> Search([FromQuery] string query, [FromQuery] int take = 20)
|
||||
{
|
||||
|
79
DysonNetwork.Sphere/Account/AccountEventService.cs
Normal file
79
DysonNetwork.Sphere/Account/AccountEventService.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using DysonNetwork.Sphere.Activity;
|
||||
using DysonNetwork.Sphere.Connection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NodaTime;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
public class AccountEventService(AppDatabase db, ActivityService act, WebSocketService ws, IMemoryCache cache)
|
||||
{
|
||||
private const string StatusCacheKey = "account_status_";
|
||||
|
||||
public async Task<Status> GetStatus(long userId)
|
||||
{
|
||||
var cacheKey = $"{StatusCacheKey}{userId}";
|
||||
if (cache.TryGetValue(cacheKey, out Status? cachedStatus))
|
||||
return cachedStatus!;
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var status = await db.AccountStatuses
|
||||
.Where(e => e.AccountId == userId)
|
||||
.Where(e => e.ClearedAt == null || e.ClearedAt > now)
|
||||
.OrderByDescending(e => e.CreatedAt)
|
||||
.FirstOrDefaultAsync();
|
||||
if (status is not null)
|
||||
{
|
||||
cache.Set(cacheKey, status, TimeSpan.FromMinutes(5));
|
||||
return status;
|
||||
}
|
||||
|
||||
var isOnline = ws.GetAccountIsConnected(userId);
|
||||
if (isOnline)
|
||||
{
|
||||
return new Status
|
||||
{
|
||||
Attitude = StatusAttitude.Neutral,
|
||||
IsOnline = true,
|
||||
Label = "Online",
|
||||
AccountId = userId,
|
||||
};
|
||||
}
|
||||
|
||||
return new Status
|
||||
{
|
||||
Attitude = StatusAttitude.Neutral,
|
||||
IsOnline = false,
|
||||
Label = "Offline",
|
||||
AccountId = userId,
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Status> CreateStatus(Account user, Status status)
|
||||
{
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
await db.AccountStatuses
|
||||
.Where(x => x.AccountId == user.Id && (x.ClearedAt == null || x.ClearedAt > now))
|
||||
.ExecuteUpdateAsync(s => s.SetProperty(x => x.ClearedAt, now));
|
||||
|
||||
db.AccountStatuses.Add(status);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
await act.CreateActivity(
|
||||
user,
|
||||
"accounts.status",
|
||||
$"account.statuses/{status.Id}",
|
||||
ActivityVisibility.Friends
|
||||
);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public async Task ClearStatus(Account user, Status status)
|
||||
{
|
||||
status.ClearedAt = SystemClock.Instance.GetCurrentInstant();
|
||||
db.Update(status);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
26
DysonNetwork.Sphere/Account/Status.cs
Normal file
26
DysonNetwork.Sphere/Account/Status.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Account;
|
||||
|
||||
public enum StatusAttitude
|
||||
{
|
||||
Positive,
|
||||
Negative,
|
||||
Neutral
|
||||
}
|
||||
|
||||
public class Status : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public StatusAttitude Attitude { get; set; }
|
||||
[NotMapped] public bool IsOnline { get; set; }
|
||||
public bool IsInvisible { get; set; }
|
||||
public bool IsNotDisturb { get; set; }
|
||||
[MaxLength(1024)] public string? Label { get; set; }
|
||||
public Instant? ClearedAt { get; set; }
|
||||
|
||||
public long AccountId { get; set; }
|
||||
public Account Account { get; set; } = null!;
|
||||
}
|
Reference in New Issue
Block a user