Ajout liste des commentaires d'un lien / ajout commentaire

This commit is contained in:
Julien LEICHER 2021-12-14 11:36:06 +01:00
parent d930693b58
commit c2d1abe808
No known key found for this signature in database
GPG Key ID: BE0761B6A007EB96
11 changed files with 225 additions and 43 deletions

View File

@ -0,0 +1,47 @@
using HackerNet.Application;
using Microsoft.AspNetCore.Mvc;
namespace HackerNet.Web.Controllers;
public class CommentsController : HackerController
{
private readonly LinkService _linkService;
public CommentsController(LinkService linkService)
{
_linkService = linkService;
}
[HttpGet]
public IActionResult New(Guid id)
{
var link = _linkService.GetLinkDetail(id);
ViewData["LinkUrl"] = link.Url;
return View(new PublishCommentCommand
{
LinkId = id
});
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult New(PublishCommentCommand cmd)
{
if (!ModelState.IsValid)
{
var link = _linkService.GetLinkDetail(cmd.LinkId);
ViewData["LinkUrl"] = link.Url;
return View(cmd);
}
_linkService.PublishComment(cmd);
SetFlashMessage("Votre commentaire a été publié !");
// asp-controller="Links" asp-action="Detail"
// asp-route-id="@Model.Id"
return RedirectToAction("Detail", "Links", new { id = cmd.LinkId });
}
}

View File

@ -1,4 +1,5 @@
using HackerNet.Application;
using HackerNet.Web.Models;
using Microsoft.AspNetCore.Mvc;
namespace HackerNet.Web.Controllers;
@ -20,12 +21,13 @@ public class LinksController : HackerController
// return View(_linkRepository.GetAll());// retourne Link[]
}
// TODO: Page de détail d'un lien
[HttpGet]
public IActionResult Detail(Guid id)
{
return View(_linkService.GetLinkDetail(id));
var link = _linkService.GetLinkDetail(id);
var comments = _linkService.GetLinkComments(id);
return View(new LinkDetailViewModel(link, comments));
}
[HttpGet]

View File

@ -0,0 +1,15 @@
using HackerNet.Application;
namespace HackerNet.Web.Models;
public class LinkDetailViewModel
{
public LinkHomePage Link { get; set; }
public LinkComment[] Comments { get; set; }
public LinkDetailViewModel(LinkHomePage link, LinkComment[] comments)
{
Link = link;
Comments = comments;
}
}

View File

@ -5,10 +5,14 @@ using HackerNet.Infrastructure.Repositories.Memory;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var linksRepository = new MemoryLinkRepository(new Link("https://localhost:7050/", "Youhouuu"));
var link = new Link("https://localhost:7050/", "Youhouuu");
var comment = new Comment(link.Id, "Wow!");
var linksRepository = new MemoryLinkRepository(link);
var commentsRepository = new MemoryCommentRepository(comment);
builder.Services.AddSingleton<ILinkRepository>(linksRepository);
builder.Services.AddSingleton<IReadStore>(linksRepository);
builder.Services.AddSingleton<ICommentRepository>(commentsRepository);
builder.Services.AddSingleton<IReadStore>(new MemoryReadStore(linksRepository, commentsRepository));
builder.Services.AddSingleton<LinkService>();
builder.Services.AddControllersWithViews();

View File

@ -0,0 +1,21 @@
@model HackerNet.Application.PublishCommentCommand
@{
ViewData["Title"] = $"Ajouter un commentaire sur {ViewData["LinkUrl"]}";
}
<div class="shadow-xl p-6">
<h1 class="font-semibold text-xl text-indigo-500">@ViewData["Title"]</h1>
<form asp-action="New" method="post">
<input type="hidden" asp-for="@Model.LinkId" />
<label asp-for="@Model.Content"></label>
<textarea class="mt-4 bg-gray-100 rounded-xl px-2 py-4 block w-full" asp-for="@Model.Content">
</textarea>
<span class="text-red-700 text-sm block" asp-validation-for="@Model.Content"></span>
<div class="mt-4 flex justify-end">
<button type="submit" class="px-4 py-2 text-indigo-500 font-semibold rounded-xl bg-indigo-100">Publier un lien</button>
</div>
</form>
</div>

View File

@ -1,6 +1,20 @@
@model HackerNet.Application.LinkHomePage
@model HackerNet.Web.Models.LinkDetailViewModel
@{
ViewData["Title"] = $"Détail du lien {Model.Url}";
ViewData["Title"] = $"Détail du lien {Model.Link.Url}";
}
<partial name="_LinkCard" model="@Model" />
<partial name="_LinkCard" model="@Model.Link" />
@if(Model.Comments.Length == 0)
{
<p>Aucun commentaire pour le moment.</p>
}
else
{
foreach (var comment in Model.Comments)
{
<p class="mb-6 shadow p-6">
@comment.Content
</p>
}
}

View File

@ -5,7 +5,9 @@
<p>@Model.Description</p>
<div class="mt-4">
<div class="flex gap-4 mt-4">
<a class="text-indigo-500 hover:underline" asp-controller="Links" asp-action="Detail" asp-route-id="@Model.Id">Détail du lien</a>
<a class="text-indigo-500 hover:underline" asp-controller="Comments" asp-action="New" asp-route-id="@Model.Id">Ajouter un commentaire</a>
<p>@Model.CommentsCount commentaire@(Model.CommentsCount > 1 ? "s" : "")</p>
</div>
</article>

View File

@ -5,11 +5,16 @@ namespace HackerNet.Application;
public class LinkService
{
private readonly ILinkRepository _repository;
private readonly ICommentRepository _commentRepository;
private readonly IReadStore _readStore;
public LinkService(ILinkRepository repository, IReadStore readStore)
public LinkService(
ILinkRepository repository,
ICommentRepository commentRepository,
IReadStore readStore)
{
_repository = repository;
_commentRepository = commentRepository;
_readStore = readStore;
}
@ -22,17 +27,30 @@ public class LinkService
return link.Id;
}
public Guid PublishComment(PublishCommentCommand cmd)
{
var comment = new Comment(cmd.LinkId, cmd.Content);
_commentRepository.Add(comment);
return comment.Id;
}
public LinkHomePage[] GetPublishedLinks()
=> _readStore.GetPublishedLinks();
public LinkHomePage GetLinkDetail(Guid id)
=> _readStore.GetLinkDetail(id);
public LinkComment[] GetLinkComments(Guid linkId)
=> _readStore.GetLinkComments(linkId);
}
public interface IReadStore
{
LinkHomePage[] GetPublishedLinks();
LinkHomePage GetLinkDetail(Guid id);
LinkComment[] GetLinkComments(Guid linkId);
}
public class LinkHomePage
@ -43,6 +61,11 @@ public class LinkHomePage
public int CommentsCount { get; set; }
}
public class LinkComment
{
public string Content { get; set; }
}
public class PublishLinkCommand
{
[Required(ErrorMessage = "L'url est requise")]
@ -52,4 +75,12 @@ public class PublishLinkCommand
[Required(ErrorMessage = "La description est obligatoire")]
public string Description { get; set; }
}
public class PublishCommentCommand
{
public Guid LinkId { get; set; }
[Required]
public string Content { get; set; }
}

View File

@ -0,0 +1,20 @@
using HackerNet.Domain;
namespace HackerNet.Infrastructure.Repositories.Memory;
public class MemoryCommentRepository : ICommentRepository
{
private List<Comment> _comments;
internal List<Comment> Comments => _comments;
public MemoryCommentRepository(params Comment[] comments)
{
_comments = comments.ToList();
}
public void Add(Comment comment)
{
_comments.Add(comment);
}
}

View File

@ -5,10 +5,12 @@ namespace HackerNet.Infrastructure.Repositories.Memory;
public class MemoryLinkRepository : ILinkRepository, IReadStore
public class MemoryLinkRepository : ILinkRepository
{
private List<Link> _links;
internal List<Link> Links => _links;
public MemoryLinkRepository(params Link[] links)
{
_links = links.ToList();
@ -18,36 +20,4 @@ public class MemoryLinkRepository : ILinkRepository, IReadStore
{
_links.Add(link);
}
public LinkHomePage GetLinkDetail(Guid id)
=> GetLinks(id).Single();
public LinkHomePage[] GetPublishedLinks()
{
// return (from l in _links
// orderby l.CreatedAt descending
// select new LinkHomePage
// {
// Id = l.Id,
// Url = l.Url,
// Description = l.Description,
// CommentsCount = 0,
// }).ToArray();
return GetLinks().ToArray();
}
private IEnumerable<LinkHomePage> GetLinks(Guid? id = null)
{
return _links
.Where(l => !id.HasValue || l.Id == id)
.OrderByDescending(l => l.CreatedAt)
.Select(l => new LinkHomePage
{
Id = l.Id,
Url = l.Url,
Description = l.Description,
CommentsCount = 0,
});
}
}

View File

@ -0,0 +1,56 @@
using HackerNet.Application;
namespace HackerNet.Infrastructure.Repositories.Memory;
public class MemoryReadStore : IReadStore
{
private readonly MemoryLinkRepository _linkRepository;
private readonly MemoryCommentRepository _commentRepository;
public MemoryReadStore(MemoryLinkRepository linkRepository, MemoryCommentRepository commentRepository)
{
_linkRepository = linkRepository;
_commentRepository = commentRepository;
}
public LinkComment[] GetLinkComments(Guid linkId)
=> _commentRepository.Comments
.OrderByDescending(c => c.CreatedAt)
.Select(c => new LinkComment
{
Content = c.Content
}).ToArray();
public LinkHomePage GetLinkDetail(Guid id)
=> GetLinks(id).Single();
public LinkHomePage[] GetPublishedLinks()
{
// return (from l in _links
// orderby l.CreatedAt descending
// select new LinkHomePage
// {
// Id = l.Id,
// Url = l.Url,
// Description = l.Description,
// CommentsCount = 0,
// }).ToArray();
return GetLinks().ToArray();
}
private IEnumerable<LinkHomePage> GetLinks(Guid? id = null)
{
return _linkRepository.Links
.Where(l => !id.HasValue || l.Id == id)
.OrderByDescending(l => l.CreatedAt)
.Select(l => new LinkHomePage
{
Id = l.Id,
Url = l.Url,
Description = l.Description,
CommentsCount = _commentRepository.Comments
.Count(c => c.LinkId == l.Id),
});
}
}