add command and handler to vote for links

This commit is contained in:
Julien Leicher 2020-12-10 12:49:06 +01:00
parent df00e15002
commit a8957ad6f7
No known key found for this signature in database
GPG Key ID: F2A187E5D2F626A9
8 changed files with 105 additions and 1 deletions

View File

@ -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;
}
}
}

View File

@ -0,0 +1,36 @@
using System.Threading;
using System.Threading.Tasks;
using HN.Domain;
using MediatR;
namespace HN.Application
{
public sealed class VoteForLinkCommandHandler : IRequestHandler<VoteForLinkCommand>
{
private readonly ILinkRepository _linkRepository;
public VoteForLinkCommandHandler(ILinkRepository linkRepository)
{
_linkRepository = linkRepository;
}
public async Task<Unit> 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;
}
}
}

View File

@ -3,6 +3,7 @@ using HN.Application;
using MediatR; using MediatR;
using System.Threading.Tasks; using System.Threading.Tasks;
using System; using System;
using HN.Domain;
namespace Website.Controllers namespace Website.Controllers
{ {
@ -32,6 +33,16 @@ namespace Website.Controllers
return View(new AddLinkCommand()); return View(new AddLinkCommand());
} }
[HttpPost("{controller}/{id:guid}/vote")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Vote(Guid id, string url, VoteType type)
{
await _bus.Send(new VoteForLinkCommand(id, type));
SetFlash($"Successfuly {type} for {url}!");
return RedirectToAction(nameof(Index));
}
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<IActionResult> Create(AddLinkCommand command) public async Task<IActionResult> Create(AddLinkCommand command)

View File

@ -1,3 +1,8 @@
@model HN.Application.LinkDto @model HN.Application.LinkDto
<a asp-action="Show" asp-controller="Links" asp-route-id="@Model.Id">@Model.Url - created at @Model.CreatedAt.ToLocalTime() (👍: @Model.UpVotes / 👎: @Model.DownVotes)</a> <a asp-action="Show" asp-controller="Links" asp-route-id="@Model.Id">@Model.Url - created at @Model.CreatedAt.ToLocalTime() (👍: @Model.UpVotes / 👎: @Model.DownVotes)</a>
<form asp-controller="Links" asp-action="Vote" asp-route-id="@Model.Id" asp-route-url="@Model.Url" method="post">
<input type="submit" name="type" value="up">👍</button>
<input type="submit" name="type" value="down">👎</button>
</form>

View File

@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace HN.Domain namespace HN.Domain
@ -5,5 +6,7 @@ namespace HN.Domain
public interface ILinkRepository public interface ILinkRepository
{ {
Task AddAsync(Link link); Task AddAsync(Link link);
Task UpdateAsync(Link link);
Task<Link> GetByIdAsync(Guid id);
} }
} }

View File

@ -23,5 +23,15 @@ namespace HN.Domain
{ {
return new Link(url); return new Link(url);
} }
public void Upvote()
{
_votes.Add(new Vote(VoteType.Up));
}
public void Downvote()
{
_votes.Add(new Vote(VoteType.Down));
}
} }
} }

View File

@ -1,5 +1,7 @@
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using HN.Domain; using HN.Domain;
using Microsoft.EntityFrameworkCore;
namespace HN.Infrastructure namespace HN.Infrastructure
{ {
@ -13,5 +15,15 @@ namespace HN.Infrastructure
{ {
await base.AddAsync(link); await base.AddAsync(link);
} }
public Task<Link> GetByIdAsync(Guid id)
{
return Entries.SingleOrDefaultAsync(o => o.Id == id);
}
public async Task UpdateAsync(Link link)
{
await base.UpdateAsync(link);
}
} }
} }

View File

@ -20,5 +20,10 @@ namespace HN.Infrastructure
await Entries.AddRangeAsync(entities); await Entries.AddRangeAsync(entities);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
protected async Task UpdateAsync(params TEntity[] entities)
{
await _context.SaveChangesAsync();
}
} }
} }