add-aspnet-identity (#26)
add exception filter when user not connected default to needing authentication and apply anonymous to some actions add user in get requests add user relation in link, comment and vote signup and in are ok now!
This commit is contained in:
parent
9c75758921
commit
3cd5133f66
@ -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