Ajout authentification sur le projet MVC

This commit is contained in:
YuukanOO 2021-04-29 11:46:17 +02:00
parent 323a5c0941
commit 9bbde92754
36 changed files with 1555 additions and 19 deletions

View File

@ -8,19 +8,21 @@ namespace Application
{ {
private readonly ILinkRepository _linkRepository; private readonly ILinkRepository _linkRepository;
private readonly ICommentRepository _commentRepository; private readonly ICommentRepository _commentRepository;
private readonly ICurrentUserProvider _userProvider;
private readonly IData _data; private readonly IData _data;
public CommentService(ILinkRepository linkRepository, ICommentRepository commentRepository, IData data) public CommentService(ILinkRepository linkRepository, ICommentRepository commentRepository, ICurrentUserProvider userProvider, IData data)
{ {
_linkRepository = linkRepository; _linkRepository = linkRepository;
_commentRepository = commentRepository; _commentRepository = commentRepository;
_userProvider = userProvider;
_data = data; _data = data;
} }
public Guid PublishComment(PublishCommentCommand cmd) public Guid PublishComment(PublishCommentCommand cmd)
{ {
var link = _linkRepository.GetById(cmd.LinkId); var link = _linkRepository.GetById(cmd.LinkId);
var comment = link.AddComment(cmd.Content); var comment = link.AddComment(_userProvider.GetCurrentUserId(), cmd.Content);
_commentRepository.Add(comment); _commentRepository.Add(comment);

View File

@ -0,0 +1,9 @@
using System;
namespace Application
{
public interface ICurrentUserProvider
{
Guid GetCurrentUserId();
}
}

View File

@ -10,11 +10,13 @@ namespace Application
public class LinkService public class LinkService
{ {
private readonly ILinkRepository _linkRepository; private readonly ILinkRepository _linkRepository;
private readonly ICurrentUserProvider _userProvider;
private readonly IData _data; private readonly IData _data;
public LinkService(ILinkRepository linkRepository, IData data) public LinkService(ILinkRepository linkRepository, ICurrentUserProvider userProvider, IData data)
{ {
_linkRepository = linkRepository; _linkRepository = linkRepository;
_userProvider = userProvider;
_data = data; _data = data;
} }
@ -25,7 +27,7 @@ namespace Application
/// <returns></returns> /// <returns></returns>
public Guid PublishLink(PublishLinkCommand cmd) public Guid PublishLink(PublishLinkCommand cmd)
{ {
var link = new Link(cmd.Url); var link = new Link(_userProvider.GetCurrentUserId(), cmd.Url);
_linkRepository.Add(link); _linkRepository.Add(link);
@ -49,7 +51,7 @@ namespace Application
private IQueryable<LinkDTO> LinksDTO() private IQueryable<LinkDTO> LinksDTO()
{ {
return (from link in _data.Links return (from link in _data.Links
join comment in _data.Comments on link.Id equals comment.LinkId into comments // join comment in _data.Comments on link.Id equals comment.LinkId into comments
orderby link.CreatedAt descending orderby link.CreatedAt descending
select new LinkDTO select new LinkDTO
{ {
@ -58,7 +60,7 @@ namespace Application
CreatedAt = link.CreatedAt, CreatedAt = link.CreatedAt,
UpvotesCount = 2, UpvotesCount = 2,
DownvotesCount = 4, DownvotesCount = 4,
CommentsCount = comments.Count(), CommentsCount = _data.Comments.Count(comment => comment.LinkId == link.Id), //comments.Count(),
}); });
// return _data.Links // return _data.Links

View File

@ -18,7 +18,8 @@ namespace Api
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddHNServicesInMemory(); // services.AddHNServicesInMemory();
services.AddHNServicesEF();
services.AddControllers(options => services.AddControllers(options =>
{ {
options.Filters.Add<CustomExceptionFilter>(); options.Filters.Add<CustomExceptionFilter>();
@ -35,6 +36,7 @@ namespace Api
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
app.UseHNDatabaseMigrations();
app.UseOpenApi(); app.UseOpenApi();
if (env.IsDevelopment()) if (env.IsDevelopment())

View File

@ -6,5 +6,8 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"ConnectionStrings": {
"Default": "Data Source=../Website/hn.db"
},
"AllowedHosts": "*" "AllowedHosts": "*"
} }

View File

@ -0,0 +1,87 @@
using System.Threading.Tasks;
using Infrastructure.Identity;
using Infrastructure.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace Website.Controllers
{
public class AccountController : BaseController
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signinManager;
public AccountController(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 cmd)
{
if (!ModelState.IsValid)
{
return View(cmd);
}
var user = new User { UserName = cmd.Username };
var result = await _userManager.CreateAsync(user, cmd.Password);
if (!result.Succeeded)
{
ModelState.AddModelError(nameof(RegisterViewModel.Username), "could not register");
return View(cmd);
}
Success("Your account was created, you can now login");
return RedirectToAction(nameof(Login));
}
[AllowAnonymous]
public IActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public async Task<IActionResult> Login(LoginViewModel cmd)
{
if (!ModelState.IsValid)
{
return View(cmd);
}
var result = await _signinManager.PasswordSignInAsync(cmd.Username, cmd.Password, true, false);
if (!result.Succeeded)
{
ModelState.AddModelError(nameof(LoginViewModel.Username), "Could not sign you in, please retry");
return View(cmd);
}
Success("You're now logged in");
return Redirect("/");
}
public async Task<IActionResult> Logout()
{
await _signinManager.SignOutAsync();
Success("You're now logged out");
return Redirect("/");
}
}
}

View File

@ -1,5 +1,6 @@
using System; using System;
using Application; using Application;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Website.Controllers namespace Website.Controllers

View File

@ -3,12 +3,14 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Website.Models; using Website.Models;
namespace Website.Controllers namespace Website.Controllers
{ {
[AllowAnonymous]
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly ILogger<HomeController> _logger; private readonly ILogger<HomeController> _logger;

View File

@ -1,5 +1,6 @@
using System; using System;
using Application; using Application;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Website.Models; using Website.Models;
@ -16,6 +17,7 @@ namespace Website
_commentService = commentService; _commentService = commentService;
} }
[AllowAnonymous]
public IActionResult Index() public IActionResult Index()
{ {
// return Forbid(); // return Forbid();
@ -23,6 +25,7 @@ namespace Website
} }
[HttpGet("{controller}/detail/{linkId:guid}")] [HttpGet("{controller}/detail/{linkId:guid}")]
[AllowAnonymous]
// [TypeFilter(typeof(CustomExceptionFilter))] // Permet d'appliquer un filtre ASP.Net // [TypeFilter(typeof(CustomExceptionFilter))] // Permet d'appliquer un filtre ASP.Net
// sur une action uniquement (valable pour toutes les actions d'un controlleur si appliqué sur ce dernier) // sur une action uniquement (valable pour toutes les actions d'un controlleur si appliqué sur ce dernier)
public IActionResult Show(Guid linkId) public IActionResult Show(Guid linkId)

View File

@ -2,8 +2,10 @@ using Application;
using Domain; using Domain;
using Infrastructure; using Infrastructure;
using Infrastructure.Filters; using Infrastructure.Filters;
using Infrastructure.Identity;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -25,15 +27,33 @@ namespace Website
// ServiceCollectionExtensions.AddHNServices(services); // strictement équivalent à la ligne du dessous // ServiceCollectionExtensions.AddHNServices(services); // strictement équivalent à la ligne du dessous
// services.AddHNServicesInMemory(); // services.AddHNServicesInMemory();
services.AddHNServicesEF(); services.AddHNServicesEF();
services
.AddIdentity<User, Role>(options =>
{
// FIXME uniquement pour nos besoins :)
options.Password.RequiredLength = options.Password.RequiredUniqueChars = 0;
options.Password.RequireDigit = options.Password.RequireLowercase = options.Password.RequireUppercase = options.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<HNDbContext>();
services.AddAuthorization(options =>
{
options.AddPolicy("IsAdmin", policy => policy
.RequireUserName("test"));
});
services.AddControllersWithViews(options => services.AddControllersWithViews(options =>
{ {
options.Filters.Add<CustomExceptionFilter>(); options.Filters.Add<CustomExceptionFilter>();
options.Filters.Add(new AuthorizeFilter());
}); });
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
app.UseHNDatabaseMigrations();
// app.Use(async (context, next) => // app.Use(async (context, next) =>
// { // {
// try // try
@ -69,6 +89,7 @@ namespace Website
// Console.WriteLine("<<< Ho"); // Console.WriteLine("<<< Ho");
// }); // });
app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>

View File

@ -0,0 +1,18 @@
@model Infrastructure.Models.LoginViewModel
@{
ViewData["Title"] = "Login";
}
<h1>Login</h1>
<form 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 asp-for="@Model.Password">
<span asp-validation-for="@Model.Password"></span>
<button type="submit">Sign in</button>
</form>

View File

@ -0,0 +1,23 @@
@model Infrastructure.Models.RegisterViewModel
@{
ViewData["Title"] = "Register an account";
}
<h1>Register an account</h1>
<form 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 asp-for="@Model.Password">
<span asp-validation-for="@Model.Password"></span>
<label asp-for="@Model.ConfirmPassword"></label>
<input asp-for="@Model.ConfirmPassword">
<span asp-validation-for="@Model.ConfirmPassword"></span>
<button type="submit">Create your account</button>
</form>

View File

@ -24,6 +24,22 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Links" asp-action="Create">Publish a new link!</a> <a class="nav-link text-dark" asp-area="" asp-controller="Links" asp-action="Create">Publish a new link!</a>
</li> </li>
@if (!User.Identity.IsAuthenticated)
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Register">Create an account</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Login">Sign in</a>
</li>
}
else
{
<li class="nav-item">@User.Identity.Name</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Logout">Sign out</a>
</li>
}
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -3,7 +3,8 @@
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft": "Warning", "Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Information"
} }
} }
} }

View File

@ -6,5 +6,8 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"ConnectionStrings": {
"Default": "Data Source=./hn.db"
},
"AllowedHosts": "*" "AllowedHosts": "*"
} }

BIN
Apps/Website/hn.db Normal file

Binary file not shown.

BIN
Apps/Website/hn.db-shm Normal file

Binary file not shown.

BIN
Apps/Website/hn.db-wal Normal file

Binary file not shown.

View File

@ -8,10 +8,12 @@ namespace Domain
public Guid LinkId { get; } public Guid LinkId { get; }
public string Content { get; } public string Content { get; }
public DateTime CreatedAt { get; } public DateTime CreatedAt { get; }
public Guid CreatedBy { get; }
internal Comment(Guid linkId, string content) internal Comment(Guid linkId, Guid createdBy, string content)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
CreatedBy = createdBy;
LinkId = linkId; LinkId = linkId;
Content = content; Content = content;
CreatedAt = DateTime.UtcNow; CreatedAt = DateTime.UtcNow;

View File

@ -10,12 +10,14 @@ namespace Domain
public Guid Id { get; } public Guid Id { get; }
public string Url { get; } public string Url { get; }
public DateTime CreatedAt { get; } public DateTime CreatedAt { get; }
public Guid CreatedBy { get; }
public Link(string url) public Link(Guid createdBy, string url)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
CreatedAt = DateTime.UtcNow; CreatedAt = DateTime.UtcNow;
Url = url; Url = url;
CreatedBy = createdBy;
} }
/// <summary> /// <summary>
@ -24,9 +26,9 @@ namespace Domain
/// </summary> /// </summary>
/// <param name="content"></param> /// <param name="content"></param>
/// <returns></returns> /// <returns></returns>
public Comment AddComment(string content) public Comment AddComment(Guid createdBy, string content)
{ {
return new Comment(this.Id, content); return new Comment(this.Id, createdBy, content);
} }
} }
} }

View File

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Infrastructure
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseHNDatabaseMigrations(this IApplicationBuilder builder)
{
using var scope = builder.ApplicationServices.CreateScope();
using var context = scope.ServiceProvider.GetRequiredService<HNDbContext>();
context.Database.Migrate();
return builder;
}
}
}

View File

@ -1,4 +1,5 @@
using Domain; using Domain;
using Infrastructure.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -16,6 +17,11 @@ namespace Infrastructure.EntityTypes
.HasForeignKey(o => o.LinkId) .HasForeignKey(o => o.LinkId)
.IsRequired() .IsRequired()
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
builder.HasOne<User>()
.WithMany()
.HasForeignKey(o => o.CreatedBy)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
} }
} }
} }

View File

@ -1,4 +1,5 @@
using Domain; using Domain;
using Infrastructure.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -11,6 +12,11 @@ namespace Infrastructure.EntityTypes
builder.HasKey(o => o.Id); builder.HasKey(o => o.Id);
builder.Property(o => o.Url).HasMaxLength(250).IsRequired(); builder.Property(o => o.Url).HasMaxLength(250).IsRequired();
builder.Property(o => o.CreatedAt).IsRequired(); builder.Property(o => o.CreatedAt).IsRequired();
builder.HasOne<User>()
.WithMany()
.HasForeignKey(o => o.CreatedBy)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
} }
} }
} }

View File

@ -1,12 +1,14 @@
using System;
using System.Linq; using System.Linq;
using Application; using Application;
using Domain; using Domain;
using Infrastructure.EntityTypes; using Infrastructure.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Infrastructure namespace Infrastructure
{ {
public class HNDbContext : DbContext, IData public class HNDbContext : IdentityDbContext<User, Role, Guid>, IData
{ {
public DbSet<Link> Links { get; set; } public DbSet<Link> Links { get; set; }
public DbSet<Comment> Comments { get; set; } public DbSet<Comment> Comments { get; set; }

View File

@ -0,0 +1,26 @@
using System;
using Application;
using Infrastructure.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
namespace Infrastructure
{
public class HttpCurrentUserProvider : ICurrentUserProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<User> _userManager;
public HttpCurrentUserProvider(IHttpContextAccessor httpContextAccessor, UserManager<User> userManager)
{
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
}
public Guid GetCurrentUserId()
{
var userPrincipal = _httpContextAccessor.HttpContext.User;
return Guid.Parse(_userManager.GetUserId(userPrincipal));
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using Microsoft.AspNetCore.Identity;
namespace Infrastructure.Identity
{
public class Role : IdentityRole<Guid>
{
}
}

View File

@ -0,0 +1,10 @@
using System;
using Microsoft.AspNetCore.Identity;
namespace Infrastructure.Identity
{
public class User : IdentityUser<Guid>
{
// On peut ajouter des propriétés ici au besoin
}
}

View File

@ -9,6 +9,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

View File

@ -0,0 +1,316 @@
// <auto-generated />
using System;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Infrastructure.Migrations
{
[DbContext(typeof(HNDbContext))]
[Migration("20210429074555_AddAspNetIdentity")]
partial class AddAspNetIdentity
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.5");
modelBuilder.Entity("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("Domain.Link", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Url")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Links");
});
modelBuilder.Entity("Infrastructure.Identity.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("Infrastructure.Identity.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("Domain.Comment", b =>
{
b.HasOne("Domain.Link", null)
.WithMany()
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,217 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Infrastructure.Migrations
{
public partial class AddAspNetIdentity : 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");
}
}
}

View File

@ -0,0 +1,341 @@
// <auto-generated />
using System;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Infrastructure.Migrations
{
[DbContext(typeof(HNDbContext))]
[Migration("20210429093017_AddCreatedBy")]
partial class AddCreatedBy
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.5");
modelBuilder.Entity("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("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(250)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CreatedBy");
b.ToTable("Links");
});
modelBuilder.Entity("Infrastructure.Identity.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("Infrastructure.Identity.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("Domain.Comment", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Domain.Link", null)
.WithMany()
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Domain.Link", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,81 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Infrastructure.Migrations
{
public partial class AddCreatedBy : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DELETE FROM Comments;");
migrationBuilder.Sql("DELETE FROM Links;");
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: "Comments",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_Links_CreatedBy",
table: "Links",
column: "CreatedBy");
migrationBuilder.CreateIndex(
name: "IX_Comments_CreatedBy",
table: "Comments",
column: "CreatedBy");
migrationBuilder.AddForeignKey(
name: "FK_Comments_AspNetUsers_CreatedBy",
table: "Comments",
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_Comments_AspNetUsers_CreatedBy",
table: "Comments");
migrationBuilder.DropForeignKey(
name: "FK_Links_AspNetUsers_CreatedBy",
table: "Links");
migrationBuilder.DropIndex(
name: "IX_Links_CreatedBy",
table: "Links");
migrationBuilder.DropIndex(
name: "IX_Comments_CreatedBy",
table: "Comments");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "Links");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "Comments");
}
}
}

View File

@ -29,11 +29,16 @@ namespace Infrastructure.Migrations
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b.Property<Guid>("LinkId") b.Property<Guid>("LinkId")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CreatedBy");
b.HasIndex("LinkId"); b.HasIndex("LinkId");
b.ToTable("Comments"); b.ToTable("Comments");
@ -48,6 +53,9 @@ namespace Infrastructure.Migrations
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b.Property<string>("Url") b.Property<string>("Url")
.IsRequired() .IsRequired()
.HasMaxLength(250) .HasMaxLength(250)
@ -55,17 +63,276 @@ namespace Infrastructure.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CreatedBy");
b.ToTable("Links"); b.ToTable("Links");
}); });
modelBuilder.Entity("Infrastructure.Identity.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("Infrastructure.Identity.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("Domain.Comment", b => modelBuilder.Entity("Domain.Comment", b =>
{ {
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Domain.Link", null) b.HasOne("Domain.Link", null)
.WithMany() .WithMany()
.HasForeignKey("LinkId") .HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("Domain.Link", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Infrastructure.Identity.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace Infrastructure.Models
{
public class LoginViewModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
namespace Infrastructure.Models
{
public class RegisterViewModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[Compare(nameof(Password))]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
}

View File

@ -1,3 +1,4 @@
using System;
using Application; using Application;
using Domain; using Domain;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -20,6 +21,8 @@ namespace Infrastructure
{ {
var configuration = provider.GetRequiredService<IConfiguration>(); var configuration = provider.GetRequiredService<IConfiguration>();
// configuration["ConnectionStrings:Default"]
options.UseSqlite(configuration.GetConnectionString("Default")); options.UseSqlite(configuration.GetConnectionString("Default"));
}); });
@ -38,9 +41,10 @@ namespace Infrastructure
/// <returns></returns> /// <returns></returns>
public static IServiceCollection AddHNServicesInMemory(this IServiceCollection services) public static IServiceCollection AddHNServicesInMemory(this IServiceCollection services)
{ {
var link1 = new Domain.Link("http://default.website"); var uid = Guid.NewGuid();
var link2 = new Domain.Link("http://another.website"); var link1 = new Domain.Link(uid, "http://default.website");
var link3 = new Domain.Link("http://a.final.website"); var link2 = new Domain.Link(uid, "http://another.website");
var link3 = new Domain.Link(uid, "http://a.final.website");
services.AddSingleton<ILinkRepository>(new Infrastructure.Repositories.Memory.LinkRepository( services.AddSingleton<ILinkRepository>(new Infrastructure.Repositories.Memory.LinkRepository(
link1, link1,
@ -48,8 +52,8 @@ namespace Infrastructure
link3 link3
)); ));
services.AddSingleton<ICommentRepository>(new Infrastructure.Repositories.Memory.CommentRepository( services.AddSingleton<ICommentRepository>(new Infrastructure.Repositories.Memory.CommentRepository(
link1.AddComment("my first comment"), link1.AddComment(uid, "my first comment"),
link3.AddComment("another comment") link3.AddComment(uid, "another comment")
)); ));
services.AddSingleton<IData>(serviceProvider => services.AddSingleton<IData>(serviceProvider =>
{ {
@ -69,6 +73,7 @@ namespace Infrastructure
/// <returns></returns> /// <returns></returns>
private static IServiceCollection AddCommon(this IServiceCollection services) private static IServiceCollection AddCommon(this IServiceCollection services)
{ {
services.AddScoped<ICurrentUserProvider, HttpCurrentUserProvider>();
services.AddTransient<LinkService>(); services.AddTransient<LinkService>();
services.AddTransient<CommentService>(); services.AddTransient<CommentService>();