Revert "feat(blog): add Visibility { Private, Public } to gate post reads"
This reverts commit 33ecfa7ebd.
This commit is contained in:
parent
33ecfa7ebd
commit
42625f5ddd
16 changed files with 46 additions and 5427 deletions
|
|
@ -1,6 +1,5 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Security.Claims;
|
||||
using Yavsc.Blogspot;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
|
||||
|
|
@ -24,21 +23,10 @@ namespace Yavsc.Server.Helpers
|
|||
dbContext.Circle.Include(c => c.Members)
|
||||
.Where(c => c.Members.Any(m => m.MemberId == readerId))
|
||||
.Select(c => c.Id).ToArray();
|
||||
// Mirror of BlogSpotService.Index for an
|
||||
// authenticated reader: Private restricts to the
|
||||
// author; Public is read-through-ACL.
|
||||
return dbContext.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Include(p => p.ACL).Where(x => x.Author.Id == posterId &&
|
||||
(
|
||||
(x.Visibility == Visibility.Private && x.AuthorId == readerId)
|
||||
|| (x.Visibility == Visibility.Public
|
||||
&& (x.ACL == null
|
||||
|| x.ACL.Count == 0
|
||||
|| x.AuthorId == readerId
|
||||
|| (readerCirclesMemberships != null
|
||||
&& x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId)))))
|
||||
));
|
||||
(x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ namespace Yavsc.Models
|
|||
using Bank;
|
||||
using Billing;
|
||||
using Blog;
|
||||
using Blogspot;
|
||||
using Chat;
|
||||
using Drawing;
|
||||
using Forms;
|
||||
|
|
@ -223,17 +222,6 @@ namespace Yavsc.Models
|
|||
.WithMany(u => u.Posts)
|
||||
.HasForeignKey(b => b.AuthorId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
// Store Visibility as a plain int (NOT NULL, default
|
||||
// 0 = Private) so existing rows land on the pre-ACL
|
||||
// behaviour by default. System.Text.Json serialises
|
||||
// the enum as its underlying int, so the wire shape
|
||||
// is a plain number — no JsonConverter needed.
|
||||
builder.Entity<BlogPost>()
|
||||
.Property(b => b.Visibility)
|
||||
.HasConversion<int>()
|
||||
.HasDefaultValue(Visibility.Private)
|
||||
.IsRequired();
|
||||
builder.Entity<Comment>()
|
||||
.HasOne(c => c.Author)
|
||||
.WithMany(u => u.BlogComments)
|
||||
|
|
|
|||
|
|
@ -30,21 +30,6 @@ namespace Yavsc.Models.Blog
|
|||
[Display(Name = "Liste de contrôle d'accès")]
|
||||
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Visibility of this post.
|
||||
/// <para><see cref="Visibility.Public"/> reads through the
|
||||
/// ACL (open when the ACL is empty, narrowed by the ACL
|
||||
/// when it is non-empty). <see cref="Visibility.Private"/>
|
||||
/// ignores the ACL at read time and restricts to author +
|
||||
/// administrators. The ACL list is preserved across
|
||||
/// Private/Public flips so re-opening is lossless.</para>
|
||||
/// <para>Configured as <c>int</c> with default
|
||||
/// <see cref="Visibility.Private"/> in
|
||||
/// <c>ApplicationDbContext.OnModelCreating</c>.</para>
|
||||
/// </summary>
|
||||
[Display(Name = "Visibilité")]
|
||||
public Visibility Visibility { get; set; } = Visibility.Private;
|
||||
|
||||
[Display(Name = "Identifiant de l'auteur")]
|
||||
[ForeignKey("Author")]
|
||||
public string? AuthorId { get; set; }
|
||||
|
|
|
|||
|
|
@ -200,46 +200,28 @@ public class BlogSpotService
|
|||
Where(c => c.Members.Any(m => m.MemberId == viewerId))
|
||||
.Select(c => c.Id).ToArrayAsync();
|
||||
|
||||
// Visibility drives the read gate:
|
||||
// * Public : the ACL decides. Open if the ACL is
|
||||
// empty, narrowed otherwise to author +
|
||||
// ACL circles + admin.
|
||||
// * Private : ACL is ignored at read time. Only the
|
||||
// author (and administrators, checked
|
||||
// elsewhere) can read.
|
||||
// Admin reads (the Administrator role) go through
|
||||
// IsInMsRole("Administrator") upstream in
|
||||
// PermissionHandler; we don't repeat that here so the
|
||||
// listing query stays role-agnostic.
|
||||
posts = _context.BlogSpot
|
||||
.Include(b => b.Author)
|
||||
.Include(p => p.ACL)
|
||||
.Include(p => p.Tags)
|
||||
.Include(p => p.Comments)
|
||||
.Where(p =>
|
||||
(p.Visibility == Visibility.Private && p.AuthorId == viewerId)
|
||||
|| (p.Visibility == Visibility.Public
|
||||
&& (p.ACL == null
|
||||
|| p.ACL.Count == 0
|
||||
|| p.AuthorId == viewerId
|
||||
|| (userCircles != null
|
||||
&& p.ACL.Any(a => userCircles.Contains(a.CircleId))))));
|
||||
.Where(p => p.ACL == null
|
||||
|| p.ACL.Count == 0
|
||||
|| (p.AuthorId == viewerId)
|
||||
|| (userCircles != null &&
|
||||
p.ACL.Any(a => userCircles.Contains(a.CircleId)))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Anonymous callers only see Public posts with no
|
||||
// ACL — anything else either requires membership
|
||||
// (which we have no way to check without an
|
||||
// identity) or is Private.
|
||||
posts = _context.blogSpotPublications
|
||||
.Include(p => p.BlogPost)
|
||||
.Include(b => b.BlogPost.Author)
|
||||
.Include(p => p.BlogPost.ACL)
|
||||
.Include(p => p.BlogPost.Tags)
|
||||
.Include(p => p.BlogPost.Comments)
|
||||
.Where(p => p.BlogPost.Visibility == Visibility.Public
|
||||
&& (p.BlogPost.ACL == null
|
||||
|| p.BlogPost.ACL.Count == 0))
|
||||
.Where(p => p.BlogPost.ACL == null
|
||||
|| p.BlogPost.ACL.Count == 0)
|
||||
.Select(p => p.BlogPost).ToArray();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Blogspot;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
|
@ -56,15 +55,9 @@ public class PermissionHandler : IAuthorizationHandler
|
|||
{
|
||||
if (resource is BlogPost blogPost)
|
||||
{
|
||||
// IsPublic is the authz twin of the Index/listing
|
||||
// filter in BlogSpotService: a post is "publicly
|
||||
// readable" (no membership required) iff its
|
||||
// Visibility is Public and its ACL is empty.
|
||||
// Visibility.Public + non-empty ACL is narrowed by
|
||||
// the ACL, so it does NOT pass IsPublic here; the
|
||||
// caller has to match IsSponsor for that.
|
||||
return blogPost.Visibility == Visibility.Public
|
||||
&& (blogPost.ACL == null || blogPost.ACL.Count == 0);
|
||||
return
|
||||
applicationDbContext.blogSpotPublications
|
||||
.Any(p=>p.BlogpostId == blogPost.Id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue