refacto site settings
Some checks failed
Dotnet build and test / build (pull_request) Failing after 8m29s
Some checks failed
Dotnet build and test / build (pull_request) Failing after 8m29s
This commit is contained in:
parent
3e7e76edf2
commit
3bc4142383
33 changed files with 399 additions and 315 deletions
|
|
@ -57,12 +57,31 @@ namespace Yavsc.Blogs.Controllers
|
|||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> 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<System.ComponentModel.DataAnnotations.ValidationResult>();
|
||||
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<IActionResult> 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<System.ComponentModel.DataAnnotations.ValidationResult>();
|
||||
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<Models.Blog.BlogPost?> ReadPutBlogRequestAsync()
|
||||
/// <summary>
|
||||
/// Read a <see cref="Models.Blog.BlogPost"/> from either a
|
||||
/// JSON body or a multipart/form-data request carrying the
|
||||
/// payload in a <c>blog</c> form field. Shared by
|
||||
/// <see cref="PostBlog"/> and <see cref="PutBlog"/>: both
|
||||
/// accept the two shapes so PostIt can attach files on
|
||||
/// create as well as on update. Returns <c>null</c> (with
|
||||
/// the reason recorded in <c>ModelState</c>) when the
|
||||
/// multipart form has no usable <c>blog</c> field.
|
||||
/// </summary>
|
||||
private async Task<Models.Blog.BlogPost?> ReadBlogRequestAsync()
|
||||
{
|
||||
if (!Request.HasFormContentType)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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> siteSettings)
|
||||
|
||||
{
|
||||
AuthorizationService = authorizationService;
|
||||
dbContext = context;
|
||||
_logger = loggerFactory.CreateLogger<FileSystemApiController>();
|
||||
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<FileReceivedInfo> received = new List<FileReceivedInfo>();
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ChatHub> hubContext;
|
||||
readonly ApplicationDbContext dbContext;
|
||||
|
||||
public FileSystemStreamController(ApplicationDbContext context, ILiveProcessor liveProcessor, ILoggerFactory loggerFactory,
|
||||
IHubContext<ChatHub> hubContext)
|
||||
private readonly SiteSettings siteSettings;
|
||||
|
||||
public FileSystemStreamController(
|
||||
ApplicationDbContext context,
|
||||
ILiveProcessor liveProcessor,
|
||||
ILoggerFactory loggerFactory,
|
||||
IHubContext<ChatHub> hubContext,
|
||||
IOptions<SiteSettings> siteSettings)
|
||||
{
|
||||
this.dbContext = context;
|
||||
this.logger = loggerFactory.CreateLogger<FileSystemStreamController>();
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;"
|
||||
|
|
|
|||
Loading…
Reference in a new issue