From c2d1abe8087e7ae7aecc484e7f54b49d9fb418d9 Mon Sep 17 00:00:00 2001 From: Julien LEICHER Date: Tue, 14 Dec 2021 11:36:06 +0100 Subject: [PATCH] Ajout liste des commentaires d'un lien / ajout commentaire --- .../Controllers/CommentsController.cs | 47 ++++++++++++++++ .../Controllers/LinksController.cs | 8 ++- .../Models/LinkDetailViewModel.cs | 15 +++++ Apps/HackerNet.Web/Program.cs | 8 ++- Apps/HackerNet.Web/Views/Comments/New.cshtml | 21 +++++++ Apps/HackerNet.Web/Views/Links/Detail.cshtml | 20 ++++++- .../Views/Shared/_LinkCard.cshtml | 4 +- HackerNet.Application/LinkService.cs | 33 ++++++++++- .../Memory/MemoryCommentRepository.cs | 20 +++++++ .../Memory/MemoryLinkRepository.cs | 36 +----------- .../Repositories/Memory/MemoryReadStore.cs | 56 +++++++++++++++++++ 11 files changed, 225 insertions(+), 43 deletions(-) create mode 100644 Apps/HackerNet.Web/Controllers/CommentsController.cs create mode 100644 Apps/HackerNet.Web/Models/LinkDetailViewModel.cs create mode 100644 Apps/HackerNet.Web/Views/Comments/New.cshtml create mode 100644 HackerNet.Infrastructure/Repositories/Memory/MemoryCommentRepository.cs create mode 100644 HackerNet.Infrastructure/Repositories/Memory/MemoryReadStore.cs diff --git a/Apps/HackerNet.Web/Controllers/CommentsController.cs b/Apps/HackerNet.Web/Controllers/CommentsController.cs new file mode 100644 index 0000000..da7f26a --- /dev/null +++ b/Apps/HackerNet.Web/Controllers/CommentsController.cs @@ -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 }); + } +} \ No newline at end of file diff --git a/Apps/HackerNet.Web/Controllers/LinksController.cs b/Apps/HackerNet.Web/Controllers/LinksController.cs index 41b40f5..3796673 100644 --- a/Apps/HackerNet.Web/Controllers/LinksController.cs +++ b/Apps/HackerNet.Web/Controllers/LinksController.cs @@ -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] diff --git a/Apps/HackerNet.Web/Models/LinkDetailViewModel.cs b/Apps/HackerNet.Web/Models/LinkDetailViewModel.cs new file mode 100644 index 0000000..0a1c689 --- /dev/null +++ b/Apps/HackerNet.Web/Models/LinkDetailViewModel.cs @@ -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; + } +} \ No newline at end of file diff --git a/Apps/HackerNet.Web/Program.cs b/Apps/HackerNet.Web/Program.cs index a7b2771..955b1e7 100644 --- a/Apps/HackerNet.Web/Program.cs +++ b/Apps/HackerNet.Web/Program.cs @@ -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(linksRepository); -builder.Services.AddSingleton(linksRepository); +builder.Services.AddSingleton(commentsRepository); +builder.Services.AddSingleton(new MemoryReadStore(linksRepository, commentsRepository)); builder.Services.AddSingleton(); builder.Services.AddControllersWithViews(); diff --git a/Apps/HackerNet.Web/Views/Comments/New.cshtml b/Apps/HackerNet.Web/Views/Comments/New.cshtml new file mode 100644 index 0000000..77b6036 --- /dev/null +++ b/Apps/HackerNet.Web/Views/Comments/New.cshtml @@ -0,0 +1,21 @@ +@model HackerNet.Application.PublishCommentCommand +@{ + ViewData["Title"] = $"Ajouter un commentaire sur {ViewData["LinkUrl"]}"; +} + +
+

@ViewData["Title"]

+ +
+ + + + + + +
+ +
+
+
\ No newline at end of file diff --git a/Apps/HackerNet.Web/Views/Links/Detail.cshtml b/Apps/HackerNet.Web/Views/Links/Detail.cshtml index 486375f..fa4f5ab 100644 --- a/Apps/HackerNet.Web/Views/Links/Detail.cshtml +++ b/Apps/HackerNet.Web/Views/Links/Detail.cshtml @@ -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}"; } - \ No newline at end of file + + +@if(Model.Comments.Length == 0) +{ +

Aucun commentaire pour le moment.

+} +else +{ + foreach (var comment in Model.Comments) + { +

+ @comment.Content +

+ } +} \ No newline at end of file diff --git a/Apps/HackerNet.Web/Views/Shared/_LinkCard.cshtml b/Apps/HackerNet.Web/Views/Shared/_LinkCard.cshtml index acdb57d..b222fa7 100644 --- a/Apps/HackerNet.Web/Views/Shared/_LinkCard.cshtml +++ b/Apps/HackerNet.Web/Views/Shared/_LinkCard.cshtml @@ -5,7 +5,9 @@

@Model.Description

-
+
Détail du lien + Ajouter un commentaire +

@Model.CommentsCount commentaire@(Model.CommentsCount > 1 ? "s" : "")

\ No newline at end of file diff --git a/HackerNet.Application/LinkService.cs b/HackerNet.Application/LinkService.cs index f06c049..97c7640 100644 --- a/HackerNet.Application/LinkService.cs +++ b/HackerNet.Application/LinkService.cs @@ -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; } } \ No newline at end of file diff --git a/HackerNet.Infrastructure/Repositories/Memory/MemoryCommentRepository.cs b/HackerNet.Infrastructure/Repositories/Memory/MemoryCommentRepository.cs new file mode 100644 index 0000000..f72d869 --- /dev/null +++ b/HackerNet.Infrastructure/Repositories/Memory/MemoryCommentRepository.cs @@ -0,0 +1,20 @@ +using HackerNet.Domain; + +namespace HackerNet.Infrastructure.Repositories.Memory; + +public class MemoryCommentRepository : ICommentRepository +{ + private List _comments; + + internal List Comments => _comments; + + public MemoryCommentRepository(params Comment[] comments) + { + _comments = comments.ToList(); + } + + public void Add(Comment comment) + { + _comments.Add(comment); + } +} \ No newline at end of file diff --git a/HackerNet.Infrastructure/Repositories/Memory/MemoryLinkRepository.cs b/HackerNet.Infrastructure/Repositories/Memory/MemoryLinkRepository.cs index 12bd2e4..59b7714 100644 --- a/HackerNet.Infrastructure/Repositories/Memory/MemoryLinkRepository.cs +++ b/HackerNet.Infrastructure/Repositories/Memory/MemoryLinkRepository.cs @@ -5,10 +5,12 @@ namespace HackerNet.Infrastructure.Repositories.Memory; -public class MemoryLinkRepository : ILinkRepository, IReadStore +public class MemoryLinkRepository : ILinkRepository { private List _links; + internal List 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 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, - }); - } } \ No newline at end of file diff --git a/HackerNet.Infrastructure/Repositories/Memory/MemoryReadStore.cs b/HackerNet.Infrastructure/Repositories/Memory/MemoryReadStore.cs new file mode 100644 index 0000000..d1c60ce --- /dev/null +++ b/HackerNet.Infrastructure/Repositories/Memory/MemoryReadStore.cs @@ -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 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), + }); + } +} \ No newline at end of file