refacto publication
This commit is contained in:
parent
67da921bce
commit
1773c5aaea
4 changed files with 16 additions and 43 deletions
20
.vscode/tasks.json
vendored
20
.vscode/tasks.json
vendored
|
|
@ -1,27 +1,13 @@
|
||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"problemMatcher": [
|
|
||||||
{
|
|
||||||
"owner": "dotnet",
|
|
||||||
"fileLocation": ["relative", "${workspaceFolder}"],
|
|
||||||
"source": "dotnet",
|
|
||||||
"pattern": {
|
|
||||||
"regexp": "^\\s*(.*)\\((\\d+),(\\d+)\\):\\s+(error|warning) (.*)$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 2,
|
|
||||||
"column": 3,
|
|
||||||
"severity": 4,
|
|
||||||
"code": 5,
|
|
||||||
"message": 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "run-debug-android",
|
"label": "run-debug-android",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
"problemMatcher": ["$msCompile"],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/src/PostIt/PostIt.Android",
|
"cwd": "${workspaceFolder}/src/PostIt/PostIt.Android",
|
||||||
"env": {
|
"env": {
|
||||||
|
|
@ -43,6 +29,7 @@
|
||||||
"label": "build",
|
"label": "build",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
|
"problemMatcher": ["$msCompile"],
|
||||||
"args": ["build", "/property:GenerateFullPaths=true"],
|
"args": ["build", "/property:GenerateFullPaths=true"],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"isBuildCommand": true,
|
"isBuildCommand": true,
|
||||||
|
|
@ -109,6 +96,7 @@
|
||||||
"isTestCommand": false,
|
"isTestCommand": false,
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
|
"problemMatcher": ["$msCompile"],
|
||||||
"args": ["build", "/property:GenerateFullPaths=true"],
|
"args": ["build", "/property:GenerateFullPaths=true"],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "src/PostIt/PostIt.Desktop"
|
"cwd": "src/PostIt/PostIt.Desktop"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using static Yavsc.Constants;
|
||||||
namespace Yavsc.Blogs.Tests;
|
namespace Yavsc.Blogs.Tests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Behavioural tests for <c>BlogAclApiController.PostCircleAuthorizationToBlogPost</c>:
|
/// Behavioral tests for <c>BlogAclApiController.PostCircleAuthorizationToBlogPost</c>:
|
||||||
/// <c>POST /api/v1/blogacl</c> with a JSON body of
|
/// <c>POST /api/v1/blogacl</c> with a JSON body of
|
||||||
/// <c>CircleAuthorizationToBlogPost</c> (CircleId + BlogPostId).
|
/// <c>CircleAuthorizationToBlogPost</c> (CircleId + BlogPostId).
|
||||||
///
|
///
|
||||||
|
|
@ -84,7 +84,7 @@ public sealed class BlogAclApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
// rather than being rewritten to ClaimTypes.NameIdentifier.
|
// rather than being rewritten to ClaimTypes.NameIdentifier.
|
||||||
// The controller, however, reads the user id via
|
// The controller, however, reads the user id via
|
||||||
// User.FindFirstValue(ClaimTypes.NameIdentifier), so we add
|
// User.FindFirstValue(ClaimTypes.NameIdentifier), so we add
|
||||||
// an explicit nameid claim to keep the legacy lookup happy.
|
// an explicit NameIdentifier claim to keep the legacy lookup happy.
|
||||||
http.DefaultRequestHeaders.Authorization =
|
http.DefaultRequestHeaders.Authorization =
|
||||||
new System.Net.Http.Headers.AuthenticationHeaderValue(
|
new System.Net.Http.Headers.AuthenticationHeaderValue(
|
||||||
"Bearer",
|
"Bearer",
|
||||||
|
|
@ -106,7 +106,7 @@ public sealed class BlogAclApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
/// when <see cref="PostAclDialogViewModel.AddAsync"/> POSTs the
|
/// when <see cref="PostAclDialogViewModel.AddAsync"/> POSTs the
|
||||||
/// shape <c>{ "circleId": <id> }</c> — the exact body the
|
/// shape <c>{ "circleId": <id> }</c> — the exact body the
|
||||||
/// PostIt client builds from <see cref="CircleAuthorization"/>
|
/// PostIt client builds from <see cref="CircleAuthorization"/>
|
||||||
/// (which only carries <c>CircleId</c>). The server deserialises
|
/// (which only carries <c>CircleId</c>). The server deserializes
|
||||||
/// it into <see cref="CircleAuthorizationToBlogPost"/>, leaves
|
/// it into <see cref="CircleAuthorizationToBlogPost"/>, leaves
|
||||||
/// <c>BlogPostId</c> at its <c>default(long) = 0</c>, attaches
|
/// <c>BlogPostId</c> at its <c>default(long) = 0</c>, attaches
|
||||||
/// no <c>Target</c> navigation, and EF Core refuses to INSERT
|
/// no <c>Target</c> navigation, and EF Core refuses to INSERT
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Yavsc.Models.Blog
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Display(Name = "Utilisateur ayant modifé le dernier")]
|
[Display(Name = "Utilisateur ayant modifié le dernier")]
|
||||||
public string? UserModified
|
public string? UserModified
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
|
|
@ -106,10 +106,10 @@ namespace Yavsc.Models.Blog
|
||||||
/// <c>[NotMapped]</c> so no migration is needed. The
|
/// <c>[NotMapped]</c> so no migration is needed. The
|
||||||
/// service hydrates it after each fetch (single bulk
|
/// service hydrates it after each fetch (single bulk
|
||||||
/// lookup, not N+1) and it surfaces through the wire
|
/// lookup, not N+1) and it surfaces through the wire
|
||||||
/// as part of the JSON-serialised <c>BlogPost</c>.
|
/// as part of the JSON-serialized <c>BlogPost</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsPublished { get; set; }
|
public bool IsPublished { get => Publication != null; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ public class BlogSpotService
|
||||||
public BlogPost Create(string userId, BlogPost post )
|
public BlogPost Create(string userId, BlogPost post )
|
||||||
{
|
{
|
||||||
// Sauvegarder le post d'abord pour obtenir son ID
|
// Sauvegarder le post d'abord pour obtenir son ID
|
||||||
// Le createur vient de l'authentification, donc on ne le prend pas du post
|
// Le créateur vient de l'authentification, donc on ne le prend pas du post
|
||||||
post.AuthorId = userId;
|
post.AuthorId = userId;
|
||||||
_context.BlogSpot.Add(post);
|
_context.BlogSpot.Add(post);
|
||||||
_context.SaveChanges(userId);
|
_context.SaveChanges(userId);
|
||||||
|
|
@ -139,15 +139,12 @@ public class BlogSpotService
|
||||||
.Include(p => p.Tags)
|
.Include(p => p.Tags)
|
||||||
.Include(p => p.Comments)
|
.Include(p => p.Comments)
|
||||||
.Include(p => p.ACL)
|
.Include(p => p.ACL)
|
||||||
|
.Include(p => p.Publication)
|
||||||
.SingleAsync(m => m.Id == blogPostId);
|
.SingleAsync(m => m.Id == blogPostId);
|
||||||
|
|
||||||
if (blog == null)
|
if (blog == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Hydrate le flag [NotMapped] depuis la table de publication.
|
|
||||||
blog.IsPublished = await _context.blogSpotPublications
|
|
||||||
.AnyAsync(pub => pub.PostId == blogPostId);
|
|
||||||
|
|
||||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new ReadPermission());
|
var auth = await _authorizationService.AuthorizeAsync(user, blog, new ReadPermission());
|
||||||
if (!auth.Succeeded)
|
if (!auth.Succeeded)
|
||||||
throw new AuthorizationFailureException(auth);
|
throw new AuthorizationFailureException(auth);
|
||||||
|
|
@ -233,6 +230,7 @@ public class BlogSpotService
|
||||||
.Include(p => p.Comments)
|
.Include(p => p.Comments)
|
||||||
.Include(p => p.Publication)
|
.Include(p => p.Publication)
|
||||||
.Where(p => p.Publication != null
|
.Where(p => p.Publication != null
|
||||||
|
|| p.AuthorId == viewerId
|
||||||
|| (userCircles != null && p.ACL.Any(a => userCircles.Contains(a.CircleId))));
|
|| (userCircles != null && p.ACL.Any(a => userCircles.Contains(a.CircleId))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -247,25 +245,12 @@ public class BlogSpotService
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var materialised = posts.ToList();
|
var materialized = posts.ToList();
|
||||||
|
|
||||||
var postIds = materialised.Select(p => p.Id).ToList();
|
foreach (var post in materialized.OfType<BlogPost>())
|
||||||
if (postIds.Count > 0)
|
|
||||||
{
|
|
||||||
var publishedIds = await _context.blogSpotPublications
|
|
||||||
.Where(pub => postIds.Contains(pub.PostId))
|
|
||||||
.Select(pub => pub.PostId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var publishedSet = publishedIds.ToHashSet();
|
|
||||||
foreach (var post in materialised.OfType<BlogPost>())
|
|
||||||
post.IsPublished = publishedSet.Contains(post.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var post in materialised.OfType<BlogPost>())
|
|
||||||
ScrubAclForViewer(post, user);
|
ScrubAclForViewer(post, user);
|
||||||
|
|
||||||
return materialised
|
return materialized
|
||||||
.OrderByDescending(p => p.DateModified)
|
.OrderByDescending(p => p.DateModified)
|
||||||
.Skip(skip)
|
.Skip(skip)
|
||||||
.Take(take);
|
.Take(take);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue