Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
8faabbb5ff |
8 changed files with 96 additions and 148 deletions
|
|
@ -11,7 +11,6 @@ using Yavsc.Server.Helpers;
|
||||||
using Yavsc.Tests.Shared;
|
using Yavsc.Tests.Shared;
|
||||||
using Yavsc.Blogs.Tests.Fixtures;
|
using Yavsc.Blogs.Tests.Fixtures;
|
||||||
using BlogPostDto = Yavsc.Blogspot.BlogPostDto;
|
using BlogPostDto = Yavsc.Blogspot.BlogPostDto;
|
||||||
using NuGet.Protocol;
|
|
||||||
|
|
||||||
namespace Yavsc.Blogs.Tests;
|
namespace Yavsc.Blogs.Tests;
|
||||||
|
|
||||||
|
|
@ -339,9 +338,9 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
ResetAndSeedDefaultUser();
|
ResetAndSeedDefaultUser();
|
||||||
using var http = NewClient(subject: "tester");
|
using var http = NewClient(subject: "tester");
|
||||||
|
|
||||||
// AttachFiles writes under the fixture-configured
|
var previousRoot = "blog";
|
||||||
// SiteSettings.Blog (BlogFilesRoot), not a local temp dir.
|
var tempRoot = Path.Combine(Path.GetTempPath(), "yavsc-blogs-tests-files-" + Guid.NewGuid().ToString("N"));
|
||||||
var filesRoot = _fixture.BlogFilesRoot;
|
Directory.CreateDirectory(tempRoot);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -374,10 +373,8 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
DateModified = DateTime.UtcNow
|
DateModified = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
var form = new MultipartFormDataContent
|
var form = new MultipartFormDataContent();
|
||||||
{
|
form.Add(new StringContent(JsonSerializer.Serialize(update)), "blog");
|
||||||
{ new StringContent(JsonSerializer.Serialize(update)), "blog" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var fileBytes = System.Text.Encoding.UTF8.GetBytes("payload test");
|
var fileBytes = System.Text.Encoding.UTF8.GetBytes("payload test");
|
||||||
var fileContent = new ByteArrayContent(fileBytes);
|
var fileContent = new ByteArrayContent(fileBytes);
|
||||||
|
|
@ -407,9 +404,7 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// BlogFilesRoot is the fixture-shared temp root (one per
|
try { Directory.Delete(tempRoot, recursive: true); } catch { }
|
||||||
// test run); leave it in place for the other multipart
|
|
||||||
// tests. The OS reclaims it.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,9 +478,9 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
ResetAndSeedDefaultUser();
|
ResetAndSeedDefaultUser();
|
||||||
using var http = NewClient(subject: "tester");
|
using var http = NewClient(subject: "tester");
|
||||||
|
|
||||||
// AttachFiles writes under the fixture-configured
|
var previousRoot = "blog";
|
||||||
// SiteSettings.Blog (BlogFilesRoot), not a local temp dir.
|
var tempRoot = Path.Combine(Path.GetTempPath(), "yavsc-blogs-tests-files-" + Guid.NewGuid().ToString("N"));
|
||||||
var filesRoot = _fixture.BlogFilesRoot;
|
Directory.CreateDirectory(tempRoot);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -571,18 +566,16 @@ public sealed class BlogApiTests : IClassFixture<BlogsWebServerFixture>
|
||||||
// markdown link points:
|
// markdown link points:
|
||||||
// {UserFilesDirName}/{user}/blogs/{postId}/{fileName}.
|
// {UserFilesDirName}/{user}/blogs/{postId}/{fileName}.
|
||||||
var expectedFile = Path.Combine(
|
var expectedFile = Path.Combine(
|
||||||
filesRoot, "tester", "blogs", created.Id.ToString(), "note.txt");
|
tempRoot, "tester", "blogs", created.Id.ToString(), "note.txt");
|
||||||
var written = Directory.Exists(filesRoot)
|
var written = Directory.Exists(tempRoot)
|
||||||
? string.Join(", ", Directory.EnumerateFiles(filesRoot, "*", SearchOption.AllDirectories))
|
? string.Join(", ", Directory.EnumerateFiles(tempRoot, "*", SearchOption.AllDirectories))
|
||||||
: "<none>";
|
: "<none>";
|
||||||
Assert.True(File.Exists(expectedFile),
|
Assert.True(File.Exists(expectedFile),
|
||||||
$"Expected uploaded file at {expectedFile}. Actually written: {written}");
|
$"Expected uploaded file at {expectedFile}. Actually written: {written}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// BlogFilesRoot is the fixture-shared temp root (one per
|
try { Directory.Delete(tempRoot, recursive: true); } catch { }
|
||||||
// test run); leave it in place for the other multipart
|
|
||||||
// tests. The OS reclaims it.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,16 +63,6 @@ public sealed class BlogsWebServerFixture : WebHostFixture
|
||||||
public long PostId { get; private set; }
|
public long PostId { get; private set; }
|
||||||
public string DefaultUserLogin { get => "alice"; }
|
public string DefaultUserLogin { get => "alice"; }
|
||||||
|
|
||||||
/// <summary>Root directory under which
|
|
||||||
/// <c>BlogSpotService.AttachFiles</c> writes uploaded files
|
|
||||||
/// during tests (the configured <c>SiteSettings.Blog</c>).
|
|
||||||
/// Attachments land at
|
|
||||||
/// <c>{BlogFilesRoot}/{userName}/blogs/{postId}/{fileName}</c>.
|
|
||||||
/// A fresh per-run temp directory, so tests can assert on the
|
|
||||||
/// physical file without touching the developer's real
|
|
||||||
/// user-files tree.</summary>
|
|
||||||
public string BlogFilesRoot { get; private set; } = string.Empty;
|
|
||||||
|
|
||||||
// A single SqliteConnection held open at the static level,
|
// A single SqliteConnection held open at the static level,
|
||||||
// mirroring how Yavsc.Org.Tests.WebServerFixture hoists its
|
// mirroring how Yavsc.Org.Tests.WebServerFixture hoists its
|
||||||
// shared configuration into static slots. Closing the
|
// shared configuration into static slots. Closing the
|
||||||
|
|
@ -122,18 +112,6 @@ public sealed class BlogsWebServerFixture : WebHostFixture
|
||||||
builder.Services.AddSingleton<IFileSystemAuthManager>(
|
builder.Services.AddSingleton<IFileSystemAuthManager>(
|
||||||
new NoopFileSystemAuthManager());
|
new NoopFileSystemAuthManager());
|
||||||
|
|
||||||
// BlogSpotService.AttachFiles writes uploaded files under
|
|
||||||
// siteSettings.Blog. Without a configured SiteSettings the
|
|
||||||
// IOptions<SiteSettings> 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<SiteSettings>(s =>
|
|
||||||
{
|
|
||||||
s.Blog = BlogFilesRoot;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Real BlogSpotService — same instance the production host
|
// Real BlogSpotService — same instance the production host
|
||||||
// builds (ApplicationDbContext, IAuthorizationService,
|
// builds (ApplicationDbContext, IAuthorizationService,
|
||||||
// IFileSystemAuthManager). With PermissionHandler registered
|
// IFileSystemAuthManager). With PermissionHandler registered
|
||||||
|
|
|
||||||
|
|
@ -57,31 +57,12 @@ namespace Yavsc.Blogs.Controllers
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
public async Task<IActionResult> PutBlog(long id)
|
public async Task<IActionResult> PutBlog(long id)
|
||||||
{
|
{
|
||||||
var blog = await ReadBlogRequestAsync();
|
var blog = await ReadPutBlogRequestAsync();
|
||||||
if (blog is null)
|
if (blog is null)
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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
|
// These properties are server-managed or optional graph members and
|
||||||
// should not block JSON payloads coming from API clients.
|
// should not block JSON payloads coming from API clients.
|
||||||
ModelState.Remove(nameof(Models.Blog.BlogPost.Author));
|
ModelState.Remove(nameof(Models.Blog.BlogPost.Author));
|
||||||
|
|
@ -112,8 +93,7 @@ namespace Yavsc.Blogs.Controllers
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await blogSpotService.Modify(User, blog);
|
await blogSpotService.Modify(User, blog, files);
|
||||||
blogSpotService.AttachFiles(files, User.GetUserId(), id);
|
|
||||||
}
|
}
|
||||||
catch (AuthorizationFailureException)
|
catch (AuthorizationFailureException)
|
||||||
{
|
{
|
||||||
|
|
@ -125,14 +105,8 @@ namespace Yavsc.Blogs.Controllers
|
||||||
|
|
||||||
// POST: api/v1/blogspot
|
// POST: api/v1/blogspot
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> PostBlog()
|
public IActionResult PostBlog([FromBody] Models.Blog.BlogPost blog)
|
||||||
{
|
{
|
||||||
var blog = await ReadBlogRequestAsync();
|
|
||||||
if (blog is null)
|
|
||||||
{
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// These properties are server-managed or optional graph members and
|
// These properties are server-managed or optional graph members and
|
||||||
// should not block JSON payloads coming from API clients.
|
// should not block JSON payloads coming from API clients.
|
||||||
ModelState.Remove(nameof(Models.Blog.BlogPost.Author));
|
ModelState.Remove(nameof(Models.Blog.BlogPost.Author));
|
||||||
|
|
@ -141,46 +115,35 @@ namespace Yavsc.Blogs.Controllers
|
||||||
ModelState.Remove(nameof(Models.Blog.BlogPost.UserCreated));
|
ModelState.Remove(nameof(Models.Blog.BlogPost.UserCreated));
|
||||||
ModelState.Remove(nameof(Models.Blog.BlogPost.UserModified));
|
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)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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:
|
// Two valid use cases for this endpoint:
|
||||||
// 1. JSON body only (no files) — PostIt path.
|
// 1. JSON body only (no files) — PostIt path.
|
||||||
// 2. multipart/form-data with a 'blog' field + 0..N
|
// 2. multipart/form-data with a 'blog' field + 0..N
|
||||||
// files — PostIt "create with attachments" path.
|
// files — future browser / server-rendered path.
|
||||||
//
|
//
|
||||||
// Branch on HasFormContentType: pass the form files when
|
// Branch on HasFormContentType: pass the form files when
|
||||||
// present, pass an empty collection otherwise. Reading
|
// present, pass an empty collection otherwise. The
|
||||||
// Request.Form.Files on a plain JSON request throws
|
// FileSystem branch in BlogSpotService.Create then
|
||||||
// "This request does not have a Content-Type header…",
|
// short-circuits to "no files to handle".
|
||||||
// and AttachFiles short-circuits on an empty collection.
|
|
||||||
var files = Request.HasFormContentType
|
var files = Request.HasFormContentType
|
||||||
? Request.Form.Files
|
? Request.Form.Files
|
||||||
: (IFormFileCollection)new FormFileCollection();
|
: (IFormFileCollection)new FormFileCollection();
|
||||||
var uid = User.GetUserId();
|
var uid = User.GetUserId();
|
||||||
var post = blogSpotService.Create(uid, blog);
|
var post = blogSpotService.Create(uid, blog, files);
|
||||||
blogSpotService.AttachFiles(files, uid, post.Id);
|
|
||||||
return CreatedAtRoute("GetBlog", new { id = post.Id },
|
return CreatedAtRoute("GetBlog", new { id = post.Id },
|
||||||
post.GetPayload());
|
post.GetPayload());
|
||||||
}
|
}
|
||||||
|
|
@ -247,17 +210,7 @@ namespace Yavsc.Blogs.Controllers
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private async Task<Models.Blog.BlogPost?> ReadPutBlogRequestAsync()
|
||||||
/// 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)
|
if (!Request.HasFormContentType)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,6 @@
|
||||||
"FavIcon": "/favicon.ico",
|
"FavIcon": "/favicon.ico",
|
||||||
"Icon": "/images/yavsc.png",
|
"Icon": "/images/yavsc.png",
|
||||||
"GitRepository": "testingrepo",
|
"GitRepository": "testingrepo",
|
||||||
"Blog": "blog",
|
|
||||||
"Bills": "bills",
|
|
||||||
"TempDir": "temp",
|
|
||||||
"Avatars": "avatars",
|
|
||||||
"Owner": {
|
"Owner": {
|
||||||
"Name": "Site Owner Name",
|
"Name": "Site Owner Name",
|
||||||
"EMail": "your@email",
|
"EMail": "your@email",
|
||||||
|
|
|
||||||
|
|
@ -109,9 +109,8 @@ namespace Yavsc.Org.Controllers
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
var uid = User.GetUserId();
|
Models.Blog.BlogPost post = blogSpotService.Create(User.GetUserId(),
|
||||||
Models.Blog.BlogPost post = blogSpotService.Create(uid, blogInput);
|
blogInput, Request.Form.Files);
|
||||||
blogSpotService.AttachFiles(Request.Form.Files, uid, post.Id);
|
|
||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
return View("Edit", blogInput);
|
return View("Edit", blogInput);
|
||||||
|
|
|
||||||
|
|
@ -1241,26 +1241,6 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;");
|
||||||
SiteSettings settings,
|
SiteSettings settings,
|
||||||
bool enableDirectoryBrowsing = false)
|
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(settings.Blog);
|
var userFilesDirInfo = new DirectoryInfo(settings.Blog);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@
|
||||||
"Bills": "bills",
|
"Bills": "bills",
|
||||||
"Blog": "blog",
|
"Blog": "blog",
|
||||||
"TempDir": "temp",
|
"TempDir": "temp",
|
||||||
"DataDir": "data",
|
"DataDir": "data"
|
||||||
"GitRepository": "git"
|
|
||||||
},
|
},
|
||||||
"Smtp": {
|
"Smtp": {
|
||||||
"Host": "[YOURSMTPHOST]",
|
"Host": "[YOURSMTPHOST]",
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,14 @@ public class BlogSpotService
|
||||||
this.siteSettings = siteSettings.Value;
|
this.siteSettings = siteSettings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AttachFiles(IFormFileCollection files, string userId, long postId)
|
public BlogPost Create(string userId, BlogPost post, IFormFileCollection files)
|
||||||
{
|
{
|
||||||
|
// Sauvegarder le post d'abord pour obtenir son ID
|
||||||
|
// Le createur vient de l'authentification, donc on ne le prend pas du post
|
||||||
|
post.AuthorId = userId;
|
||||||
|
_context.BlogSpot.Add(post);
|
||||||
|
_context.SaveChanges(userId);
|
||||||
|
|
||||||
// Traiter les fichiers attaches s'il y en a
|
// Traiter les fichiers attaches s'il y en a
|
||||||
if (files != null && files.Count > 0)
|
if (files != null && files.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +52,7 @@ public class BlogSpotService
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string blogFilesSubdir = $"blogs/{postId}";
|
string blogFilesSubdir = $"blogs/{post.Id}";
|
||||||
string destDir = Path.Combine(
|
string destDir = Path.Combine(
|
||||||
siteSettings.Blog,
|
siteSettings.Blog,
|
||||||
user.UserName,
|
user.UserName,
|
||||||
|
|
@ -70,7 +76,7 @@ public class BlogSpotService
|
||||||
|
|
||||||
var attachment = new BlogAttachedFile
|
var attachment = new BlogAttachedFile
|
||||||
{
|
{
|
||||||
PostId = postId,
|
PostId = post.Id,
|
||||||
FileId = uploadedFile.Id
|
FileId = uploadedFile.Id
|
||||||
};
|
};
|
||||||
_context.BlogAttachedFiles.Add(attachment);
|
_context.BlogAttachedFiles.Add(attachment);
|
||||||
|
|
@ -83,15 +89,7 @@ public class BlogSpotService
|
||||||
Debug.WriteLine($"Erreur lors du traitement des fichiers : {ex.Message}");
|
Debug.WriteLine($"Erreur lors du traitement des fichiers : {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public BlogPost Create(string userId, BlogPost post )
|
|
||||||
{
|
|
||||||
// Sauvegarder le post d'abord pour obtenir son ID
|
|
||||||
// Le createur vient de l'authentification, donc on ne le prend pas du post
|
|
||||||
post.AuthorId = userId;
|
|
||||||
_context.BlogSpot.Add(post);
|
|
||||||
_context.SaveChanges(userId);
|
|
||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,6 +191,58 @@ public class BlogSpotService
|
||||||
_context.SaveChanges(user.GetUserId());
|
_context.SaveChanges(user.GetUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Modify(ClaimsPrincipal user, BlogPost blog, IFormFileCollection files)
|
||||||
|
{
|
||||||
|
await Modify(user, blog);
|
||||||
|
|
||||||
|
if (files == null || files.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var userId = user.GetUserId();
|
||||||
|
var userEntity = _context.Users.FirstOrDefault(u => u.Id == userId);
|
||||||
|
if (userEntity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string blogFilesSubdir = $"blogs/{blog.Id}";
|
||||||
|
string destDir = Path.Combine(
|
||||||
|
siteSettings.Blog,
|
||||||
|
userEntity.UserName,
|
||||||
|
blogFilesSubdir);
|
||||||
|
var di = new DirectoryInfo(destDir);
|
||||||
|
if (!di.Exists) di.Create();
|
||||||
|
|
||||||
|
foreach (var formFile in files)
|
||||||
|
{
|
||||||
|
var fileInfo = userEntity.ReceiveUserFile(destDir, formFile);
|
||||||
|
if (fileInfo != null && !fileInfo.QuotaOffense)
|
||||||
|
{
|
||||||
|
var uploadedFile = new UploadedFile
|
||||||
|
{
|
||||||
|
Path = fileInfo.FileName,
|
||||||
|
ContentType = formFile.ContentType,
|
||||||
|
Length = formFile.Length
|
||||||
|
};
|
||||||
|
_context.UploadedFiles.Add(uploadedFile);
|
||||||
|
_context.SaveChanges(userId);
|
||||||
|
|
||||||
|
var attachment = new BlogAttachedFile
|
||||||
|
{
|
||||||
|
PostId = blog.Id,
|
||||||
|
FileId = uploadedFile.Id
|
||||||
|
};
|
||||||
|
_context.BlogAttachedFiles.Add(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.SaveChanges(userId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"Erreur lors du traitement des fichiers : {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<IBlogPost>> Index(ClaimsPrincipal user, string id, int skip = 0, int take = 25)
|
public async Task<IEnumerable<IBlogPost>> Index(ClaimsPrincipal user, string id, int skip = 0, int take = 25)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue