Sharable rewind point

This commit is contained in:
2025-12-27 14:24:35 +08:00
parent b51a086031
commit bb5d70eddb
3 changed files with 94 additions and 0 deletions

View File

@@ -8,6 +8,14 @@ namespace DysonNetwork.Pass.Rewind;
[Route("/api/rewind")]
public class AccountRewindController(AccountRewindService rewindSrv) : ControllerBase
{
[HttpGet("{code}")]
public async Task<ActionResult<SnRewindPoint>> GetRewindPoint([FromRoute] string code)
{
var point = await rewindSrv.GetPublicRewindPoint(code);
if (point is null) return NotFound();
return Ok(point);
}
[HttpGet("me")]
[Authorize]
public async Task<ActionResult<SnRewindPoint>> GetCurrentRewindPoint()
@@ -16,4 +24,36 @@ public class AccountRewindController(AccountRewindService rewindSrv) : Controlle
var point = await rewindSrv.GetOrCreateRewindPoint(currentUser.Id);
return Ok(point);
}
[HttpPost("me/{year:int}/public")]
[Authorize]
public async Task<ActionResult<SnRewindPoint>> SetRewindPointPublic([FromRoute] int year)
{
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
var point = await rewindSrv.SetRewindPointPublic(currentUser.Id, year);
return Ok(point);
}
catch (InvalidOperationException error)
{
return BadRequest(error.Message);
}
}
[HttpPost("me/{year:int}/private")]
[Authorize]
public async Task<ActionResult<SnRewindPoint>> SetRewindPointPrivate([FromRoute] int year)
{
if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
try
{
var point = await rewindSrv.SetRewindPointPrivate(currentUser.Id, year);
return Ok(point);
}
catch (InvalidOperationException error)
{
return BadRequest(error.Message);
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Security.Cryptography;
using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Proto;
using Grpc.Net.Client;
@@ -75,4 +76,55 @@ public class AccountRewindService(
return await CreateRewindPoint(accountId);
}
public async Task<SnRewindPoint?> GetPublicRewindPoint(string code)
{
var point = await db.RewindPoints
.Where(p => p.SharableCode == code)
.OrderBy(p => p.CreatedAt)
.FirstOrDefaultAsync();
return point;
}
public async Task<SnRewindPoint> SetRewindPointPublic(Guid accountId, int year)
{
var point = await db.RewindPoints
.Where(p => p.AccountId == accountId && p.Year == year)
.OrderBy(p => p.CreatedAt)
.FirstOrDefaultAsync();
if (point is null) throw new InvalidOperationException("No rewind point was found.");
point.SharableCode = _GenerateRandomString(16);
db.RewindPoints.Update(point);
await db.SaveChangesAsync();
return point;
}
public async Task<SnRewindPoint> SetRewindPointPrivate(Guid accountId, int year)
{
var point = await db.RewindPoints
.Where(p => p.AccountId == accountId && p.Year == year)
.OrderBy(p => p.CreatedAt)
.FirstOrDefaultAsync();
if (point is null) throw new InvalidOperationException("No rewind point was found.");
point.SharableCode = null;
db.RewindPoints.Update(point);
await db.SaveChangesAsync();
return point;
}
private static string _GenerateRandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var result = new char[length];
using var rng = RandomNumberGenerator.Create();
for (var i = 0; i < length; i++)
{
var bytes = new byte[1];
rng.GetBytes(bytes);
result[i] = chars[bytes[0] % chars.Length];
}
return new string(result);
}
}

View File

@@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DysonNetwork.Shared.Models;
@@ -13,6 +14,7 @@ public class SnRewindPoint : ModelBase
/// this field provide the clues for the client to parsing the data correctly.
/// </summary>
public int SchemaVersion { get; set; } = 1;
[MaxLength(4096)] public string? SharableCode { get; set; }
[Column(TypeName = "jsonb")] public Dictionary<string, object?> Data { get; set; } = new();