diff --git a/Application/VoteForLink/VoteForLinkCommand.cs b/Application/VoteForLink/VoteForLinkCommand.cs new file mode 100644 index 0000000..e56741b --- /dev/null +++ b/Application/VoteForLink/VoteForLinkCommand.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; +using HN.Domain; +using MediatR; + +namespace HN.Application +{ + public sealed class VoteForLinkCommand : IRequest + { + [Required] + public Guid LinkId { get; set; } + + [Required] + public VoteType Type { get; set; } + + public VoteForLinkCommand(Guid linkId, VoteType type) + { + LinkId = linkId; + Type = type; + } + } +} \ No newline at end of file diff --git a/Application/VoteForLink/VoteForLinkCommandHandler.cs b/Application/VoteForLink/VoteForLinkCommandHandler.cs new file mode 100644 index 0000000..5c1965c --- /dev/null +++ b/Application/VoteForLink/VoteForLinkCommandHandler.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using HN.Domain; +using MediatR; + +namespace HN.Application +{ + public sealed class VoteForLinkCommandHandler : IRequestHandler + { + private readonly ILinkRepository _linkRepository; + + public VoteForLinkCommandHandler(ILinkRepository linkRepository) + { + _linkRepository = linkRepository; + } + + public async Task Handle(VoteForLinkCommand request, CancellationToken cancellationToken) + { + var link = await _linkRepository.GetByIdAsync(request.LinkId); + + switch (request.Type) + { + case VoteType.Up: + link.Upvote(); + break; + case VoteType.Down: + link.Downvote(); + break; + } + + await _linkRepository.UpdateAsync(link); + + return Unit.Value; + } + } +} \ No newline at end of file diff --git a/Apps/Website/Controllers/LinksController.cs b/Apps/Website/Controllers/LinksController.cs index 0b1a48a..aa7e811 100644 --- a/Apps/Website/Controllers/LinksController.cs +++ b/Apps/Website/Controllers/LinksController.cs @@ -3,6 +3,7 @@ using HN.Application; using MediatR; using System.Threading.Tasks; using System; +using HN.Domain; namespace Website.Controllers { @@ -32,6 +33,16 @@ namespace Website.Controllers return View(new AddLinkCommand()); } + [HttpPost("{controller}/{id:guid}/vote")] + [ValidateAntiForgeryToken] + public async Task Vote(Guid id, string url, VoteType type) + { + await _bus.Send(new VoteForLinkCommand(id, type)); + + SetFlash($"Successfuly {type} for {url}!"); + return RedirectToAction(nameof(Index)); + } + [HttpPost] [ValidateAntiForgeryToken] public async Task Create(AddLinkCommand command) diff --git a/Apps/Website/Views/Links/_LinkItem.cshtml b/Apps/Website/Views/Links/_LinkItem.cshtml index 2bd2b3f..7a6e43f 100644 --- a/Apps/Website/Views/Links/_LinkItem.cshtml +++ b/Apps/Website/Views/Links/_LinkItem.cshtml @@ -1,3 +1,8 @@ @model HN.Application.LinkDto -@Model.Url - created at @Model.CreatedAt.ToLocalTime() (👍: @Model.UpVotes / 👎: @Model.DownVotes) \ No newline at end of file +@Model.Url - created at @Model.CreatedAt.ToLocalTime() (👍: @Model.UpVotes / 👎: @Model.DownVotes) + +
+ 👍 + 👎 +
\ No newline at end of file diff --git a/Domain/ILinkRepository.cs b/Domain/ILinkRepository.cs index 0798d0b..016ee1f 100644 --- a/Domain/ILinkRepository.cs +++ b/Domain/ILinkRepository.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; namespace HN.Domain @@ -5,5 +6,7 @@ namespace HN.Domain public interface ILinkRepository { Task AddAsync(Link link); + Task UpdateAsync(Link link); + Task GetByIdAsync(Guid id); } } \ No newline at end of file diff --git a/Domain/Link.cs b/Domain/Link.cs index e17a0e0..121dd40 100644 --- a/Domain/Link.cs +++ b/Domain/Link.cs @@ -23,5 +23,15 @@ namespace HN.Domain { return new Link(url); } + + public void Upvote() + { + _votes.Add(new Vote(VoteType.Up)); + } + + public void Downvote() + { + _votes.Add(new Vote(VoteType.Down)); + } } } diff --git a/Infrastructure/LinkRepository.cs b/Infrastructure/LinkRepository.cs index f047b11..842f73c 100644 --- a/Infrastructure/LinkRepository.cs +++ b/Infrastructure/LinkRepository.cs @@ -1,5 +1,7 @@ +using System; using System.Threading.Tasks; using HN.Domain; +using Microsoft.EntityFrameworkCore; namespace HN.Infrastructure { @@ -13,5 +15,15 @@ namespace HN.Infrastructure { await base.AddAsync(link); } + + public Task GetByIdAsync(Guid id) + { + return Entries.SingleOrDefaultAsync(o => o.Id == id); + } + + public async Task UpdateAsync(Link link) + { + await base.UpdateAsync(link); + } } } \ No newline at end of file diff --git a/Infrastructure/Repository.cs b/Infrastructure/Repository.cs index 0ca047f..fa85942 100644 --- a/Infrastructure/Repository.cs +++ b/Infrastructure/Repository.cs @@ -20,5 +20,10 @@ namespace HN.Infrastructure await Entries.AddRangeAsync(entities); await _context.SaveChangesAsync(); } + + protected async Task UpdateAsync(params TEntity[] entities) + { + await _context.SaveChangesAsync(); + } } } \ No newline at end of file