add-aspnet-identity #26
@ -10,15 +10,17 @@ namespace HN.Application
|
||||
public class AddLinkCommandHandler : IRequestHandler<AddLinkCommand, Guid>
|
||||
{
|
||||
private readonly ILinkRepository _repository;
|
||||
private readonly IExecutingUserProvider _executingUserProvider;
|
||||
|
||||
public AddLinkCommandHandler(ILinkRepository repository)
|
||||
public AddLinkCommandHandler(ILinkRepository repository, IExecutingUserProvider executingUserProvider)
|
||||
{
|
||||
this._repository = repository;
|
||||
_repository = repository;
|
||||
_executingUserProvider = executingUserProvider;
|
||||
}
|
||||
|
||||
public async Task<Guid> Handle(AddLinkCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var link = Link.FromUrl(request.Url);
|
||||
var link = Link.FromUrl(_executingUserProvider.GetCurrentUserId(), request.Url);
|
||||
|
||||
await this._repository.AddAsync(link);
|
||||
|
||||
|
||||
@ -10,17 +10,19 @@ namespace HN.Application
|
||||
{
|
||||
private readonly ILinkRepository _linkRepository;
|
||||
private readonly ICommentRepository _commentRepository;
|
||||
private readonly IExecutingUserProvider _executingUserProvider;
|
||||
|
||||
public CommentLinkCommandHandler(ILinkRepository linkRepository, ICommentRepository commentRepository)
|
||||
public CommentLinkCommandHandler(ILinkRepository linkRepository, ICommentRepository commentRepository, IExecutingUserProvider executingUserProvider)
|
||||
{
|
||||
_linkRepository = linkRepository;
|
||||
_commentRepository = commentRepository;
|
||||
_executingUserProvider = executingUserProvider;
|
||||
}
|
||||
|
||||
public async Task<Guid> Handle(CommentLinkCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var link = await _linkRepository.GetByIdAsync(request.LinkId);
|
||||
var comment = link.AddComment(request.Content);
|
||||
var comment = link.AddComment(_executingUserProvider.GetCurrentUserId(), request.Content);
|
||||
|
||||
await _commentRepository.AddAsync(comment);
|
||||
|
||||
|
||||
@ -18,11 +18,13 @@ namespace HN.Application
|
||||
public Task<LinkDto> Handle(GetLinkQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = from link in _context.Links
|
||||
join user in _context.Users on link.CreatedBy equals user.Id
|
||||
where link.Id == request.Id
|
||||
select new LinkDto
|
||||
{
|
||||
Id = link.Id,
|
||||
Url = link.Url,
|
||||
CreatedByName = user.UserName,
|
||||
CreatedAt = link.CreatedAt,
|
||||
UpVotes = link.Votes.Count(v => v.Type == VoteType.Up),
|
||||
DownVotes = link.Votes.Count(v => v.Type == VoteType.Down)
|
||||
|
||||
12
Application/IExecutingUserProvider.cs
Normal file
12
Application/IExecutingUserProvider.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace HN.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Permet de récupérer l'utilisateur courant effectuant une commande.
|
||||
/// </summary>
|
||||
public interface IExecutingUserProvider
|
||||
{
|
||||
Guid GetCurrentUserId();
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using HN.Domain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@ -10,5 +11,6 @@ namespace HN.Application
|
||||
{
|
||||
DbSet<Link> Links { get; }
|
||||
DbSet<Comment> Comments { get; }
|
||||
IQueryable<IUser> Users { get; }
|
||||
}
|
||||
}
|
||||
|
||||
10
Application/IUser.cs
Normal file
10
Application/IUser.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace HN.Application
|
||||
{
|
||||
public interface IUser
|
||||
{
|
||||
Guid Id { get; }
|
||||
string UserName { get; }
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ namespace HN.Application
|
||||
public Guid Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public string CreatedByName { get; set; }
|
||||
public int UpVotes { get; set; }
|
||||
public int DownVotes { get; set; }
|
||||
|
||||
|
||||
@ -46,10 +46,12 @@ namespace HN.Application
|
||||
public Task<LinkDto[]> Handle(ListLinksQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var links = from link in _context.Links
|
||||
join user in _context.Users on link.CreatedBy equals user.Id
|
||||
select new LinkDto
|
||||
{
|
||||
Id = link.Id,
|
||||
Url = link.Url,
|
||||
CreatedByName = user.UserName,
|
||||
CreatedAt = link.CreatedAt,
|
||||
UpVotes = link.Votes.Count(v => v.Type == VoteType.Up),
|
||||
DownVotes = link.Votes.Count(v => v.Type == VoteType.Down)
|
||||
|
||||
@ -8,23 +8,26 @@ namespace HN.Application
|
||||
public sealed class VoteForCommentCommandHandler : IRequestHandler<VoteForCommentCommand>
|
||||
{
|
||||
private readonly ICommentRepository _commentRepository;
|
||||
private readonly IExecutingUserProvider _executingUserProvider;
|
||||
|
||||
public VoteForCommentCommandHandler(ICommentRepository commentRepository)
|
||||
public VoteForCommentCommandHandler(ICommentRepository commentRepository, IExecutingUserProvider executingUserProvider)
|
||||
{
|
||||
_commentRepository = commentRepository;
|
||||
_executingUserProvider = executingUserProvider;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(VoteForCommentCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var comment = await _commentRepository.GetByIdAsync(request.CommentId);
|
||||
var userId = _executingUserProvider.GetCurrentUserId();
|
||||
|
||||
switch (request.Type)
|
||||
{
|
||||
case VoteType.Up:
|
||||
comment.Upvote();
|
||||
comment.Upvote(userId);
|
||||
break;
|
||||
case VoteType.Down:
|
||||
comment.Downvote();
|
||||
comment.Downvote(userId);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -8,23 +8,26 @@ namespace HN.Application
|
||||
public sealed class VoteForLinkCommandHandler : IRequestHandler<VoteForLinkCommand>
|
||||
{
|
||||
private readonly ILinkRepository _linkRepository;
|
||||
private readonly IExecutingUserProvider _executingUserProvider;
|
||||
|
||||
public VoteForLinkCommandHandler(ILinkRepository linkRepository)
|
||||
public VoteForLinkCommandHandler(ILinkRepository linkRepository, IExecutingUserProvider executingUserProvider)
|
||||
{
|
||||
_linkRepository = linkRepository;
|
||||
_executingUserProvider = executingUserProvider;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(VoteForLinkCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var link = await _linkRepository.GetByIdAsync(request.LinkId);
|
||||
var userId = _executingUserProvider.GetCurrentUserId();
|
||||
|
||||
switch (request.Type)
|
||||
{
|
||||
case VoteType.Up:
|
||||
link.Upvote();
|
||||
link.Upvote(userId);
|
||||
break;
|
||||
case VoteType.Down:
|
||||
link.Downvote();
|
||||
link.Downvote(userId);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
17
Apps/Website/Components/LoginViewComponent.cs
Normal file
17
Apps/Website/Components/LoginViewComponent.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Website.Components
|
||||
{
|
||||
public sealed class LoginViewComponent : ViewComponent
|
||||
{
|
||||
public IViewComponentResult Invoke()
|
||||
{
|
||||
if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
return View("LoggedIn");
|
||||
}
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Apps/Website/Controllers/AccountsController.cs
Normal file
100
Apps/Website/Controllers/AccountsController.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using HN.Infrastructure;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Website.Models;
|
||||
|
||||
namespace Website.Controllers
|
||||
{
|
||||
public sealed class AccountsController : BaseController
|
||||
{
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly SignInManager<User> _signInManager;
|
||||
|
||||
public AccountsController(UserManager<User> userManager, SignInManager<User> signInManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public IActionResult Register()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Register(RegisterViewModel command)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(command);
|
||||
}
|
||||
|
||||
var user = new User(command.Username);
|
||||
var result = await _userManager.CreateAsync(user, command.Password);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
ModelState.AddModelError(nameof(RegisterViewModel.Username), string.Join(", ", result.Errors.Select(e => e.Description)));
|
||||
return View(command);
|
||||
}
|
||||
|
||||
SetFlash("Account created, you can now sign in!");
|
||||
|
||||
return RedirectToAction(nameof(Login));
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public IActionResult Login()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Login(LoginViewModel command)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByNameAsync(command.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(LoginViewModel.Username), "Could not verify user identity");
|
||||
return View();
|
||||
}
|
||||
|
||||
var result = await _signInManager.PasswordSignInAsync(user, command.Password, true, false);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
ModelState.AddModelError(nameof(LoginViewModel.Username), "Could not verify user identity");
|
||||
return View();
|
||||
}
|
||||
|
||||
SetFlash("Successfuly connected!");
|
||||
|
||||
return RedirectToAction(nameof(LinksController.Index), "Links");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
|
||||
SetFlash("Successfuly disconnected!");
|
||||
|
||||
return RedirectToAction(nameof(Login));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,37 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Website.Models;
|
||||
|
||||
namespace Website.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
[AllowAnonymous]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using System;
|
||||
using HN.Domain;
|
||||
using Website.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Website.Controllers
|
||||
{
|
||||
@ -18,12 +19,14 @@ namespace Website.Controllers
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
return View(await _bus.Send(new ListLinksQuery()));
|
||||
}
|
||||
|
||||
[HttpGet("{controller}/{id:guid}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Show(Guid id)
|
||||
{
|
||||
var link = await _bus.Send(new GetLinkQuery(id));
|
||||
@ -31,11 +34,6 @@ namespace Website.Controllers
|
||||
return View(new ShowLinkViewModel(link, new CommentLinkCommand(id), comments));
|
||||
}
|
||||
|
||||
public IActionResult Create()
|
||||
{
|
||||
return View(new AddLinkCommand());
|
||||
}
|
||||
|
||||
[HttpPost("{controller}/{id:guid}/vote")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Vote(Guid id, string url, VoteType type, string redirectTo)
|
||||
@ -46,8 +44,14 @@ namespace Website.Controllers
|
||||
return Redirect(redirectTo);
|
||||
}
|
||||
|
||||
public IActionResult Create()
|
||||
{
|
||||
return View(new AddLinkCommand());
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
|
||||
public async Task<IActionResult> Create(AddLinkCommand command)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
|
||||
16
Apps/Website/CustomExceptionFilter.cs
Normal file
16
Apps/Website/CustomExceptionFilter.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Website
|
||||
{
|
||||
public sealed class CustomExceptionFilter : IExceptionFilter
|
||||
{
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
if (context.Exception is UserNotConnected)
|
||||
{
|
||||
context.Result = new UnauthorizedResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Apps/Website/HttpExecutingUserProvider.cs
Normal file
32
Apps/Website/HttpExecutingUserProvider.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using HN.Application;
|
||||
using HN.Infrastructure;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace Website
|
||||
{
|
||||
public sealed class HttpExecutingUserProvider : IExecutingUserProvider
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
public HttpExecutingUserProvider(IHttpContextAccessor httpContextAccessor, UserManager<User> userManager)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
public Guid GetCurrentUserId()
|
||||
{
|
||||
var uid = _userManager.GetUserId(_httpContextAccessor.HttpContext.User);
|
||||
|
||||
if (!Guid.TryParse(uid, out Guid result))
|
||||
{
|
||||
throw new UserNotConnected();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Apps/Website/Models/LoginViewModel.cs
Normal file
13
Apps/Website/Models/LoginViewModel.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Website.Models
|
||||
{
|
||||
public sealed class LoginViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
17
Apps/Website/Models/RegisterViewModel.cs
Normal file
17
Apps/Website/Models/RegisterViewModel.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Website.Models
|
||||
{
|
||||
public sealed class RegisterViewModel
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required]
|
||||
[Compare(nameof(Password))]
|
||||
public string PasswordConfirm { get; set; }
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,11 @@ using HN.Application;
|
||||
using HN.Domain;
|
||||
using HN.Infrastructure;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -28,15 +31,36 @@ namespace Website
|
||||
services.AddScoped<IHNContext, HNDbContext>();
|
||||
services.AddScoped<ILinkRepository, LinkRepository>();
|
||||
services.AddScoped<ICommentRepository, CommentRepository>();
|
||||
services.AddScoped<IExecutingUserProvider, HttpExecutingUserProvider>();
|
||||
services.AddMediatR(typeof(HN.Application.IHNContext));
|
||||
|
||||
// Permet d'avoir des routes en lowercase
|
||||
services.Configure<RouteOptions>(options =>
|
||||
{
|
||||
options.LowercaseUrls = true;
|
||||
options.LowercaseQueryStrings = true;
|
||||
});
|
||||
|
||||
services.AddControllersWithViews();
|
||||
// Pour permettre l'authentification
|
||||
services.AddIdentity<User, Role>(o =>
|
||||
{
|
||||
o.Password.RequiredLength = o.Password.RequiredUniqueChars = 0;
|
||||
o.Password.RequireDigit = o.Password.RequireLowercase = o.Password.RequireNonAlphanumeric = o.Password.RequireUppercase = false;
|
||||
})
|
||||
.AddEntityFrameworkStores<HNDbContext>();
|
||||
|
||||
// Permet de reconfigurer certaines parties préconfigurées par Identity https://github.com/dotnet/aspnetcore/blob/3ea1fc7aac9d43152908d5d45ae811f3df7ca399/src/Identity/Core/src/IdentityServiceCollectionExtensions.cs#L51
|
||||
services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, o =>
|
||||
{
|
||||
o.LoginPath = "/accounts/login";
|
||||
o.LogoutPath = "/accounts/logout";
|
||||
});
|
||||
|
||||
services.AddControllersWithViews(o =>
|
||||
{
|
||||
o.Filters.Add<CustomExceptionFilter>();
|
||||
o.Filters.Add(new AuthorizeFilter()); // Nécessite l'authentification par défaut
|
||||
});
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@ -59,6 +83,20 @@ namespace Website
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
// Permet de rediriger selon les codes d'erreurs retournés, notamment par notre CustomExceptionFilter
|
||||
app.UseStatusCodePages(context =>
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
var response = context.HttpContext.Response;
|
||||
if (response.StatusCode == (int)System.Net.HttpStatusCode.Unauthorized)
|
||||
{
|
||||
response.Redirect("/accounts/login");
|
||||
}
|
||||
|
||||
return System.Threading.Tasks.Task.CompletedTask;
|
||||
});
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
|
||||
12
Apps/Website/UserNotConnected.cs
Normal file
12
Apps/Website/UserNotConnected.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Website
|
||||
{
|
||||
public sealed class UserNotConnected : Exception
|
||||
{
|
||||
public UserNotConnected() : base("User not connected!")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Apps/Website/Views/Accounts/Login.cshtml
Normal file
13
Apps/Website/Views/Accounts/Login.cshtml
Normal file
@ -0,0 +1,13 @@
|
||||
@model LoginViewModel
|
||||
|
||||
<form asp-action="Login" method="post">
|
||||
<label asp-for="@Model.Username"></label>
|
||||
<input asp-for="@Model.Username" />
|
||||
<span asp-validation-for="@Model.Username"></span>
|
||||
|
||||
<label asp-for="@Model.Password"></label>
|
||||
<input type="password" asp-for="@Model.Password" />
|
||||
<span asp-validation-for="@Model.Password"></span>
|
||||
|
||||
<button type="submit">Sign in</button>
|
||||
</form>
|
||||
17
Apps/Website/Views/Accounts/Register.cshtml
Normal file
17
Apps/Website/Views/Accounts/Register.cshtml
Normal file
@ -0,0 +1,17 @@
|
||||
@model RegisterViewModel
|
||||
|
||||
<form asp-action="Register" method="post">
|
||||
<label asp-for="@Model.Username"></label>
|
||||
<input asp-for="@Model.Username" />
|
||||
<span asp-validation-for="@Model.Username"></span>
|
||||
|
||||
<label asp-for="@Model.Password"></label>
|
||||
<input type="password" asp-for="@Model.Password" />
|
||||
<span asp-validation-for="@Model.Password"></span>
|
||||
|
||||
<label asp-for="@Model.PasswordConfirm"></label>
|
||||
<input type="password" asp-for="@Model.PasswordConfirm" />
|
||||
<span asp-validation-for="@Model.PasswordConfirm"></span>
|
||||
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
@ -0,0 +1,2 @@
|
||||
<a asp-action="Register" asp-controller="Accounts">Register</a>
|
||||
<a asp-action="Login" asp-controller="Accounts">Sign in</a>
|
||||
@ -0,0 +1,4 @@
|
||||
<p>Connected as @User.Identity.Name</p>
|
||||
<form asp-action="Logout" asp-controller="Accounts" method="post">
|
||||
<button type="submit">Sign out</button>
|
||||
</form>
|
||||
@ -2,11 +2,15 @@
|
||||
|
||||
<div>
|
||||
<h2>Add a comment</h2>
|
||||
<form asp-action="Create" asp-controller="Comments" method="post">
|
||||
<input type="hidden" asp-for="@Model.LinkId" />
|
||||
<textarea asp-for="@Model.Content"></textarea>
|
||||
<span asp-validation-for="@Model.Content"></span>
|
||||
|
||||
<button type="submit">Post a comment</button>
|
||||
</form>
|
||||
@if(User.Identity.IsAuthenticated) {
|
||||
<form asp-action="Create" asp-controller="Comments" method="post">
|
||||
<input type="hidden" asp-for="@Model.LinkId" />
|
||||
<textarea asp-for="@Model.Content"></textarea>
|
||||
<span asp-validation-for="@Model.Content"></span>
|
||||
|
||||
<button type="submit">Post a comment</button>
|
||||
</form>
|
||||
} else {
|
||||
<p>Only logged in users can comment.</p>
|
||||
}
|
||||
</div>
|
||||
@ -4,8 +4,11 @@
|
||||
<div>
|
||||
👍: @Model.UpVotes / 👎: @Model.DownVotes
|
||||
</div>
|
||||
<form asp-action="Vote" asp-controller="Comments" asp-route-id="@Model.Id" method="post">
|
||||
<input type="hidden" name="redirectTo" value="@Context.Request.Path" />
|
||||
<input type="submit" name="type" value="up" />
|
||||
<input type="submit" name="type" value="down" />
|
||||
</form>
|
||||
|
||||
@if (User.Identity.IsAuthenticated) {
|
||||
<form asp-action="Vote" asp-controller="Comments" asp-route-id="@Model.Id" method="post">
|
||||
<input type="hidden" name="redirectTo" value="@Context.Request.Path" />
|
||||
<input type="submit" name="type" value="up" />
|
||||
<input type="submit" name="type" value="down" />
|
||||
</form>
|
||||
}
|
||||
@ -28,6 +28,8 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<vc:login />
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
@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() by @Model.CreatedByName (👍: @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="hidden" name="redirectTo" value="@Context.Request.Path" />
|
||||
<input type="submit" name="type" value="up" />
|
||||
<input type="submit" name="type" value="down" />
|
||||
</form>
|
||||
@if(User.Identity.IsAuthenticated) {
|
||||
<form asp-controller="Links" asp-action="Vote" asp-route-id="@Model.Id" asp-route-url="@Model.Url" method="post">
|
||||
<input type="hidden" name="redirectTo" value="@Context.Request.Path" />
|
||||
<input type="submit" name="type" value="up" />
|
||||
<input type="submit" name="type" value="down" />
|
||||
</form>
|
||||
}
|
||||
@ -1,34 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HN.Domain
|
||||
{
|
||||
public sealed class Comment
|
||||
public sealed class Comment : Votable
|
||||
{
|
||||
public Guid Id { get; private set; }
|
||||
public Guid LinkId { get; private set; }
|
||||
public string Content { get; private set; }
|
||||
public DateTime CreatedAt { get; private set; }
|
||||
private List<Vote> _votes;
|
||||
public IReadOnlyList<Vote> Votes => _votes;
|
||||
public Guid Id { get; }
|
||||
public Guid LinkId { get; }
|
||||
public string Content { get; }
|
||||
public Guid CreatedBy { get; }
|
||||
public DateTime CreatedAt { get; }
|
||||
|
||||
internal Comment(Guid linkId, string content)
|
||||
internal Comment(Guid linkId, Guid createdBy, string content) : base()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
LinkId = linkId;
|
||||
CreatedBy = createdBy;
|
||||
Content = content;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
_votes = new List<Vote>();
|
||||
}
|
||||
|
||||
public void Upvote()
|
||||
{
|
||||
_votes.Add(new Vote(VoteType.Up));
|
||||
}
|
||||
|
||||
public void Downvote()
|
||||
{
|
||||
_votes.Add(new Vote(VoteType.Down));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,42 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HN.Domain
|
||||
{
|
||||
public sealed class Link
|
||||
public sealed class Link : Votable
|
||||
{
|
||||
public Guid Id { get; }
|
||||
public string Url { get; }
|
||||
public DateTime CreatedAt { get; }
|
||||
private List<Vote> _votes;
|
||||
public IReadOnlyList<Vote> Votes => _votes;
|
||||
public Guid CreatedBy { get; }
|
||||
|
||||
private Link(string url)
|
||||
private Link(Guid createdBy, string url) : base()
|
||||
{
|
||||
this.Id = Guid.NewGuid();
|
||||
this.CreatedAt = DateTime.UtcNow;
|
||||
this.Url = url;
|
||||
this._votes = new List<Vote>();
|
||||
Id = Guid.NewGuid();
|
||||
CreatedBy = createdBy;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public static Link FromUrl(string url)
|
||||
public static Link FromUrl(Guid posterId, string url)
|
||||
{
|
||||
return new Link(url);
|
||||
return new Link(posterId, url);
|
||||
}
|
||||
|
||||
public void Upvote()
|
||||
public Comment AddComment(Guid userId, string content)
|
||||
{
|
||||
_votes.Add(new Vote(VoteType.Up));
|
||||
}
|
||||
|
||||
public void Downvote()
|
||||
{
|
||||
_votes.Add(new Vote(VoteType.Down));
|
||||
}
|
||||
|
||||
public Comment AddComment(string content)
|
||||
{
|
||||
return new Comment(Id, content);
|
||||
return new Comment(Id, userId, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
Domain/Votable.cs
Normal file
43
Domain/Votable.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace HN.Domain
|
||||
{
|
||||
/// <summary>
|
||||
/// Représente une entité sur laquelle on peut voter.
|
||||
/// </summary>
|
||||
public abstract class Votable
|
||||
{
|
||||
private List<Vote> _votes;
|
||||
public IReadOnlyList<Vote> Votes => _votes;
|
||||
|
||||
protected Votable()
|
||||
{
|
||||
_votes = new List<Vote>();
|
||||
}
|
||||
|
||||
public void Upvote(Guid userId)
|
||||
{
|
||||
UpsertUserVote(userId, VoteType.Up);
|
||||
}
|
||||
|
||||
public void Downvote(Guid userId)
|
||||
{
|
||||
UpsertUserVote(userId, VoteType.Down);
|
||||
}
|
||||
|
||||
private void UpsertUserVote(Guid userId, VoteType type)
|
||||
{
|
||||
var vote = _votes.SingleOrDefault(v => v.CreatedBy == userId);
|
||||
|
||||
if (vote == null)
|
||||
{
|
||||
_votes.Add(new Vote(userId, type));
|
||||
return;
|
||||
}
|
||||
|
||||
vote.HasType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,9 +5,21 @@ namespace HN.Domain
|
||||
public sealed class Vote
|
||||
{
|
||||
public VoteType Type { get; private set; }
|
||||
public Guid CreatedBy { get; }
|
||||
public DateTime CreatedAt { get; private set; }
|
||||
|
||||
internal Vote(VoteType type)
|
||||
internal Vote(Guid createdBy, VoteType type)
|
||||
{
|
||||
CreatedBy = createdBy;
|
||||
Type = type;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change le type d'un vote
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public void HasType(VoteType type)
|
||||
{
|
||||
Type = type;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
|
||||
@ -17,11 +17,14 @@ namespace HN.Infrastructure
|
||||
builder.Property(o => o.Content).IsRequired();
|
||||
builder.Property(o => o.CreatedAt).IsRequired();
|
||||
|
||||
builder.HasOne<User>().WithMany().HasForeignKey(nameof(Comment.CreatedBy)).IsRequired();
|
||||
|
||||
builder.OwnsMany(o => o.Votes, vote =>
|
||||
{
|
||||
vote.ToTable("comment_votes");
|
||||
vote.WithOwner().HasForeignKey("CommentId");
|
||||
vote.HasKey("CommentId");
|
||||
vote.HasKey("CommentId", nameof(Comment.CreatedBy));
|
||||
vote.HasOne<User>().WithMany().HasForeignKey(nameof(Vote.CreatedBy)).IsRequired();
|
||||
vote.Property(o => o.Type).IsRequired();
|
||||
vote.Property(o => o.CreatedAt).IsRequired();
|
||||
});
|
||||
|
||||
@ -14,11 +14,14 @@ namespace HN.Infrastructure.EntityTypes
|
||||
builder.Property(o => o.CreatedAt).IsRequired();
|
||||
builder.HasIndex(o => o.Url).IsUnique();
|
||||
|
||||
builder.HasOne<User>().WithMany().HasForeignKey(nameof(Link.CreatedBy)).IsRequired();
|
||||
|
||||
builder.OwnsMany(o => o.Votes, vote =>
|
||||
{
|
||||
vote.ToTable("link_votes");
|
||||
vote.WithOwner().HasForeignKey("LinkId");
|
||||
vote.HasKey("LinkId");
|
||||
vote.HasKey("LinkId", nameof(Link.CreatedBy));
|
||||
vote.HasOne<User>().WithMany().HasForeignKey(nameof(Vote.CreatedBy)).IsRequired();
|
||||
vote.Property(o => o.Type).IsRequired();
|
||||
vote.Property(o => o.CreatedAt).IsRequired();
|
||||
});
|
||||
|
||||
@ -1,16 +1,21 @@
|
||||
using HN.Application;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using HN.Application;
|
||||
using HN.Domain;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HN.Infrastructure
|
||||
{
|
||||
public sealed class HNDbContext : DbContext, IHNContext
|
||||
public sealed class HNDbContext : IdentityDbContext<User, Role, Guid>, IHNContext
|
||||
{
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
public DbSet<Link> Links { get; set; }
|
||||
public DbSet<Comment> Comments { get; set; }
|
||||
|
||||
IQueryable<IUser> IHNContext.Users => Users;
|
||||
|
||||
public HNDbContext()
|
||||
{
|
||||
|
||||
@ -21,7 +26,11 @@ namespace HN.Infrastructure
|
||||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) => modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
|
||||
}
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
364
Infrastructure/Migrations/20201211113924_AddNetIdentity.Designer.cs
generated
Normal file
364
Infrastructure/Migrations/20201211113924_AddNetIdentity.Designer.cs
generated
Normal file
@ -0,0 +1,364 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using HN.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(HNDbContext))]
|
||||
[Migration("20201211113924_AddNetIdentity")]
|
||||
partial class AddNetIdentity
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Comment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.ToTable("comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Link", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Url")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("links");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.Role", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Comment", b =>
|
||||
{
|
||||
b.HasOne("HN.Domain.Link", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CommentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("CommentId");
|
||||
|
||||
b1.ToTable("comment_votes");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CommentId");
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Link", b =>
|
||||
{
|
||||
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("LinkId");
|
||||
|
||||
b1.ToTable("link_votes");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("LinkId");
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Infrastructure/Migrations/20201211113924_AddNetIdentity.cs
Normal file
217
Infrastructure/Migrations/20201211113924_AddNetIdentity.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Infrastructure.Migrations
|
||||
{
|
||||
public partial class AddNetIdentity : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
UserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedUserName = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
Email = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
NormalizedEmail = table.Column<string>(type: "TEXT", maxLength: 256, nullable: true),
|
||||
EmailConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "TEXT", nullable: true),
|
||||
SecurityStamp = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ConcurrencyStamp = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "TEXT", nullable: true),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "TEXT", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
RoleId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ClaimValue = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ProviderKey = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ProviderDisplayName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
RoleId = table.Column<Guid>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
||||
408
Infrastructure/Migrations/20201211144029_AddCreatedBy.Designer.cs
generated
Normal file
408
Infrastructure/Migrations/20201211144029_AddCreatedBy.Designer.cs
generated
Normal file
@ -0,0 +1,408 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using HN.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(HNDbContext))]
|
||||
[Migration("20201211144029_AddCreatedBy")]
|
||||
partial class AddCreatedBy
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Comment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.ToTable("comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Link", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("Url")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("links");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.Role", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Comment", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HN.Domain.Link", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CommentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("CommentId", "CreatedBy");
|
||||
|
||||
b1.HasIndex("CreatedBy");
|
||||
|
||||
b1.ToTable("comment_votes");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CommentId");
|
||||
|
||||
b1.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Link", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("LinkId", "CreatedBy");
|
||||
|
||||
b1.HasIndex("CreatedBy");
|
||||
|
||||
b1.ToTable("link_votes");
|
||||
|
||||
b1.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("LinkId");
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
178
Infrastructure/Migrations/20201211144029_AddCreatedBy.cs
Normal file
178
Infrastructure/Migrations/20201211144029_AddCreatedBy.cs
Normal file
@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Infrastructure.Migrations
|
||||
{
|
||||
public partial class AddCreatedBy : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_link_votes",
|
||||
table: "link_votes");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_comment_votes",
|
||||
table: "comment_votes");
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "CreatedBy",
|
||||
table: "links",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "CreatedBy",
|
||||
table: "link_votes",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "CreatedBy",
|
||||
table: "comments",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "CreatedBy",
|
||||
table: "comment_votes",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_link_votes",
|
||||
table: "link_votes",
|
||||
columns: new[] { "LinkId", "CreatedBy" });
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_comment_votes",
|
||||
table: "comment_votes",
|
||||
columns: new[] { "CommentId", "CreatedBy" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_links_CreatedBy",
|
||||
table: "links",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_link_votes_CreatedBy",
|
||||
table: "link_votes",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_comments_CreatedBy",
|
||||
table: "comments",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_comment_votes_CreatedBy",
|
||||
table: "comment_votes",
|
||||
column: "CreatedBy");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_comment_votes_AspNetUsers_CreatedBy",
|
||||
table: "comment_votes",
|
||||
column: "CreatedBy",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_comments_AspNetUsers_CreatedBy",
|
||||
table: "comments",
|
||||
column: "CreatedBy",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_link_votes_AspNetUsers_CreatedBy",
|
||||
table: "link_votes",
|
||||
column: "CreatedBy",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_links_AspNetUsers_CreatedBy",
|
||||
table: "links",
|
||||
column: "CreatedBy",
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_comment_votes_AspNetUsers_CreatedBy",
|
||||
table: "comment_votes");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_comments_AspNetUsers_CreatedBy",
|
||||
table: "comments");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_link_votes_AspNetUsers_CreatedBy",
|
||||
table: "link_votes");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_links_AspNetUsers_CreatedBy",
|
||||
table: "links");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_links_CreatedBy",
|
||||
table: "links");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_link_votes",
|
||||
table: "link_votes");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_link_votes_CreatedBy",
|
||||
table: "link_votes");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_comments_CreatedBy",
|
||||
table: "comments");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_comment_votes",
|
||||
table: "comment_votes");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_comment_votes_CreatedBy",
|
||||
table: "comment_votes");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedBy",
|
||||
table: "links");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedBy",
|
||||
table: "link_votes");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedBy",
|
||||
table: "comments");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedBy",
|
||||
table: "comment_votes");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_link_votes",
|
||||
table: "link_votes",
|
||||
column: "LinkId");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_comment_votes",
|
||||
table: "comment_votes",
|
||||
column: "CommentId");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,11 +29,16 @@ namespace Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.ToTable("comments");
|
||||
@ -48,6 +53,9 @@ namespace Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
@ -55,14 +63,213 @@ namespace Infrastructure.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("Url")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("links");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.Role", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Infrastructure.User", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Comment", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HN.Domain.Link", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("LinkId")
|
||||
@ -74,18 +281,29 @@ namespace Infrastructure.Migrations
|
||||
b1.Property<Guid>("CommentId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("CommentId");
|
||||
b1.HasKey("CommentId", "CreatedBy");
|
||||
|
||||
b1.HasIndex("CreatedBy");
|
||||
|
||||
b1.ToTable("comment_votes");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CommentId");
|
||||
|
||||
b1.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
@ -93,27 +311,95 @@ namespace Infrastructure.Migrations
|
||||
|
||||
modelBuilder.Entity("HN.Domain.Link", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<Guid>("CreatedBy")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.HasKey("LinkId");
|
||||
b1.HasKey("LinkId", "CreatedBy");
|
||||
|
||||
b1.HasIndex("CreatedBy");
|
||||
|
||||
b1.ToTable("link_votes");
|
||||
|
||||
b1.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("LinkId");
|
||||
});
|
||||
|
||||
b.Navigation("Votes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
|
||||
{
|
||||
b.HasOne("HN.Infrastructure.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
||||
10
Infrastructure/Role.cs
Normal file
10
Infrastructure/Role.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace HN.Infrastructure
|
||||
{
|
||||
public sealed class Role : IdentityRole<Guid>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
14
Infrastructure/User.cs
Normal file
14
Infrastructure/User.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using HN.Application;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace HN.Infrastructure
|
||||
{
|
||||
public sealed class User : IdentityUser<Guid>, IUser
|
||||
{
|
||||
public User(string userName) : base(userName)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
13
README.md
13
README.md
@ -87,6 +87,19 @@ Proche de ce qui est fait en Blazor mais sans la partie interactivité. Possibil
|
||||
|
||||
#### Tag Helpers
|
||||
|
||||
### Authentification avec ASP.Net Identity Core
|
||||
|
||||
```console
|
||||
$ cd Infrastructure
|
||||
$ dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
|
||||
```
|
||||
|
||||
On fait hériter notre `HNDbContext` de `IdentityDbContext`. On peut créer des types customs pour nos User et Role de manière à utiliser des Guid et rester cohérent.
|
||||
|
||||
Côté web, on s'assure d'avoir bien ajouter `AddIdentity` avec les options qui nous intéressent.
|
||||
|
||||
Grâce à ça, nous aurons à notre disposition un `UserManager<User>` et un `SignInManager<User>` nous permettant de réaliser les opérations d'authentification. Bien penser au `UseAuthentication` avant le `UseAuthorization` afin que l'authentification puisse avoir lieu.
|
||||
|
||||
## Démarche
|
||||
|
||||
On crée un fichier solution avec `dotnet new sln`. On pourra alimenter ce fichier sln avec la commande `dotnet sln add DirProjet`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user