From 3bc4142383ab9e4db3b702a34c7876ed9e70a203 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 17 Sep 2026 22:22:18 +0100 Subject: [PATCH] refacto site settings --- .../FileSystem/AbstractFileSystemHelpers.cs | 13 -- .../Controllers/Business/BillingController.cs | 20 ++- .../accounting/AccountController.cs | 9 +- src/Yavsc.Api/Program.cs | 1 - src/Yavsc.Api/appsettings-api.json | 4 +- src/Yavsc.Blogs.Tests/BlogApiTests.cs | 37 ++-- .../Fixtures/BlogsWebServerFixture.cs | 22 +++ .../Controllers/BlogApiController.cs | 85 +++++++--- .../Controllers/FileSystemApiController.cs | 18 +- .../Controllers/FileSystemStreamController.cs | 14 +- src/Yavsc.Blogs/appsettings-blogs.json | 3 +- .../EstimateSignatureFileHelperTests.cs | 14 +- src/Yavsc.Org.Tests/appsettings.json | 4 + .../Accounting/AccountController.cs | 20 ++- .../Communicating/BlogspotController.cs | 5 +- .../Contracting/FrontOfficeController.cs | 10 +- .../Controllers/FileSystemController.cs | 13 +- src/Yavsc.Org/Extensions/HostingExtensions.cs | 32 +++- src/Yavsc.Org/Helpers/TeXHelpers.cs | 8 +- src/Yavsc.Org/Services/BlogSpotService.cs | 9 +- src/Yavsc.Org/Startup.cs | 21 +-- .../ViewComponents/BillViewComponent.cs | 48 +++--- .../ViewComponents/DirectoryViewComponent.cs | 19 ++- .../Shared/Components/Bill/Bill_pdf.cshtml | 4 +- .../Components/Estimate/Estimate_pdf.cshtml | 2 +- src/Yavsc.Org/Views/Shared/_Nav.cshtml | 8 +- src/Yavsc.Org/appsettings-org.json | 3 +- src/Yavsc.Server/Config.cs | 3 +- src/Yavsc.Server/Helpers/BillingHelpers.cs | 5 +- .../Helpers/EstimateSignatureFileHelper.cs | 3 +- src/Yavsc.Server/Helpers/FileSystemHelpers.cs | 57 ++++--- src/Yavsc.Server/Services/BlogSpotService.cs | 159 +++++++----------- src/Yavsc.Server/Settings/SiteSettings.cs | 57 +++---- 33 files changed, 407 insertions(+), 323 deletions(-) diff --git a/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs b/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs index 14bc86435..7665df8ab 100644 --- a/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs +++ b/src/Yavsc.Abstract/FileSystem/AbstractFileSystemHelpers.cs @@ -7,8 +7,6 @@ namespace Yavsc.Server.Helpers { public static class AbstractFileSystemHelpers { - public static string UserBillsDirName { set; get; } - public static string UserFilesDirName { set; get; } /// /// Is Valid this Path? @@ -64,17 +62,6 @@ namespace Yavsc.Server.Helpers return sb.ToString(); } - public static UserDirectoryInfo GetUserFiles(string userId, string subdir) - { - UserDirectoryInfo di = new UserDirectoryInfo(UserFilesDirName, userId, subdir); - return di; - } - public static bool IsRegularFile(string userName, string subdir) - { - FileInfo fi = new FileInfo( Path.Combine(Path.Combine(UserFilesDirName, userName), subdir)); - return fi.Exists; - } - // Server side only supports POSIX file systems public const char RemoteDirectorySeparator = '/'; diff --git a/src/Yavsc.Api/Controllers/Business/BillingController.cs b/src/Yavsc.Api/Controllers/Business/BillingController.cs index d10e166e3..ba099e7c7 100644 --- a/src/Yavsc.Api/Controllers/Business/BillingController.cs +++ b/src/Yavsc.Api/Controllers/Business/BillingController.cs @@ -35,6 +35,7 @@ namespace Yavsc.ApiControllers private readonly ILogger logger; private readonly IBillingService billingService; + private readonly SiteSettings siteSettings; public BillingController( IAuthorizationService authorizationService, @@ -43,7 +44,8 @@ namespace Yavsc.ApiControllers ApplicationDbContext context, IOptions googleSettings, IYavscMessageSender GCMSender, - IBillingService billingService + IBillingService billingService, + IOptions siteSettings ) { _googleSettings=googleSettings.Value; @@ -53,6 +55,7 @@ namespace Yavsc.ApiControllers this._localizer = SR; _GCMSender=GCMSender; this.billingService=billingService; + this.siteSettings = siteSettings.Value; } [HttpGet("facture-{billingCode}-{id}.pdf"), Authorize] @@ -65,7 +68,7 @@ namespace Yavsc.ApiControllers return new ChallengeResult(); } - var fi = bill.GetBillInfo(billingService); + var fi = bill.GetBillInfo(billingService, siteSettings); if (!fi.Exists) return Ok(new { Error = "Not generated" }); return File(fi.OpenRead(), "application/x-pdf", fi.Name); @@ -229,7 +232,7 @@ namespace Yavsc.ApiControllers } if (Request.Form.Files.Count!=1) return new BadRequestResult(); - await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"pro"); + await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"pro", siteSettings); estimate.ProviderValidationDate = DateTime.UtcNow; dbContext.SaveChanges(User.GetUserId()); // Notify the client @@ -273,7 +276,7 @@ namespace Yavsc.ApiControllers } var filename = AbstractFileSystemHelpers.SignFileNameFormat("pro", billingCode, id); - FileInfo fi = new FileInfo(Path.Combine(AbstractFileSystemHelpers.UserBillsDirName, filename)); + FileInfo fi = new FileInfo(Path.Combine(siteSettings.Bills, filename)); if (!fi.Exists) return NotFound(new { Error = "Professional signature not found" }); return File(fi.OpenRead(), "application/x-pdf", filename); ; } @@ -310,7 +313,7 @@ namespace Yavsc.ApiControllers } if (Request.Form.Files.Count!=1) return new BadRequestResult(); - await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"cli"); + await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"cli", siteSettings); estimate.ClientValidationDate = DateTime.UtcNow; dbContext.SaveChanges(User.GetUserId()); return Ok (new { ClientValidationDate = estimate.ClientValidationDate }); @@ -327,9 +330,9 @@ namespace Yavsc.ApiControllers } var filename = AbstractFileSystemHelpers.SignFileNameFormat("pro", billingCode, id); - FileInfo fi = new FileInfo(Path.Combine(AbstractFileSystemHelpers.UserBillsDirName, filename)); + FileInfo fi = new FileInfo(Path.Combine(siteSettings.Bills, filename)); if (!fi.Exists) return NotFound(new { Error = "Professional signature not found" }); - return File(fi.OpenRead(), "application/x-pdf", filename); ; + return File(fi.OpenRead(), "application/x-pdf", filename); } /// @@ -405,7 +408,8 @@ namespace Yavsc.ApiControllers FileReceivedInfo fi; try { - fi = await User.ReceiveEstimateSignatureAsync(id, type, payload, token); + fi = await User.ReceiveEstimateSignatureAsync(id, type, payload, + siteSettings, token); } catch (Exception ex) { diff --git a/src/Yavsc.Api/Controllers/accounting/AccountController.cs b/src/Yavsc.Api/Controllers/accounting/AccountController.cs index 155274cdf..f0986e98f 100644 --- a/src/Yavsc.Api/Controllers/accounting/AccountController.cs +++ b/src/Yavsc.Api/Controllers/accounting/AccountController.cs @@ -2,13 +2,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Http; using ImageMagick; using Yavsc.Models; using Yavsc.Api.Helpers; using Yavsc.Server.Helpers; using System.Diagnostics; +using Microsoft.Extensions.Options; namespace Yavsc.WebApi.Controllers { @@ -28,13 +28,16 @@ namespace Yavsc.WebApi.Controllers ]; readonly ApplicationDbContext _dbContext; + private readonly SiteSettings siteSettings; private readonly ILogger _logger; public ApiAccountController( - ILoggerFactory loggerFactory, ApplicationDbContext dbContext) + ILoggerFactory loggerFactory, ApplicationDbContext dbContext, + IOptions siteSettings) { _logger = loggerFactory.CreateLogger(nameof(ApiAccountController)); _dbContext = dbContext; + this.siteSettings = siteSettings.Value; } [HttpGet("me")] @@ -146,7 +149,7 @@ namespace Yavsc.WebApi.Controllers try { - var info = user.ReceiveAvatar(avatarFile); + var info = user.ReceiveAvatar(avatarFile, siteSettings); await _dbContext.SaveChangesAsync(); return Ok(new { diff --git a/src/Yavsc.Api/Program.cs b/src/Yavsc.Api/Program.cs index 5f7ef25c0..be4ae6579 100644 --- a/src/Yavsc.Api/Program.cs +++ b/src/Yavsc.Api/Program.cs @@ -21,7 +21,6 @@ internal class Program var builder = WebApplication.CreateBuilder(args); builder.AddConfiguration("api"); - Config.SiteSetup = builder.Configuration.GetSection("Site").Get() ?? new SiteSettings(); var services = builder.Services; diff --git a/src/Yavsc.Api/appsettings-api.json b/src/Yavsc.Api/appsettings-api.json index 1bde1d39f..b16e7b8b4 100644 --- a/src/Yavsc.Api/appsettings-api.json +++ b/src/Yavsc.Api/appsettings-api.json @@ -5,7 +5,9 @@ "CorsAllowedOrigins": [ "https://yavsc.pschneider.fr", "https://blogs.pschneider.fr" - ] + ], + "Bills": "bills", + "TempDir": "temp" }, "Logging": { "LogLevel": { diff --git a/src/Yavsc.Blogs.Tests/BlogApiTests.cs b/src/Yavsc.Blogs.Tests/BlogApiTests.cs index c57c31c3f..b2989ef50 100644 --- a/src/Yavsc.Blogs.Tests/BlogApiTests.cs +++ b/src/Yavsc.Blogs.Tests/BlogApiTests.cs @@ -11,6 +11,7 @@ using Yavsc.Server.Helpers; using Yavsc.Tests.Shared; using Yavsc.Blogs.Tests.Fixtures; using BlogPostDto = Yavsc.Blogspot.BlogPostDto; +using NuGet.Protocol; namespace Yavsc.Blogs.Tests; @@ -338,10 +339,9 @@ public sealed class BlogApiTests : IClassFixture ResetAndSeedDefaultUser(); using var http = NewClient(subject: "tester"); - var previousRoot = AbstractFileSystemHelpers.UserFilesDirName; - var tempRoot = Path.Combine(Path.GetTempPath(), "yavsc-blogs-tests-files-" + Guid.NewGuid().ToString("N")); - Directory.CreateDirectory(tempRoot); - AbstractFileSystemHelpers.UserFilesDirName = tempRoot; + // AttachFiles writes under the fixture-configured + // SiteSettings.Blog (BlogFilesRoot), not a local temp dir. + var filesRoot = _fixture.BlogFilesRoot; try { @@ -374,8 +374,10 @@ public sealed class BlogApiTests : IClassFixture DateModified = DateTime.UtcNow }; - var form = new MultipartFormDataContent(); - form.Add(new StringContent(JsonSerializer.Serialize(update)), "blog"); + var form = new MultipartFormDataContent + { + { new StringContent(JsonSerializer.Serialize(update)), "blog" } + }; var fileBytes = System.Text.Encoding.UTF8.GetBytes("payload test"); var fileContent = new ByteArrayContent(fileBytes); @@ -405,8 +407,9 @@ public sealed class BlogApiTests : IClassFixture } finally { - AbstractFileSystemHelpers.UserFilesDirName = previousRoot; - try { Directory.Delete(tempRoot, recursive: true); } catch { } + // BlogFilesRoot is the fixture-shared temp root (one per + // test run); leave it in place for the other multipart + // tests. The OS reclaims it. } } @@ -480,10 +483,9 @@ public sealed class BlogApiTests : IClassFixture ResetAndSeedDefaultUser(); using var http = NewClient(subject: "tester"); - var previousRoot = AbstractFileSystemHelpers.UserFilesDirName; - var tempRoot = Path.Combine(Path.GetTempPath(), "yavsc-blogs-tests-files-" + Guid.NewGuid().ToString("N")); - Directory.CreateDirectory(tempRoot); - AbstractFileSystemHelpers.UserFilesDirName = tempRoot; + // AttachFiles writes under the fixture-configured + // SiteSettings.Blog (BlogFilesRoot), not a local temp dir. + var filesRoot = _fixture.BlogFilesRoot; try { @@ -569,17 +571,18 @@ public sealed class BlogApiTests : IClassFixture // markdown link points: // {UserFilesDirName}/{user}/blogs/{postId}/{fileName}. var expectedFile = Path.Combine( - tempRoot, "tester", "blogs", created.Id.ToString(), "note.txt"); - var written = Directory.Exists(tempRoot) - ? string.Join(", ", Directory.EnumerateFiles(tempRoot, "*", SearchOption.AllDirectories)) + filesRoot, "tester", "blogs", created.Id.ToString(), "note.txt"); + var written = Directory.Exists(filesRoot) + ? string.Join(", ", Directory.EnumerateFiles(filesRoot, "*", SearchOption.AllDirectories)) : ""; Assert.True(File.Exists(expectedFile), $"Expected uploaded file at {expectedFile}. Actually written: {written}"); } finally { - AbstractFileSystemHelpers.UserFilesDirName = previousRoot; - try { Directory.Delete(tempRoot, recursive: true); } catch { } + // BlogFilesRoot is the fixture-shared temp root (one per + // test run); leave it in place for the other multipart + // tests. The OS reclaims it. } } diff --git a/src/Yavsc.Blogs.Tests/Fixtures/BlogsWebServerFixture.cs b/src/Yavsc.Blogs.Tests/Fixtures/BlogsWebServerFixture.cs index e0606f5d7..f464a1caa 100644 --- a/src/Yavsc.Blogs.Tests/Fixtures/BlogsWebServerFixture.cs +++ b/src/Yavsc.Blogs.Tests/Fixtures/BlogsWebServerFixture.cs @@ -63,6 +63,16 @@ public sealed class BlogsWebServerFixture : WebHostFixture public long PostId { get; private set; } public string DefaultUserLogin { get => "alice"; } + /// Root directory under which + /// BlogSpotService.AttachFiles writes uploaded files + /// during tests (the configured SiteSettings.Blog). + /// Attachments land at + /// {BlogFilesRoot}/{userName}/blogs/{postId}/{fileName}. + /// A fresh per-run temp directory, so tests can assert on the + /// physical file without touching the developer's real + /// user-files tree. + public string BlogFilesRoot { get; private set; } = string.Empty; + // A single SqliteConnection held open at the static level, // mirroring how Yavsc.Org.Tests.WebServerFixture hoists its // shared configuration into static slots. Closing the @@ -112,6 +122,18 @@ public sealed class BlogsWebServerFixture : WebHostFixture builder.Services.AddSingleton( new NoopFileSystemAuthManager()); + // BlogSpotService.AttachFiles writes uploaded files under + // siteSettings.Blog. Without a configured SiteSettings the + // IOptions value has Blog == null and + // Path.Combine(null, …) throws inside AttachFiles' catch-all, + // silently persisting no attachment. Point Blog at a + // per-run temp directory so the multipart tests can assert + // on real files. + builder.Services.Configure(s => + { + s.Blog = BlogFilesRoot; + }); + // Real BlogSpotService — same instance the production host // builds (ApplicationDbContext, IAuthorizationService, // IFileSystemAuthManager). With PermissionHandler registered diff --git a/src/Yavsc.Blogs/Controllers/BlogApiController.cs b/src/Yavsc.Blogs/Controllers/BlogApiController.cs index 97c070a3c..7aaf221e4 100644 --- a/src/Yavsc.Blogs/Controllers/BlogApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogApiController.cs @@ -57,12 +57,31 @@ namespace Yavsc.Blogs.Controllers [HttpPut("{id}")] public async Task PutBlog(long id) { - var blog = await ReadPutBlogRequestAsync(); + var blog = await ReadBlogRequestAsync(); if (blog is null) { return BadRequest(ModelState); } + // Without [FromBody], the data-annotations attributes + // ([Required] on Title, etc.) are no longer evaluated by + // the model binder — the body is read manually. Run + // validation explicitly so an empty Title still yields + // 400 (and not a 500 from the DB NOT NULL constraint). + var validationContext = new System.ComponentModel.DataAnnotations.ValidationContext(blog); + var validationResults = new List(); + if (!System.ComponentModel.DataAnnotations.Validator.TryValidateObject( + blog, validationContext, validationResults, validateAllProperties: true)) + { + foreach (var result in validationResults) + { + ModelState.AddModelError( + result.MemberNames.FirstOrDefault() ?? string.Empty, + result.ErrorMessage ?? "Invalid value."); + } + return BadRequest(ModelState); + } + // These properties are server-managed or optional graph members and // should not block JSON payloads coming from API clients. ModelState.Remove(nameof(Models.Blog.BlogPost.Author)); @@ -93,7 +112,8 @@ namespace Yavsc.Blogs.Controllers try { - await blogSpotService.Modify(User, blog, files); + await blogSpotService.Modify(User, blog); + blogSpotService.AttachFiles(files, User.GetUserId(), id); } catch (AuthorizationFailureException) { @@ -105,8 +125,14 @@ namespace Yavsc.Blogs.Controllers // POST: api/v1/blogspot [HttpPost] - public IActionResult PostBlog([FromBody] Models.Blog.BlogPost blog) + public async Task PostBlog() { + var blog = await ReadBlogRequestAsync(); + if (blog is null) + { + return BadRequest(ModelState); + } + // These properties are server-managed or optional graph members and // should not block JSON payloads coming from API clients. ModelState.Remove(nameof(Models.Blog.BlogPost.Author)); @@ -115,35 +141,46 @@ namespace Yavsc.Blogs.Controllers ModelState.Remove(nameof(Models.Blog.BlogPost.UserCreated)); ModelState.Remove(nameof(Models.Blog.BlogPost.UserModified)); + // Without [FromBody], the data-annotations attributes + // ([Required] on Title, etc.) are no longer evaluated by + // the model binder — the body is read manually. Run + // validation explicitly so an empty Title still yields + // 400 (and not a 500 from the DB NOT NULL constraint). + var validationContext = new System.ComponentModel.DataAnnotations.ValidationContext(blog); + var validationResults = new List(); + if (!System.ComponentModel.DataAnnotations.Validator.TryValidateObject( + blog, validationContext, validationResults, validateAllProperties: true)) + { + foreach (var result in validationResults) + { + ModelState.AddModelError( + result.MemberNames.FirstOrDefault() ?? string.Empty, + result.ErrorMessage ?? "Invalid value."); + } + return BadRequest(ModelState); + } + if (!ModelState.IsValid) { return BadRequest(ModelState); } - // The BlogSpotService.Create() signature requires an - // IFormFileCollection for file uploads. Reading - // Request.Form.Files when the request is a plain JSON - // body (e.g. from PostIt) throws - // "This request does not have a Content-Type header. - // Forms are available from requests with bodies like - // POSTs and a form Content-Type of either - // application/x-www-form-urlencoded or - // multipart/form-data." - // // Two valid use cases for this endpoint: // 1. JSON body only (no files) — PostIt path. // 2. multipart/form-data with a 'blog' field + 0..N - // files — future browser / server-rendered path. + // files — PostIt "create with attachments" path. // // Branch on HasFormContentType: pass the form files when - // present, pass an empty collection otherwise. The - // FileSystem branch in BlogSpotService.Create then - // short-circuits to "no files to handle". + // present, pass an empty collection otherwise. Reading + // Request.Form.Files on a plain JSON request throws + // "This request does not have a Content-Type header…", + // and AttachFiles short-circuits on an empty collection. var files = Request.HasFormContentType ? Request.Form.Files : (IFormFileCollection)new FormFileCollection(); var uid = User.GetUserId(); - var post = blogSpotService.Create(uid, blog, files); + var post = blogSpotService.Create(uid, blog); + blogSpotService.AttachFiles(files, uid, post.Id); return CreatedAtRoute("GetBlog", new { id = post.Id }, post.GetPayload()); } @@ -210,7 +247,17 @@ namespace Yavsc.Blogs.Controllers base.Dispose(disposing); } - private async Task ReadPutBlogRequestAsync() + /// + /// Read a from either a + /// JSON body or a multipart/form-data request carrying the + /// payload in a blog form field. Shared by + /// and : both + /// accept the two shapes so PostIt can attach files on + /// create as well as on update. Returns null (with + /// the reason recorded in ModelState) when the + /// multipart form has no usable blog field. + /// + private async Task ReadBlogRequestAsync() { if (!Request.HasFormContentType) { diff --git a/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs b/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs index 5e8345034..b714af4e0 100644 --- a/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs +++ b/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs @@ -12,6 +12,7 @@ namespace Yavsc.Blogs.Controllers using Yavsc.Server.Helpers; using Yavsc.Abstract.Helpers; using Yavsc.Server.Models.FileSystem; + using Microsoft.Extensions.Options; [Authorize,Route(APIPrefix + "/fs")] public partial class FileSystemApiController : Controller @@ -19,15 +20,18 @@ namespace Yavsc.Blogs.Controllers readonly ApplicationDbContext dbContext; private readonly IAuthorizationService AuthorizationService; private readonly ILogger _logger; + private readonly SiteSettings siteSettings; public FileSystemApiController(ApplicationDbContext context, IAuthorizationService authorizationService, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + IOptions siteSettings) { AuthorizationService = authorizationService; dbContext = context; _logger = loggerFactory.CreateLogger(); + this.siteSettings = siteSettings.Value; } [HttpGet()] @@ -41,7 +45,7 @@ namespace Yavsc.Blogs.Controllers { if (!ModelState.IsValid) return new BadRequestObjectResult(ModelState); // _logger.LogInformation($"listing files from {User.Identity.Name}{subdir}"); - var files = AbstractFileSystemHelpers.GetUserFiles(User.GetUserId(), subdir); + var files = FileSystemHelpers.GetUserFiles(siteSettings, User.GetUserId(), subdir); return Ok(files); } @@ -53,7 +57,7 @@ namespace Yavsc.Blogs.Controllers List received = new List(); InvalidPathException pathex = null; try { - destDir = User.EnsureDestinationDirectory(subdir); + destDir = User.EnsureDestinationDirectory(subdir, siteSettings); } catch (InvalidPathException ex) { pathex = ex; } @@ -108,7 +112,7 @@ namespace Yavsc.Blogs.Controllers var user = dbContext.Users.Single( u => u.Id == uid ); - var info = user.MoveUserFileToDir(query.Id, query.To); + var info = user.MoveUserFileToDir(query.Id, query.To, siteSettings); if (!info.Done) return new BadRequestObjectResult(info); return Ok(new { moved = query.Id }); } @@ -131,11 +135,11 @@ namespace Yavsc.Blogs.Controllers try { if (Config.UserFilesOptions.FileProvider.GetFileInfo(Path.Combine(user.UserName, query.Id)).Exists) { - var result = user.MoveUserFile(query.Id, query.To); + var result = user.MoveUserFile(query.Id, query.To, siteSettings); if (!result.Done) return new BadRequestObjectResult(result); } else { - var result = user.MoveUserDir(query.Id, query.To); + var result = user.MoveUserDir(query.Id, query.To, siteSettings); if (!result.Done) return new BadRequestObjectResult(result); } } @@ -161,7 +165,7 @@ namespace Yavsc.Blogs.Controllers ); try { - var result = user.DeleteUserDirOrFile(id); + var result = user.DeleteUserDirOrFile(id, siteSettings); if (!result.Done) return new BadRequestObjectResult(result); } diff --git a/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs b/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs index bc6485dd4..1de56b310 100644 --- a/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs +++ b/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.SignalR; using Yavsc.Server.Helpers; using static Yavsc.Constants; using Yavsc.Server.Hubs; +using Microsoft.Extensions.Options; namespace Yavsc.Blogs.Controllers { @@ -21,13 +22,20 @@ namespace Yavsc.Blogs.Controllers private readonly IHubContext hubContext; readonly ApplicationDbContext dbContext; - public FileSystemStreamController(ApplicationDbContext context, ILiveProcessor liveProcessor, ILoggerFactory loggerFactory, - IHubContext hubContext) + private readonly SiteSettings siteSettings; + + public FileSystemStreamController( + ApplicationDbContext context, + ILiveProcessor liveProcessor, + ILoggerFactory loggerFactory, + IHubContext hubContext, + IOptions siteSettings) { this.dbContext = context; this.logger = loggerFactory.CreateLogger(); this.liveProcessor = liveProcessor; this.hubContext = hubContext; + this.siteSettings = siteSettings.Value; } [Authorize, Route("put/{filename}")] @@ -55,7 +63,7 @@ namespace Yavsc.Blogs.Controllers ); - string destDir = HttpContext.User.EnsureDestinationDirectory(filePath); + string destDir = HttpContext.User.EnsureDestinationDirectory(filePath, siteSettings); logger.LogInformation($"Saving flow to {destDir}"); var userId = User.GetUserId(); var user = await dbContext.Users.FirstAsync(u => u.Id == userId); diff --git a/src/Yavsc.Blogs/appsettings-blogs.json b/src/Yavsc.Blogs/appsettings-blogs.json index 3888af71f..34134c937 100644 --- a/src/Yavsc.Blogs/appsettings-blogs.json +++ b/src/Yavsc.Blogs/appsettings-blogs.json @@ -8,7 +8,8 @@ "CorsAllowedOrigins": [ "https://localhost:5005", "https://api.pschneider.fr" - ] + ], + "Blog": "blog" }, "ConnectionStrings": { "YavscConnection": "Server=localhost;Port=5432;Database=lame-db-name;Username=lame-user-name;Password=lame-password;" diff --git a/src/Yavsc.Org.Tests/EstimateSignatureFileHelperTests.cs b/src/Yavsc.Org.Tests/EstimateSignatureFileHelperTests.cs index 91a4e1532..b7b4d3591 100644 --- a/src/Yavsc.Org.Tests/EstimateSignatureFileHelperTests.cs +++ b/src/Yavsc.Org.Tests/EstimateSignatureFileHelperTests.cs @@ -18,6 +18,7 @@ namespace Yavsc.Org.Tests; public class EstimateSignatureFileHelperTests : IDisposable { private readonly string _tempRoot; + private SiteSettings siteSettings; public EstimateSignatureFileHelperTests() { @@ -28,7 +29,7 @@ public class EstimateSignatureFileHelperTests : IDisposable Path.GetTempPath(), "yavsc-sig-tests-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_tempRoot); - AbstractFileSystemHelpers.UserFilesDirName = _tempRoot; + this.siteSettings = new SiteSettings { Blog = _tempRoot }; } public void Dispose() @@ -71,7 +72,7 @@ public class EstimateSignatureFileHelperTests : IDisposable }; // Act - var fi = Run(user, 123L, SignatureType.Pro, payload); + var fi = Run(user, 123L, SignatureType.Pro, payload, this.siteSettings); // Assert: file exists, sits under the user's root, and // parses as a yavsc.signature/v1 envelope. @@ -98,7 +99,8 @@ public class EstimateSignatureFileHelperTests : IDisposable var ct = TestContext.Current.CancellationToken; await Assert.ThrowsAsync(() => EstimateSignatureFileHelper.ReceiveEstimateSignatureAsync( - user, 1L, SignatureType.Pro, payload: null!, token: ct)); + user, 1L, SignatureType.Pro, payload: null!, + siteSettings, token: ct)); } [Fact] @@ -109,19 +111,19 @@ public class EstimateSignatureFileHelperTests : IDisposable var ct = TestContext.Current.CancellationToken; await Assert.ThrowsAsync(() => EstimateSignatureFileHelper.ReceiveEstimateSignatureAsync( - user, 0L, SignatureType.Pro, payload, token: ct)); + user, 0L, SignatureType.Pro, payload, this.siteSettings, token: ct)); } // --- helpers ---------------------------------------------------- private static FileReceivedInfo Run( - ClaimsPrincipal user, long estimateId, SignatureType type, SignaturePadPayload payload) + ClaimsPrincipal user, long estimateId, SignatureType type, SignaturePadPayload payload, SiteSettings siteSettings) { // The helper is async; tests that don't care about the // result can call it sync via .GetAwaiter().GetResult() // because we know it never throws in the happy path. return EstimateSignatureFileHelper - .ReceiveEstimateSignatureAsync(user, estimateId, type, payload, CancellationToken.None) + .ReceiveEstimateSignatureAsync(user, estimateId, type, payload, siteSettings, CancellationToken.None) .GetAwaiter().GetResult(); } diff --git a/src/Yavsc.Org.Tests/appsettings.json b/src/Yavsc.Org.Tests/appsettings.json index ef95fef61..f21f348ae 100644 --- a/src/Yavsc.Org.Tests/appsettings.json +++ b/src/Yavsc.Org.Tests/appsettings.json @@ -9,6 +9,10 @@ "FavIcon": "/favicon.ico", "Icon": "/images/yavsc.png", "GitRepository": "testingrepo", + "Blog": "blog", + "Bills": "bills", + "TempDir": "temp", + "Avatars": "avatars", "Owner": { "Name": "Site Owner Name", "EMail": "your@email", diff --git a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs index 3fd8a0159..04f60aa1d 100644 --- a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs +++ b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs @@ -490,14 +490,17 @@ IHtmlLocalizerFactory htmlLocalizerFactory, if (result.Succeeded) { _logger.LogInformation(3, "User created a new account with password."); - await _emailSender.SendEmailAsync(Config.SiteSetup.Owner.Name, Config.SiteSetup.Owner.EMail, - $"[{_siteSettings.Title}] Inscription avec mot de passe: {user.UserName} ", $"{user.Id}/{user.UserName}/{user.Email}"); + await _emailSender.SendEmailAsync( + _siteSettings.Owner.Name, + _siteSettings.Owner.EMail, + $"[{_siteSettings.Title}] Inscription avec mot de passe: {user.UserName} ", + $"{user.Id}/{user.UserName}/{user.Email}"); // TODO user.DiskQuota = Startup.SiteSetup.UserFiles.Quota; // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713 // Send an email with this link - Uri authority = new Uri(Config.Authority); + Uri authority = new Uri(_siteSettings.Authority); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); var callbackUrl = Url.Action("ConfirmEmail", "Account", @@ -703,10 +706,15 @@ IHtmlLocalizerFactory htmlLocalizerFactory, await _signInManager.SignInAsync(user, isPersistent: false); - await _emailSender.SendEmailAsync(Config.SiteSetup.Owner.Name, Config.SiteSetup.Owner.EMail, - $"[{_siteSettings.Title}] Inscription via {info.LoginProvider}: {user.UserName} ", $"{user.Id}/{user.UserName}/{user.Email}"); + await _emailSender.SendEmailAsync( + _siteSettings.Owner.Name, + _siteSettings.Owner.EMail, + $"[{_siteSettings.Title}] Inscription via {info.LoginProvider}: {user.UserName} ", + $"{user.Id}/{user.UserName}/{user.Email}"); - _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider); + _logger.LogInformation(6, + "User created an account using {Name} provider.", + info.LoginProvider); return Redirect(returnUrl); } diff --git a/src/Yavsc.Org/Controllers/Communicating/BlogspotController.cs b/src/Yavsc.Org/Controllers/Communicating/BlogspotController.cs index 98611e5fe..b55171879 100644 --- a/src/Yavsc.Org/Controllers/Communicating/BlogspotController.cs +++ b/src/Yavsc.Org/Controllers/Communicating/BlogspotController.cs @@ -109,8 +109,9 @@ namespace Yavsc.Org.Controllers { if (ModelState.IsValid) { - Models.Blog.BlogPost post = blogSpotService.Create(User.GetUserId(), - blogInput, Request.Form.Files); + var uid = User.GetUserId(); + Models.Blog.BlogPost post = blogSpotService.Create(uid, blogInput); + blogSpotService.AttachFiles(Request.Form.Files, uid, post.Id); return RedirectToAction("Index"); } return View("Edit", blogInput); diff --git a/src/Yavsc.Org/Controllers/Contracting/FrontOfficeController.cs b/src/Yavsc.Org/Controllers/Contracting/FrontOfficeController.cs index b86d0ab4a..549d80942 100644 --- a/src/Yavsc.Org/Controllers/Contracting/FrontOfficeController.cs +++ b/src/Yavsc.Org/Controllers/Contracting/FrontOfficeController.cs @@ -8,6 +8,7 @@ namespace Yavsc.Controllers using Helpers; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Localization; + using Microsoft.Extensions.Options; using Models; using ViewModels.FrontOffice; using Yavsc.Server.Helpers; @@ -20,18 +21,21 @@ namespace Yavsc.Controllers readonly ILogger _logger; readonly IStringLocalizer _SR; private readonly IBillingService _billing; + private readonly SiteSettings _siteSettings; public FrontOfficeController(ApplicationDbContext context, UserManager userManager, IBillingService billing, ILoggerFactory loggerFactory, - IStringLocalizer SR) + IStringLocalizer SR, + IOptions siteSettings) { _context = context; _userManager = userManager; _logger = loggerFactory.CreateLogger(); _SR = SR; _billing = billing; + _siteSettings = siteSettings.Value; } public ActionResult Index() { @@ -95,8 +99,8 @@ namespace Yavsc.Controllers [HttpGet] public IActionResult EstimatePdf(long id) { - ViewBag.TempDir = Config.SiteSetup.TempDir; - ViewBag.BillsDir = AbstractFileSystemHelpers.UserBillsDirName; + ViewBag.TempDir = _siteSettings.TempDir; + ViewBag.BillsDir = _siteSettings.Bills; var estimate = _context.Estimates.Include(x => x.Query) .Include(x => x.Query.Client) .Include(x => x.Query.PerformerProfile) diff --git a/src/Yavsc.Org/Controllers/FileSystemController.cs b/src/Yavsc.Org/Controllers/FileSystemController.cs index e4f18b39c..21a3325ff 100644 --- a/src/Yavsc.Org/Controllers/FileSystemController.cs +++ b/src/Yavsc.Org/Controllers/FileSystemController.cs @@ -1,20 +1,25 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Yavsc.Server.Helpers; -namespace Yavsc.Controllers +namespace Yavsc.Org.Controllers { public class FileSystemController : Controller { - public FileSystemController() + private SiteSettings _siteSettings; + + public FileSystemController(IOptions siteSettings) { + _siteSettings = siteSettings.Value; } + // Removed redundant empty constructor block public IActionResult Index(string subdir="") - { + { if (subdir !=null) if (!subdir.IsValidYavscPath()) return new BadRequestResult(); - var files = AbstractFileSystemHelpers.GetUserFiles(User.GetUserId(), subdir); + var files = FileSystemHelpers.GetUserFiles(_siteSettings, User.GetUserId(), subdir); return View(files); } } diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index e986620f1..8c1db2a73 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -1044,7 +1044,7 @@ public static class HostingExtensions Startup.Configure(app, siteSettings, smtpSettings, payPalSettings, googleAuthSettings, localization, loggerFactory, app.Environment.EnvironmentName); - app.ConfigureFileServerApp(); + app.ConfigureFileServerApp(siteSettings.Value); app.UseSession(); return app; } @@ -1238,24 +1238,44 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;"); #nullable disable public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app, + SiteSettings settings, bool enableDirectoryBrowsing = false) { + if (settings.GitRepository == null) + { + throw new InvalidOperationException("GitRepository path is not configured in SiteSettings."); + } + if (settings.Blog == null) + { + throw new InvalidOperationException("Blog path is not configured in SiteSettings."); + } + if (settings.Avatars == null) + { + throw new InvalidOperationException("Avatars path is not configured in SiteSettings."); + } + if (settings.Bills == null) + { + throw new InvalidOperationException("Bills path is not configured in SiteSettings."); + } + if (settings.TempDir == null) + { + throw new InvalidOperationException("TempDir path is not configured in SiteSettings."); + } - var userFilesDirInfo = new DirectoryInfo(Config.SiteSetup.Blog); - AbstractFileSystemHelpers.UserFilesDirName = userFilesDirInfo.FullName; + var userFilesDirInfo = new DirectoryInfo(settings.Blog); if (!userFilesDirInfo.Exists) userFilesDirInfo.Create(); Config.UserFilesOptions = new FileServerOptions() { - FileProvider = new PhysicalFileProvider(AbstractFileSystemHelpers.UserFilesDirName), + FileProvider = new PhysicalFileProvider(userFilesDirInfo.FullName), RequestPath = PathString.FromUriComponent(Constants.UserFilesPath), EnableDirectoryBrowsing = enableDirectoryBrowsing, }; Config.UserFilesOptions.EnableDefaultFiles = true; Config.UserFilesOptions.StaticFileOptions.ServeUnknownFileTypes = true; - var avatarsDirInfo = new DirectoryInfo(Config.SiteSetup.Avatars); + var avatarsDirInfo = new DirectoryInfo(settings.Avatars); if (!avatarsDirInfo.Exists) avatarsDirInfo.Create(); Config.AvatarsDirName = avatarsDirInfo.FullName; @@ -1267,7 +1287,7 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;"); }; - var gitdirinfo = new DirectoryInfo(Config.SiteSetup.GitRepository); + var gitdirinfo = new DirectoryInfo(settings.GitRepository); Config.GitDirName = gitdirinfo.FullName; if (!gitdirinfo.Exists) gitdirinfo.Create(); Config.GitOptions = new FileServerOptions() diff --git a/src/Yavsc.Org/Helpers/TeXHelpers.cs b/src/Yavsc.Org/Helpers/TeXHelpers.cs index daacb7417..f7cc812fb 100644 --- a/src/Yavsc.Org/Helpers/TeXHelpers.cs +++ b/src/Yavsc.Org/Helpers/TeXHelpers.cs @@ -91,7 +91,7 @@ namespace Yavsc.Helpers result = result.Replace("\n","\\tabularnewline "); return new TeXString(result); } - + public static string NewLinesWith(this string target, string separator) { @@ -115,11 +115,11 @@ namespace Yavsc.Helpers return new TeXString(string.Join(lineSeparator,texlines)); } - public static bool GenerateEstimatePdf(this PdfGenerationViewModel Model) + public static bool GenerateEstimatePdf(this SiteSettings settings, PdfGenerationViewModel Model) { string errorMsg = null; var billdir = Model.DestDir; - var tempdir = Config.SiteSetup.TempDir; + var tempdir = settings.TempDir; string name = Model.BaseFileName; string fullname = new FileInfo( System.IO.Path.Combine(tempdir, name)).FullName; @@ -154,7 +154,7 @@ namespace Yavsc.Helpers { errorMsg = $"Pdf generation failed with exit code: {p.ExitCode}"; } - else + else { fi.Delete(); var di = new DirectoryInfo(Path.Combine(tempdir,$"{Model.BaseFileName}.t2d")); diff --git a/src/Yavsc.Org/Services/BlogSpotService.cs b/src/Yavsc.Org/Services/BlogSpotService.cs index 39e9329f1..aa00d4121 100644 --- a/src/Yavsc.Org/Services/BlogSpotService.cs +++ b/src/Yavsc.Org/Services/BlogSpotService.cs @@ -2,6 +2,8 @@ using System.Diagnostics; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Yavsc; using Yavsc.Blogspot; using Yavsc.Models; using Yavsc.Models.Access; @@ -18,14 +20,17 @@ public class OldBlogSpotService private readonly ApplicationDbContext _context; private readonly IAuthorizationService _authorizationService; private readonly IFileSystemAuthManager fileSystemAuthManager; + private readonly SiteSettings siteSettings; public OldBlogSpotService(ApplicationDbContext context, IAuthorizationService authorizationService, - IFileSystemAuthManager fileSystemAuthManager) + IFileSystemAuthManager fileSystemAuthManager, + IOptions siteSettings) { _authorizationService = authorizationService; _context = context; this.fileSystemAuthManager = fileSystemAuthManager; + this.siteSettings = siteSettings.Value; } public Yavsc.Models.Blog.BlogPost Create(string userId, Yavsc.Models.Blog.BlogPost post, IFormFileCollection files) @@ -45,7 +50,7 @@ public class OldBlogSpotService // Créer un répertoire pour les fichiers du blog string blogFilesSubdir = $"blogs/{post.Id}"; string destDir = Path.Combine( - AbstractFileSystemHelpers.UserFilesDirName, + siteSettings.Blog, user.UserName, blogFilesSubdir ); diff --git a/src/Yavsc.Org/Startup.cs b/src/Yavsc.Org/Startup.cs index 558a95665..497ee6389 100644 --- a/src/Yavsc.Org/Startup.cs +++ b/src/Yavsc.Org/Startup.cs @@ -21,13 +21,10 @@ public class Startup { Config.GoogleSettings = googleSettings.Value; ResourcesHelpers.GlobalLocalizer = localizer; - Config.SiteSetup = siteSettings.Value; Config.SmtpSetup = smtpSettings.Value; Config.Authority = siteSettings.Value.Authority; string blogsDir = siteSettings.Value.Blog ?? throw new Exception("blogsDir is not set."); string billsDir = siteSettings.Value.Bills ?? throw new Exception("billsDir is not set."); - AbstractFileSystemHelpers.UserFilesDirName = new DirectoryInfo(blogsDir).FullName; - AbstractFileSystemHelpers.UserBillsDirName = new DirectoryInfo(billsDir).FullName; Config.Temp = siteSettings.Value.TempDir; Config.PayPalSettings = payPalSettings.Value; @@ -35,7 +32,7 @@ public class Startup // TODO implement an installation & upgrade procedure // Create required directories - foreach (string dir in new string[] { AbstractFileSystemHelpers.UserFilesDirName, AbstractFileSystemHelpers.UserBillsDirName, Config.Temp }) + foreach (string dir in new string[] { blogsDir, billsDir, Config.Temp }) { if (dir == null) { @@ -48,27 +45,27 @@ public class Startup di.Create(); } } - CheckApp(loggerFactory.CreateLogger(), environmentName); + CheckApp(siteSettings.Value, loggerFactory.CreateLogger(), environmentName); } - public static void CheckApp(ILogger logger, string environmentName) + public static void CheckApp(SiteSettings settings, ILogger logger, string environmentName) { var appData = Environment.GetEnvironmentVariable("APPDATA"); if (appData == null) { logger.LogWarning("AppData was not found in environment variables"); - if (Config.SiteSetup.DataDir == null) { - Config.SiteSetup.DataDir = "AppData"+environmentName; - logger.LogInformation("Using: "+Config.SiteSetup.DataDir); - } else logger.LogInformation("Using value from settings: "+Config.SiteSetup.DataDir); - DirectoryInfo di = new DirectoryInfo(Config.SiteSetup.DataDir); + if (settings.DataDir == null) { + settings.DataDir = "AppData"+environmentName; + logger.LogInformation("Using: "+settings.DataDir); + } else logger.LogInformation("Using value from settings: "+settings.DataDir); + DirectoryInfo di = new DirectoryInfo(settings.DataDir); if (!di.Exists) { di.Create(); logger.LogWarning("Created dir : "+di.FullName); } logger.LogInformation("Using existing directory: "+di.FullName); - Environment.SetEnvironmentVariable("APPDATA", Config.SiteSetup.DataDir); + Environment.SetEnvironmentVariable("APPDATA", settings.DataDir); logger.LogWarning("It has been set to : "+Environment.GetEnvironmentVariable("APPDATA")); } diff --git a/src/Yavsc.Org/ViewComponents/BillViewComponent.cs b/src/Yavsc.Org/ViewComponents/BillViewComponent.cs index 1db521f86..a4698e2f6 100644 --- a/src/Yavsc.Org/ViewComponents/BillViewComponent.cs +++ b/src/Yavsc.Org/ViewComponents/BillViewComponent.cs @@ -8,7 +8,7 @@ using Yavsc.ViewModels; using Yavsc.ViewModels.Gen; using Yavsc.Services; using Microsoft.EntityFrameworkCore; -using Yavsc.Server.Helpers; +using Microsoft.Extensions.Options; namespace Yavsc.ViewComponents { @@ -17,20 +17,29 @@ namespace Yavsc.ViewComponents readonly ApplicationDbContext dbContext; readonly IBillingService billing; readonly IStringLocalizer localizer; + private readonly SiteSettings siteSettings; - public BillViewComponent(ApplicationDbContext dbContext, + public BillViewComponent(ApplicationDbContext dbContext, IStringLocalizer localizer, - IBillingService billing) + IBillingService billing, + IOptions siteSettings) { this.billing = billing; this.dbContext = dbContext; this.localizer = localizer; + this.siteSettings = siteSettings.Value; } - public async Task InvokeAsync(string code, IBillable billable, OutputFormat format, bool asBill) + public async Task InvokeAsync( + string code, + IBillable billable, + OutputFormat format, + bool asBill, + SiteSettings settings + ) { - var di = new DirectoryInfo(Config.SiteSetup.Bills); - var dia = new DirectoryInfo(Config.SiteSetup.Avatars); + var di = new DirectoryInfo(settings.Bills); + var dia = new DirectoryInfo(settings.Avatars); ViewBag.BillsDir = di.FullName; ViewBag.AvatarsDir = dia.FullName; ViewBag.AsBill = asBill; // vrai pour une facture, sinon, c'est un devis @@ -56,9 +65,9 @@ namespace Yavsc.ViewComponents ViewBag.PerformerProfile = profile; ViewBag.ActivityLabel = (await dbContext.Activities.SingleAsync(a => a.Code == billable.ActivityCode)).Name; - var proaddr = profile.OrganizationAddress.Address; - ViewBag.PerformerOrganizationAddress = proaddr.SplitAddressToTeX() ; - ViewBag.FooterPerformerOrganizationAddress = proaddr.SplitAddressToTeX(", "); + var proAddr = profile.OrganizationAddress.Address; + ViewBag.PerformerOrganizationAddress = proAddr.SplitAddressToTeX() ; + ViewBag.FooterPerformerOrganizationAddress = proAddr.SplitAddressToTeX(", "); ViewBag.PerformerAddress = performer.PostalAddress?.Address.SplitAddressToTeX() ; switch (format) { @@ -75,23 +84,24 @@ namespace Yavsc.ViewComponents tex = writer.ToString(); } ViewComponentContext.ViewContext.Writer = oldWriter; - - var genrtrData = new PdfGenerationViewModel - { + + var pdfGenerationViewModel = new PdfGenerationViewModel + { Temp = Config.Temp, - TeXSource = tex, - DestDir = AbstractFileSystemHelpers.UserBillsDirName, + TeXSource = tex, + DestDir = settings.Blog, BaseFileName = billable.GetFileBaseName(billing) }; - if (genrtrData.GenerateEstimatePdf()) { - return this.View(new { Generated = genrtrData.BaseFileName+".pdf" }); + if (settings.GenerateEstimatePdf(pdfGenerationViewModel)) { + return this.View(new { Generated = pdfGenerationViewModel.BaseFileName+".pdf" }); } else { - return View(new { Error = genrtrData.GenerationErrorMessage } ); + return View(new { Error = pdfGenerationViewModel.GenerationErrorMessage } ); } } - ViewBag.BillFileInfo = billable.GetBillInfo(billing); + ViewBag.BillFileInfo = billable.GetBillInfo(billing, siteSettings); + ViewBag.Settings = settings; return View("Default",billable); - + } } diff --git a/src/Yavsc.Org/ViewComponents/DirectoryViewComponent.cs b/src/Yavsc.Org/ViewComponents/DirectoryViewComponent.cs index fea78afb0..fb8748d3c 100644 --- a/src/Yavsc.Org/ViewComponents/DirectoryViewComponent.cs +++ b/src/Yavsc.Org/ViewComponents/DirectoryViewComponent.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Yavsc.Models; using Yavsc.Server.Helpers; using Yavsc.ViewModels.UserFiles; @@ -11,24 +12,24 @@ namespace Yavsc.ViewComponents { private readonly UserManager _userManager; private readonly SignInManager _signInManager; - public DirectoryViewComponent(UserManager userManager, - SignInManager signInManager) + private readonly SiteSettings siteSettings; + + public DirectoryViewComponent( + UserManager userManager, + SignInManager signInManager, + IOptions siteSettings) { _userManager = userManager; _signInManager = signInManager; + this.siteSettings = siteSettings.Value; } public async Task InvokeAsync(string dirname) { string uid = ViewContext.HttpContext.User.GetUserId(); - - IViewComponentResult result = null; - - result = View(new UserDirectoryInfo( - AbstractFileSystemHelpers.UserFilesDirName, + return View(new UserDirectoryInfo( + siteSettings.Blog, uid, dirname)); - - return result; } } } diff --git a/src/Yavsc.Org/Views/Shared/Components/Bill/Bill_pdf.cshtml b/src/Yavsc.Org/Views/Shared/Components/Bill/Bill_pdf.cshtml index d053469a4..f49fad802 100644 --- a/src/Yavsc.Org/Views/Shared/Components/Bill/Bill_pdf.cshtml +++ b/src/Yavsc.Org/Views/Shared/Components/Bill/Bill_pdf.cshtml @@ -6,8 +6,8 @@ @using Yavsc.Helpers @model Yavsc.ViewModels.Gen.PdfGenerationViewModel -@{ - Model.GenerateEstimatePdf(); +@{ + ViewBag.Settings.GenerateEstimatePdf(Model); } @if (Model.Generated) {
diff --git a/src/Yavsc.Org/Views/Shared/Components/Estimate/Estimate_pdf.cshtml b/src/Yavsc.Org/Views/Shared/Components/Estimate/Estimate_pdf.cshtml index d053469a4..bef19b35a 100644 --- a/src/Yavsc.Org/Views/Shared/Components/Estimate/Estimate_pdf.cshtml +++ b/src/Yavsc.Org/Views/Shared/Components/Estimate/Estimate_pdf.cshtml @@ -7,7 +7,7 @@ @model Yavsc.ViewModels.Gen.PdfGenerationViewModel @{ - Model.GenerateEstimatePdf(); + SiteSettings.Value.GenerateEstimatePdf(Model); } @if (Model.Generated) {
diff --git a/src/Yavsc.Org/Views/Shared/_Nav.cshtml b/src/Yavsc.Org/Views/Shared/_Nav.cshtml index 23dc76fb7..385884fc0 100644 --- a/src/Yavsc.Org/Views/Shared/_Nav.cshtml +++ b/src/Yavsc.Org/Views/Shared/_Nav.cshtml @@ -1,13 +1,13 @@