🐛 Bug fixes on posts and publishers

This commit is contained in:
2025-04-19 23:51:27 +08:00
parent fb1de3da9e
commit c43ff6be7b
7 changed files with 46 additions and 11 deletions

View File

@ -26,6 +26,8 @@ public class UserInfoMiddleware(RequestDelegate next, IMemoryCache cache)
if (user is not null)
{
context.Items["CurrentUser"] = user;
var prefix = user.IsSuperuser ? "super:" : "";
context.Items["CurrentIdentity"] = $"{prefix}{userId}";
}
}

View File

@ -11,4 +11,4 @@ g = _, _, _
e = some(where (p.eft == allow))
[matchers]
m = r.sub.StartsWith("super:") || (g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act)
m = regexMatch(r.sub, "^super:") || (g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act)

View File

@ -1,12 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Casbin;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NodaTime;
namespace DysonNetwork.Sphere.Post;
[ApiController]
[Route("/posts")]
public class PostController(AppDatabase db, PostService ps) : ControllerBase
public class PostController(AppDatabase db, PostService ps, IEnforcer enforcer) : ControllerBase
{
[HttpGet]
public async Task<ActionResult<List<Post>>> ListPosts([FromQuery] int offset = 0, [FromQuery] int take = 20)
@ -99,6 +101,7 @@ public class PostController(AppDatabase db, PostService ps) : ControllerBase
[MaxLength(8)] public List<string>? Categories { get; set; }
[MaxLength(32)] public List<string>? Attachments { get; set; }
public Dictionary<string, object>? Meta { get; set; }
public Instant? PublishedAt { get; set; }
}
[HttpPost]
@ -108,6 +111,8 @@ public class PostController(AppDatabase db, PostService ps) : ControllerBase
)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "posts", "create"))
return StatusCode(403);
Publisher? publisher;
if (publisherName is null)
@ -136,8 +141,10 @@ public class PostController(AppDatabase db, PostService ps) : ControllerBase
Description = request.Description,
Content = request.Content,
Visibility = request.Visibility ?? PostVisibility.Public,
PublishedAt = request.PublishedAt,
Type = request.Type ?? PostType.Moment,
Meta = request.Meta,
Publisher = publisher,
};
try
@ -190,7 +197,8 @@ public class PostController(AppDatabase db, PostService ps) : ControllerBase
post,
attachments: request.Attachments,
tags: request.Tags,
categories: request.Categories
categories: request.Categories,
publishedAt: request.PublishedAt
);
}
catch (InvalidOperationException err)

View File

@ -13,6 +13,12 @@ public class PostService(AppDatabase db, FileService fs)
List<string>? categories = null
)
{
if (post.PublishedAt is not null)
{
if (post.PublishedAt.Value.ToDateTimeUtc() < DateTime.UtcNow)
throw new InvalidOperationException("Cannot create the post which published in the past.");
}
if (attachments is not null)
{
post.Attachments = await db.Files.Where(e => attachments.Contains(e.Id)).ToListAsync();
@ -46,7 +52,7 @@ public class PostService(AppDatabase db, FileService fs)
if (post.Categories.Count != categories.Distinct().Count())
throw new InvalidOperationException("Categories contains one or more categories that wasn't exists.");
}
if (post.Empty)
throw new InvalidOperationException("Cannot create a post with barely no content.");
@ -63,11 +69,21 @@ public class PostService(AppDatabase db, FileService fs)
Post post,
List<string>? attachments = null,
List<string>? tags = null,
List<string>? categories = null
List<string>? categories = null,
Instant? publishedAt = null
)
{
post.EditedAt = Instant.FromDateTimeUtc(DateTime.UtcNow);
if (publishedAt is not null)
{
// User cannot set the published at to the past to prevent scam,
// But we can just let the controller set the published at, because when no changes to
// the published at will blocked the update operation
if (publishedAt.Value.ToDateTimeUtc() < DateTime.UtcNow)
throw new InvalidOperationException("Cannot set the published at to the past.");
}
if (attachments is not null)
{
var records = await db.Files.Where(e => attachments.Contains(e.Id)).ToListAsync();
@ -87,7 +103,7 @@ public class PostService(AppDatabase db, FileService fs)
await fs.MarkUsageRangeAsync(added, 1);
await fs.MarkUsageRangeAsync(removed, -1);
}
if (tags is not null)
{
var existingTags = await db.PostTags.Where(e => tags.Contains(e.Slug)).ToListAsync();
@ -111,14 +127,14 @@ public class PostService(AppDatabase db, FileService fs)
post.Categories = await db.PostCategories.Where(e => categories.Contains(e.Slug)).ToListAsync();
if (post.Categories.Count != categories.Distinct().Count())
throw new InvalidOperationException("Categories contains one or more categories that wasn't exists.");
}
}
if (post.Empty)
throw new InvalidOperationException("Cannot edit a post to barely no content.");
db.Update(post);
await db.SaveChangesAsync();
return post;
}

View File

@ -20,6 +20,8 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
var publisher = await db.Publishers
.Where(e => e.Name == name)
.Include(e => e.Picture)
.Include(e => e.Background)
.FirstOrDefaultAsync();
if (publisher is null) return NotFound();
@ -37,6 +39,8 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
.Where(m => m.AccountId == userId)
.Where(m => m.JoinedAt != null)
.Include(e => e.Publisher)
.Include(e => e.Publisher.Picture)
.Include(e => e.Publisher.Background)
.ToListAsync();
return members.Select(m => m.Publisher).ToList();
@ -53,6 +57,8 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
.Where(m => m.AccountId == userId)
.Where(m => m.JoinedAt == null)
.Include(e => e.Publisher)
.Include(e => e.Publisher.Picture)
.Include(e => e.Publisher.Background)
.ToListAsync();
return members.ToList();
@ -164,7 +170,8 @@ public class PublisherController(AppDatabase db, PublisherService ps, FileServic
public async Task<ActionResult<Publisher>> CreatePublisherIndividual(PublisherRequest request)
{
if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized();
if (!await enforcer.EnforceAsync(currentUser.Id.ToString(), "global", "publishers", "create"))
if (!await enforcer.EnforceAsync((string)HttpContext.Items["CurrentIdentity"]!, "global", "publishers",
"create"))
return StatusCode(403);
var takenName = request.Name ?? currentUser.Name;

View File

@ -51,6 +51,7 @@ var casbinDbContext = new CasbinDbContext<int>(
var casbinEfcore = new EFCoreAdapter<int>(casbinDbContext);
casbinDbContext.Database.EnsureCreated();
var casbinEncofcer = new Enforcer("Casbin.conf", casbinEfcore);
casbinEncofcer.EnableCache(true);
casbinEncofcer.LoadPolicy();
builder.Services.AddSingleton<IEnforcer>(casbinEncofcer);