b3c4615bc7
- Post.cshtml.cs: load hero image, tag from SiteSettings in SetViewDataAsync - Post.cshtml: show <img> with hero image in .doc-avatar when set, fall back to emoji only if no image is configured - .doc-avatar: circular crop with object-fit:cover, gold border - doc-title now uses HeroTag from settings (not hardcoded) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
157 lines
5.6 KiB
C#
157 lines
5.6 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using DrSousan.Api.Data;
|
|
using DrSousan.Api.Models;
|
|
|
|
namespace DrSousan.Api.Pages.Blog;
|
|
|
|
public class PostModel : PageModel
|
|
{
|
|
private readonly AppDbContext _db;
|
|
|
|
public PostModel(AppDbContext db) => _db = db;
|
|
|
|
public BlogPost? Post { get; private set; }
|
|
public List<CommentVm> Comments { get; private set; } = new();
|
|
public bool CommentSent { get; private set; } = false;
|
|
|
|
// Comment form binding
|
|
[BindProperty]
|
|
[Required(ErrorMessage = "نام الزامی است.")]
|
|
[MaxLength(100)]
|
|
public string CommentAuthor { get; set; } = "";
|
|
|
|
[BindProperty]
|
|
[MaxLength(200)]
|
|
[EmailAddress]
|
|
public string CommentEmail { get; set; } = "";
|
|
|
|
[BindProperty]
|
|
[Required(ErrorMessage = "متن نظر الزامی است.")]
|
|
public string CommentBody { get; set; } = "";
|
|
|
|
public async Task<IActionResult> OnGetAsync(string slug)
|
|
{
|
|
var post = await _db.BlogPosts
|
|
.Include(p => p.Category)
|
|
.FirstOrDefaultAsync(p => p.Slug == slug && p.IsPublished);
|
|
|
|
if (post is null) return NotFound();
|
|
|
|
// Increment view count
|
|
post.ViewCount++;
|
|
await _db.SaveChangesAsync();
|
|
|
|
Post = post;
|
|
await LoadCommentsAsync(post.Id);
|
|
await SetViewDataAsync(post);
|
|
return Page();
|
|
}
|
|
|
|
public async Task<IActionResult> OnPostAsync(string slug)
|
|
{
|
|
var post = await _db.BlogPosts
|
|
.Include(p => p.Category)
|
|
.FirstOrDefaultAsync(p => p.Slug == slug && p.IsPublished);
|
|
|
|
if (post is null) return NotFound();
|
|
|
|
Post = post;
|
|
await LoadCommentsAsync(post.Id);
|
|
await SetViewDataAsync(post);
|
|
|
|
if (!ModelState.IsValid) return Page();
|
|
|
|
// Sanitise
|
|
var body = System.Text.RegularExpressions.Regex.Replace(CommentBody ?? "", "<[^>]*>", "").Trim();
|
|
var authorName = System.Text.RegularExpressions.Regex.Replace(CommentAuthor ?? "", "<[^>]*>", "").Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(body) || string.IsNullOrWhiteSpace(authorName))
|
|
{
|
|
ModelState.AddModelError("", "نام و متن نظر الزامی است.");
|
|
return Page();
|
|
}
|
|
|
|
_db.Comments.Add(new Comment
|
|
{
|
|
BlogPostId = post.Id,
|
|
AuthorName = authorName,
|
|
AuthorEmail = CommentEmail ?? "",
|
|
Body = body,
|
|
IsApproved = false,
|
|
CreatedAt = DateTime.UtcNow
|
|
});
|
|
await _db.SaveChangesAsync();
|
|
|
|
CommentSent = true;
|
|
// Clear form
|
|
CommentAuthor = "";
|
|
CommentEmail = "";
|
|
CommentBody = "";
|
|
ModelState.Clear();
|
|
return Page();
|
|
}
|
|
|
|
private async Task LoadCommentsAsync(int postId)
|
|
{
|
|
var raw = await _db.Comments
|
|
.Where(c => c.BlogPostId == postId && c.IsApproved && c.ParentId == null)
|
|
.OrderBy(c => c.CreatedAt)
|
|
.Select(c => new
|
|
{
|
|
c.Id, c.AuthorName, c.Body, c.CreatedAt, c.IsAdminReply,
|
|
Replies = _db.Comments
|
|
.Where(r => r.ParentId == c.Id && r.IsApproved)
|
|
.OrderBy(r => r.CreatedAt)
|
|
.Select(r => new { r.Id, r.AuthorName, r.Body, r.CreatedAt, r.IsAdminReply })
|
|
.ToList()
|
|
}).ToListAsync();
|
|
|
|
Comments = raw.Select(c => new CommentVm
|
|
{
|
|
Id = c.Id, AuthorName = c.AuthorName, Body = c.Body,
|
|
CreatedAt = c.CreatedAt, IsAdminReply = c.IsAdminReply,
|
|
Replies = c.Replies.Select(r => new CommentVm
|
|
{
|
|
Id = r.Id, AuthorName = r.AuthorName, Body = r.Body,
|
|
CreatedAt = r.CreatedAt, IsAdminReply = r.IsAdminReply
|
|
}).ToList()
|
|
}).ToList();
|
|
}
|
|
|
|
private async Task SetViewDataAsync(BlogPost post)
|
|
{
|
|
var metaTitle = string.IsNullOrEmpty(post.MetaTitle) ? post.Title : post.MetaTitle;
|
|
var metaDesc = string.IsNullOrEmpty(post.MetaDescription) ? post.Excerpt : post.MetaDescription;
|
|
|
|
// Avoid duplicating the site name if MetaTitle already contains it
|
|
var suffix = " | دکتر سوسن آلطه";
|
|
ViewData["Title"] = metaTitle.Contains("دکتر سوسن") ? metaTitle : metaTitle + suffix;
|
|
ViewData["MetaDesc"] = metaDesc;
|
|
ViewData["Keywords"] = post.Keywords;
|
|
ViewData["OgImage"] = string.IsNullOrEmpty(post.OgImage) ? post.FeaturedImage : post.OgImage;
|
|
ViewData["ArticleType"] = post.ArticleType;
|
|
ViewData["Slug"] = post.Slug;
|
|
|
|
var heroSettings = await _db.SiteSettings
|
|
.Where(x => x.Section == "hero" && (x.Key == "name" || x.Key == "image" || x.Key == "tag"))
|
|
.ToListAsync();
|
|
ViewData["SiteName"] = heroSettings.FirstOrDefault(x => x.Key == "name")?.Value ?? "دکتر سوسن آلطه";
|
|
ViewData["HeroImage"] = heroSettings.FirstOrDefault(x => x.Key == "image")?.Value ?? "";
|
|
ViewData["HeroTag"] = heroSettings.FirstOrDefault(x => x.Key == "tag")?.Value ?? "پزشک عمومی و متخصص زیبایی پوست";
|
|
}
|
|
|
|
// View model for comments
|
|
public class CommentVm
|
|
{
|
|
public int Id { get; set; }
|
|
public string AuthorName { get; set; } = "";
|
|
public string Body { get; set; } = "";
|
|
public DateTime CreatedAt { get; set; }
|
|
public bool IsAdminReply { get; set; }
|
|
public List<CommentVm> Replies { get; set; } = new();
|
|
}
|
|
}
|