diff --git a/contrib/Makefile b/contrib/Makefile
index 7c73406b..8e0e5567 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -45,9 +45,12 @@ copy-binaries: build_publish_Org build_publish_Api build_publish_Blogs stop-serv
echo "$${project} -> $${LCAPI}" ; \
BINDIR="$(SLNDIR)/src/Yavsc.$${project}/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish" ; \
echo BINDIR: $${BINDIR} ; \
- ls $${BINDIR}/appsettings* 2>&1 ; \
- mv $${BINDIR}/appsettings-$${LCAPI}.json \
+ rm -f $${BINDIR}/appsettings-$${LCAPI}-dist.json ; \
+ mv -f $${BINDIR}/appsettings-$${LCAPI}.json \
$${BINDIR}/appsettings-$${LCAPI}-dist.json ; \
+ rm -f $${BINDIR}/appsettings-$${LCAPI}.json ; \
+ sync ; \
+ ls $${BINDIR}/appsettings* 2>&1 ; \
sudo cp -a $${BINDIR}/* $(BASEAPPDIR) ; \
done
@sudo chown -R $(USER_AND_GROUP) $(BASEAPPDIR)
@@ -56,9 +59,12 @@ copy-binaries: build_publish_Org build_publish_Api build_publish_Blogs stop-serv
sudo cp $^ $@
sudo chown root:root $@
-build_publish_%:
+build_publish_%: clean_publish_dir_%
@ASPNETCORE_ENV=$(CONFIGURATION) dotnet publish $(SLNDIR)/src/Yavsc.$*/Yavsc.$*.csproj
+clean_publish_dir_%:
+ @rm -rf $(SLNDIR)/src/Yavsc.$*/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish
+
install: build_publish copy-binaries copy-services
@sudo systemctl daemon-reload
@for project in $(APP_PROJECT_NAMES); \
diff --git a/src/Yavsc.Blogs/Program.cs b/src/Yavsc.Blogs/Program.cs
index 673fff20..ea9f044b 100644
--- a/src/Yavsc.Blogs/Program.cs
+++ b/src/Yavsc.Blogs/Program.cs
@@ -18,7 +18,6 @@ using Yavsc.Interface;
using Yavsc.Models;
using Yavsc.Services;
using Yavsc.Server.Helpers;
-using Yavsc.Extensions;
namespace Yavsc.Blogs;
internal class Program
diff --git a/src/Yavsc.Blogs/Yavsc.Blogs.csproj b/src/Yavsc.Blogs/Yavsc.Blogs.csproj
index db36859c..7961fba2 100644
--- a/src/Yavsc.Blogs/Yavsc.Blogs.csproj
+++ b/src/Yavsc.Blogs/Yavsc.Blogs.csproj
@@ -10,6 +10,5 @@
-
-
\ No newline at end of file
+
diff --git a/src/Yavsc.Org.Tests/WebServerFixture.cs b/src/Yavsc.Org.Tests/WebServerFixture.cs
index 2ced3a09..099d1e0a 100644
--- a/src/Yavsc.Org.Tests/WebServerFixture.cs
+++ b/src/Yavsc.Org.Tests/WebServerFixture.cs
@@ -121,7 +121,7 @@ namespace Yavsc.Org.Tests
{
var builder = WebApplication.CreateBuilder();
- builder.AddConfiguration("org").AddInMemoryCollection(new Dictionary
+ builder.AddConfiguration(null).AddInMemoryCollection(new Dictionary
{
[$"ConnectionStrings:{YavscConstants.YavscConnectionStringName}"] = "InMemory"
});
diff --git a/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj b/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj
index 6b532415..f2e137fe 100644
--- a/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj
+++ b/src/Yavsc.Org.Tests/Yavsc.Org.Tests.csproj
@@ -48,7 +48,4 @@
-
-
-
diff --git a/src/Yavsc.Org/Helpers/UserHelpers.cs b/src/Yavsc.Org/Helpers/UserHelpers.cs
deleted file mode 100644
index ca3d9ec3..00000000
--- a/src/Yavsc.Org/Helpers/UserHelpers.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using Yavsc.Models;
-using Yavsc.Models.Blog;
-
-namespace Yavsc.Helpers
-{
- public static class UserHelpers
- {
- public static IEnumerable UserPosts(this ApplicationDbContext dbContext, string posterId, string? readerId)
- {
- if (readerId == null)
- {
- var userPosts = dbContext.blogSpotPublications.Include(
- b => b.BlogPost
- ).Where(x => x.BlogPost.AuthorId == posterId)
- .Select(x => x.BlogPost).ToArray();
- return userPosts;
- }
- else
- {
- long[] readerCirclesMemberships =
- dbContext.Circle.Include(c => c.Members)
- .Where(c => c.Members.Any(m => m.MemberId == readerId))
- .Select(c => c.Id).ToArray();
- return dbContext.BlogSpot.Include(
- b => b.Author
- ).Include(p => p.ACL).Where(x => x.Author.Id == posterId &&
- (x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
- }
- }
- }
-}
diff --git a/src/Yavsc.Server/Helpers/ConfigHelpers.cs b/src/Yavsc.Server/Helpers/ConfigHelpers.cs
index 26c8c887..fa3fb832 100644
--- a/src/Yavsc.Server/Helpers/ConfigHelpers.cs
+++ b/src/Yavsc.Server/Helpers/ConfigHelpers.cs
@@ -6,14 +6,24 @@ namespace Yavsc.Server.Helpers;
public static class ConfigHelpers
{
- public static IConfigurationBuilder AddConfiguration(this WebApplicationBuilder builder, string appName )
+ public static IConfigurationBuilder AddConfiguration(this WebApplicationBuilder builder, string appName)
+ {
+ if (string.IsNullOrEmpty(appName))
{
var rootConfig = builder.Configuration
- .AddJsonFile($"appsettings-{appName}.json", optional: false, reloadOnChange: false);
+ .AddJsonFile($"appsettings.json", optional: false, reloadOnChange: false);
+
+ rootConfig.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false);
- rootConfig.AddJsonFile($"appsettings-{appName}.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false);
-
return rootConfig.AddEnvironmentVariables();
-
}
+
+ var specRootConfig = builder.Configuration
+ .AddJsonFile($"appsettings-{appName}.json", optional: false, reloadOnChange: false);
+
+ specRootConfig.AddJsonFile($"appsettings-{appName}.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: false);
+
+ return specRootConfig.AddEnvironmentVariables();
+
+ }
}
\ No newline at end of file
diff --git a/src/Yavsc.Server/Helpers/UserHelpers.cs b/src/Yavsc.Server/Helpers/UserHelpers.cs
index 8620ad2d..63716963 100644
--- a/src/Yavsc.Server/Helpers/UserHelpers.cs
+++ b/src/Yavsc.Server/Helpers/UserHelpers.cs
@@ -1,9 +1,35 @@
+using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
+using Yavsc.Models;
+using Yavsc.Models.Blog;
namespace Yavsc.Server.Helpers
{
public static class UserHelpers
{
+ public static IEnumerable UserPosts(this ApplicationDbContext dbContext, string posterId, string? readerId)
+ {
+ if (readerId == null)
+ {
+ var userPosts = dbContext.blogSpotPublications.Include(
+ b => b.BlogPost
+ ).Where(x => x.BlogPost.AuthorId == posterId)
+ .Select(x => x.BlogPost).ToArray();
+ return userPosts;
+ }
+ else
+ {
+ long[] readerCirclesMemberships =
+ dbContext.Circle.Include(c => c.Members)
+ .Where(c => c.Members.Any(m => m.MemberId == readerId))
+ .Select(c => c.Id).ToArray();
+ return dbContext.BlogSpot.Include(
+ b => b.Author
+ ).Include(p => p.ACL).Where(x => x.Author.Id == posterId &&
+ (x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
+ }
+ }
+
public static string GetUserId(this ClaimsPrincipal user)
{
return user.FindFirstValue("sub");
diff --git a/src/Yavsc.Server/Services/BlogSpotService.cs b/src/Yavsc.Server/Services/BlogSpotService.cs
new file mode 100644
index 00000000..8dfa9e33
--- /dev/null
+++ b/src/Yavsc.Server/Services/BlogSpotService.cs
@@ -0,0 +1,268 @@
+using System.Diagnostics;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.EntityFrameworkCore;
+using Yavsc;
+using Yavsc.Models;
+using Yavsc.Models.Blog;
+using Yavsc.Server.Exceptions;
+using Yavsc.Server.Helpers;
+using Yavsc.Services;
+using Yavsc.ViewModels.Auth;
+using Microsoft.AspNetCore.Http;
+
+public class BlogSpotService
+{
+ private readonly ApplicationDbContext _context;
+ private readonly IAuthorizationService _authorizationService;
+ private readonly IFileSystemAuthManager fileSystemAuthManager;
+
+ public BlogSpotService(ApplicationDbContext context,
+ IAuthorizationService authorizationService,
+ IFileSystemAuthManager fileSystemAuthManager)
+ {
+ _authorizationService = authorizationService;
+ _context = context;
+ this.fileSystemAuthManager = fileSystemAuthManager;
+ }
+
+ public BlogPost Create(string userId, BlogPost post, IFormFileCollection files)
+ {
+ // Sauvegarder le post d'abord pour obtenir son ID
+ _context.BlogSpot.Add(post);
+ _context.SaveChanges(userId);
+
+ // Traiter les fichiers attachés s'il y en a
+ if (files != null && files.Count > 0)
+ {
+ var user = _context.Users.FirstOrDefault(u => u.Id == userId);
+ if (user != null)
+ {
+ try
+ {
+ // Créer un répertoire pour les fichiers du blog
+ string blogFilesSubdir = $"blogs/{post.Id}";
+ string destDir = Path.Combine(
+ AbstractFileSystemHelpers.UserFilesDirName,
+ user.UserName,
+ blogFilesSubdir
+ );
+ var di = new DirectoryInfo(destDir);
+ if (!di.Exists) di.Create();
+
+ // Traiter chaque fichier
+ foreach (var formFile in files)
+ {
+ var fileInfo = user.ReceiveUserFile(destDir, formFile);
+ if (fileInfo != null && !fileInfo.QuotaOffense)
+ {
+ // Créer une entrée UploadedFile si nécessaire
+ var uploadedFile = new UploadedFile
+ {
+ Path = fileInfo.FileName,
+ ContentType = formFile.ContentType,
+ Length = formFile.Length
+ };
+ _context.UploadedFiles.Add(uploadedFile);
+ _context.SaveChanges(userId);
+
+ // Lier le fichier au post
+ var attachment = new BlogAttachedFile
+ {
+ PostId = post.Id,
+ FileId = uploadedFile.Id
+ };
+ _context.BlogAttachedFiles.Add(attachment);
+ }
+ }
+ _context.SaveChanges(userId);
+ }
+ catch (Exception ex)
+ {
+ // Logger l'erreur mais ne pas échouer la création du post
+ System.Diagnostics.Debug.WriteLine($"Erreur lors du traitement des fichiers : {ex.Message}");
+ }
+ }
+ }
+
+ return post;
+ }
+ public async Task GetPostForEdition(ClaimsPrincipal user, long blogPostId)
+ {
+ var blog = await _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).SingleAsync(m => m.Id == blogPostId);
+ var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
+ if (!auth.Succeeded)
+ {
+ throw new AuthorizationFailureException(auth);
+ }
+ var pub = await _context.blogSpotPublications.AnyAsync(x => x.BlogpostId == blog.Id);
+
+ return new BlogPostEditViewModel(blog, pub);
+ }
+
+ public async Task Details(ClaimsPrincipal user, long blogPostId)
+ {
+ BlogPost blog = await _context.BlogSpot
+ .Include(p => p.Author)
+ .Include(p => p.Tags)
+ .Include(p => p.Comments)
+ .Include(p => p.ACL)
+ .SingleAsync(m => m.Id == blogPostId);
+ if (blog == null)
+ {
+ return null;
+ }
+ var auth = await _authorizationService.AuthorizeAsync(user, blog, new ReadPermission());
+ if (!auth.Succeeded)
+ {
+ throw new AuthorizationFailureException(auth);
+ }
+ foreach (var c in blog.Comments)
+ {
+ c.Author = _context.Users.First(u => u.Id == c.AuthorId);
+ }
+ return blog;
+ }
+
+ public async Task Modify(ClaimsPrincipal user, BlogPostEditViewModel blogEdit)
+ {
+ var blog = _context.BlogSpot.SingleOrDefault(b => b.Id == blogEdit.Id);
+ Debug.Assert(blog != null);
+ var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
+ if (!auth.Succeeded)
+ {
+ throw new AuthorizationFailureException(auth);
+ }
+ blog.Article = blogEdit.Article;
+ blog.Title = blogEdit.Title;
+ blog.Photo = blogEdit.Photo;
+ blog.ACL = blogEdit.ACL;
+ // saves the change
+ _context.Update(blog);
+ var publication = await _context.blogSpotPublications.SingleOrDefaultAsync
+ (p => p.BlogpostId == blogEdit.Id);
+ if (publication != null)
+ {
+ if (!blogEdit.Publish)
+ {
+ _context.blogSpotPublications.Remove(publication);
+ }
+ }
+ else
+ {
+ if (blogEdit.Publish)
+ {
+ _context.blogSpotPublications.Add(
+ new BlogSpotPublication
+ {
+ BlogpostId = blogEdit.Id
+ }
+ );
+ }
+ }
+ _context.SaveChanges(user.GetUserId());
+ }
+
+ public async Task Modify(ClaimsPrincipal user, BlogPost blog)
+ {
+ var existing = await _context.BlogSpot.Include(b => b.ACL).SingleOrDefaultAsync(b => b.Id == blog.Id);
+ if (existing == null)
+ {
+ throw new InvalidOperationException($"Blog post {blog.Id} not found.");
+ }
+
+ var auth = await _authorizationService.AuthorizeAsync(user, existing, new EditPermission());
+ if (!auth.Succeeded)
+ {
+ throw new AuthorizationFailureException(auth);
+ }
+
+ existing.Title = blog.Title;
+ existing.Article = blog.Article;
+ existing.Photo = blog.Photo;
+ existing.ACL = blog.ACL;
+
+ _context.Update(existing);
+ _context.SaveChanges(user.GetUserId());
+ }
+
+ public async Task> Index(ClaimsPrincipal user, string id, int skip = 0, int take = 25)
+ {
+ IEnumerable posts;
+
+ if (user.Identity.IsAuthenticated)
+ {
+ string viewerId = user.GetUserId();
+ long[] userCircles = await _context.Circle.Include(c => c.Members).
+ Where(c => c.Members.Any(m => m.MemberId == viewerId))
+ .Select(c => c.Id).ToArrayAsync();
+
+ posts = _context.BlogSpot
+ .Include(b => b.Author)
+ .Include(p => p.ACL)
+ .Include(p => p.Tags)
+ .Include(p => p.Comments)
+ .Where(p => p.ACL == null
+ || p.ACL.Count == 0
+ || (p.AuthorId == viewerId)
+ || (userCircles != null &&
+ p.ACL.Any(a => userCircles.Contains(a.CircleId)))
+ );
+ }
+ else
+ {
+ 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.ACL == null
+ || p.BlogPost.ACL.Count == 0)
+ .Select(p => p.BlogPost).ToArray();
+ }
+
+ var data = posts.OrderByDescending(p => p.DateModified)
+ .Skip(skip)
+ .Take(take);
+ return data;
+ }
+
+ public async Task Delete(ClaimsPrincipal user, long id)
+ {
+ var uid = user.GetUserId();
+ BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
+
+ _context.BlogSpot.Remove(blog);
+ _context.SaveChanges(user.GetUserId());
+ }
+
+ public async Task> UserPosts(
+ string posterName,
+ string? readerId,
+ int pageLen = 10,
+ int pageNum = 0)
+ {
+ string? posterId = (await _context.Users.SingleOrDefaultAsync(u => u.UserName == posterName))?.Id ?? null;
+ if (posterId == null) return Array.Empty();
+ return _context.UserPosts(posterId, readerId);
+ }
+
+ public object? GetTitle(string title)
+ {
+ return _context.BlogSpot.Include(
+ b => b.Author
+ ).Where(x => x.Title == title).OrderByDescending(
+ x => x.DateCreated
+ ).ToList();
+ }
+
+ public async Task GetBlogPostAsync(long value)
+ {
+ return await _context.BlogSpot
+ .Include(b => b.Author)
+ .Include(b => b.ACL)
+ .SingleOrDefaultAsync(x => x.Id == value);
+ }
+
+}
diff --git a/src/Yavsc.Org/Extensions/PermissionHandler.cs b/src/Yavsc.Server/Services/PermissionHandler.cs
similarity index 96%
rename from src/Yavsc.Org/Extensions/PermissionHandler.cs
rename to src/Yavsc.Server/Services/PermissionHandler.cs
index 15f168ec..6848070a 100644
--- a/src/Yavsc.Org/Extensions/PermissionHandler.cs
+++ b/src/Yavsc.Server/Services/PermissionHandler.cs
@@ -1,12 +1,14 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Blog;
using Yavsc.Server.Helpers;
using Yavsc.ViewModels.Auth;
-namespace Yavsc.Extensions;
+namespace Yavsc.Services;
public class PermissionHandler : IAuthorizationHandler
{