From 9bbde9275456c1afbd9a71fb1ef4c60c89ea87cf Mon Sep 17 00:00:00 2001 From: YuukanOO Date: Thu, 29 Apr 2021 11:46:17 +0200 Subject: [PATCH] Ajout authentification sur le projet MVC --- Application/CommentService.cs | 6 +- Application/ICurrentUserProvider.cs | 9 + Application/LinkService.cs | 10 +- Apps/Api/Startup.cs | 4 +- Apps/Api/appsettings.json | 3 + Apps/Website/Controllers/AccountController.cs | 87 +++++ .../Website/Controllers/CommentsController.cs | 1 + Apps/Website/Controllers/HomeController.cs | 2 + Apps/Website/Controllers/LinksController.cs | 3 + Apps/Website/Startup.cs | 21 ++ Apps/Website/Views/Account/Login.cshtml | 18 + Apps/Website/Views/Account/Register.cshtml | 23 ++ Apps/Website/Views/Shared/_Layout.cshtml | 16 + Apps/Website/appsettings.Development.json | 3 +- Apps/Website/appsettings.json | 3 + Apps/Website/hn.db | Bin 0 -> 32768 bytes Apps/Website/hn.db-shm | Bin 0 -> 32768 bytes Apps/Website/hn.db-wal | Bin 0 -> 358472 bytes Domain/Comment.cs | 4 +- Domain/Link.cs | 8 +- .../ApplicationBuilderExtensions.cs | 18 + .../EntityTypes/CommentEntityType.cs | 6 + Infrastructure/EntityTypes/LinkEntityType.cs | 6 + Infrastructure/HNDbContext.cs | 6 +- Infrastructure/HttpCurrentUserProvider.cs | 26 ++ Infrastructure/Identity/Role.cs | 10 + Infrastructure/Identity/User.cs | 10 + Infrastructure/Infrastructure.csproj | 1 + ...210429074555_AddAspNetIdentity.Designer.cs | 316 ++++++++++++++++ .../20210429074555_AddAspNetIdentity.cs | 217 +++++++++++ .../20210429093017_AddCreatedBy.Designer.cs | 341 ++++++++++++++++++ .../Migrations/20210429093017_AddCreatedBy.cs | 81 +++++ .../Migrations/HNDbContextModelSnapshot.cs | 267 ++++++++++++++ Infrastructure/Models/LoginViewModel.cs | 14 + Infrastructure/Models/RegisterViewModel.cs | 19 + Infrastructure/ServiceCollectionExtensions.cs | 15 +- 36 files changed, 1555 insertions(+), 19 deletions(-) create mode 100644 Application/ICurrentUserProvider.cs create mode 100644 Apps/Website/Controllers/AccountController.cs create mode 100644 Apps/Website/Views/Account/Login.cshtml create mode 100644 Apps/Website/Views/Account/Register.cshtml create mode 100644 Apps/Website/hn.db create mode 100644 Apps/Website/hn.db-shm create mode 100644 Apps/Website/hn.db-wal create mode 100644 Infrastructure/ApplicationBuilderExtensions.cs create mode 100644 Infrastructure/HttpCurrentUserProvider.cs create mode 100644 Infrastructure/Identity/Role.cs create mode 100644 Infrastructure/Identity/User.cs create mode 100644 Infrastructure/Migrations/20210429074555_AddAspNetIdentity.Designer.cs create mode 100644 Infrastructure/Migrations/20210429074555_AddAspNetIdentity.cs create mode 100644 Infrastructure/Migrations/20210429093017_AddCreatedBy.Designer.cs create mode 100644 Infrastructure/Migrations/20210429093017_AddCreatedBy.cs create mode 100644 Infrastructure/Models/LoginViewModel.cs create mode 100644 Infrastructure/Models/RegisterViewModel.cs diff --git a/Application/CommentService.cs b/Application/CommentService.cs index 279be44..df6249d 100644 --- a/Application/CommentService.cs +++ b/Application/CommentService.cs @@ -8,19 +8,21 @@ namespace Application { private readonly ILinkRepository _linkRepository; private readonly ICommentRepository _commentRepository; + private readonly ICurrentUserProvider _userProvider; private readonly IData _data; - public CommentService(ILinkRepository linkRepository, ICommentRepository commentRepository, IData data) + public CommentService(ILinkRepository linkRepository, ICommentRepository commentRepository, ICurrentUserProvider userProvider, IData data) { _linkRepository = linkRepository; _commentRepository = commentRepository; + _userProvider = userProvider; _data = data; } public Guid PublishComment(PublishCommentCommand cmd) { var link = _linkRepository.GetById(cmd.LinkId); - var comment = link.AddComment(cmd.Content); + var comment = link.AddComment(_userProvider.GetCurrentUserId(), cmd.Content); _commentRepository.Add(comment); diff --git a/Application/ICurrentUserProvider.cs b/Application/ICurrentUserProvider.cs new file mode 100644 index 0000000..40560a7 --- /dev/null +++ b/Application/ICurrentUserProvider.cs @@ -0,0 +1,9 @@ +using System; + +namespace Application +{ + public interface ICurrentUserProvider + { + Guid GetCurrentUserId(); + } +} \ No newline at end of file diff --git a/Application/LinkService.cs b/Application/LinkService.cs index 015a607..abda42b 100644 --- a/Application/LinkService.cs +++ b/Application/LinkService.cs @@ -10,11 +10,13 @@ namespace Application public class LinkService { private readonly ILinkRepository _linkRepository; + private readonly ICurrentUserProvider _userProvider; private readonly IData _data; - public LinkService(ILinkRepository linkRepository, IData data) + public LinkService(ILinkRepository linkRepository, ICurrentUserProvider userProvider, IData data) { _linkRepository = linkRepository; + _userProvider = userProvider; _data = data; } @@ -25,7 +27,7 @@ namespace Application /// public Guid PublishLink(PublishLinkCommand cmd) { - var link = new Link(cmd.Url); + var link = new Link(_userProvider.GetCurrentUserId(), cmd.Url); _linkRepository.Add(link); @@ -49,7 +51,7 @@ namespace Application private IQueryable LinksDTO() { 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 select new LinkDTO { @@ -58,7 +60,7 @@ namespace Application CreatedAt = link.CreatedAt, UpvotesCount = 2, DownvotesCount = 4, - CommentsCount = comments.Count(), + CommentsCount = _data.Comments.Count(comment => comment.LinkId == link.Id), //comments.Count(), }); // return _data.Links diff --git a/Apps/Api/Startup.cs b/Apps/Api/Startup.cs index 83430b7..cbd403a 100644 --- a/Apps/Api/Startup.cs +++ b/Apps/Api/Startup.cs @@ -18,7 +18,8 @@ namespace Api // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - services.AddHNServicesInMemory(); + // services.AddHNServicesInMemory(); + services.AddHNServicesEF(); services.AddControllers(options => { options.Filters.Add(); @@ -35,6 +36,7 @@ namespace Api // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + app.UseHNDatabaseMigrations(); app.UseOpenApi(); if (env.IsDevelopment()) diff --git a/Apps/Api/appsettings.json b/Apps/Api/appsettings.json index d9d9a9b..55f4a8f 100644 --- a/Apps/Api/appsettings.json +++ b/Apps/Api/appsettings.json @@ -6,5 +6,8 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "ConnectionStrings": { + "Default": "Data Source=../Website/hn.db" + }, "AllowedHosts": "*" } diff --git a/Apps/Website/Controllers/AccountController.cs b/Apps/Website/Controllers/AccountController.cs new file mode 100644 index 0000000..5b02ec5 --- /dev/null +++ b/Apps/Website/Controllers/AccountController.cs @@ -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 _userManager; + private readonly SignInManager _signinManager; + + public AccountController(UserManager userManager, SignInManager signinManager) + { + _userManager = userManager; + _signinManager = signinManager; + } + + [AllowAnonymous] + public IActionResult Register() + { + return View(); + } + + [HttpPost] + [ValidateAntiForgeryToken] + [AllowAnonymous] + public async Task 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 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 Logout() + { + await _signinManager.SignOutAsync(); + Success("You're now logged out"); + return Redirect("/"); + } + } +} \ No newline at end of file diff --git a/Apps/Website/Controllers/CommentsController.cs b/Apps/Website/Controllers/CommentsController.cs index bf6076d..f35d381 100644 --- a/Apps/Website/Controllers/CommentsController.cs +++ b/Apps/Website/Controllers/CommentsController.cs @@ -1,5 +1,6 @@ using System; using Application; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Website.Controllers diff --git a/Apps/Website/Controllers/HomeController.cs b/Apps/Website/Controllers/HomeController.cs index dbcfdca..a9ccc77 100644 --- a/Apps/Website/Controllers/HomeController.cs +++ b/Apps/Website/Controllers/HomeController.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Website.Models; namespace Website.Controllers { + [AllowAnonymous] public class HomeController : Controller { private readonly ILogger _logger; diff --git a/Apps/Website/Controllers/LinksController.cs b/Apps/Website/Controllers/LinksController.cs index e18a9f6..4c18498 100644 --- a/Apps/Website/Controllers/LinksController.cs +++ b/Apps/Website/Controllers/LinksController.cs @@ -1,5 +1,6 @@ using System; using Application; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Website.Models; @@ -16,6 +17,7 @@ namespace Website _commentService = commentService; } + [AllowAnonymous] public IActionResult Index() { // return Forbid(); @@ -23,6 +25,7 @@ namespace Website } [HttpGet("{controller}/detail/{linkId:guid}")] + [AllowAnonymous] // [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) public IActionResult Show(Guid linkId) diff --git a/Apps/Website/Startup.cs b/Apps/Website/Startup.cs index 9c5fc09..568e1f7 100644 --- a/Apps/Website/Startup.cs +++ b/Apps/Website/Startup.cs @@ -2,8 +2,10 @@ using Application; using Domain; using Infrastructure; using Infrastructure.Filters; +using Infrastructure.Identity; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -25,15 +27,33 @@ namespace Website // ServiceCollectionExtensions.AddHNServices(services); // strictement équivalent à la ligne du dessous // services.AddHNServicesInMemory(); services.AddHNServicesEF(); + services + .AddIdentity(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(); + + services.AddAuthorization(options => + { + options.AddPolicy("IsAdmin", policy => policy + .RequireUserName("test")); + }); + services.AddControllersWithViews(options => { options.Filters.Add(); + options.Filters.Add(new AuthorizeFilter()); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + app.UseHNDatabaseMigrations(); + // app.Use(async (context, next) => // { // try @@ -69,6 +89,7 @@ namespace Website // Console.WriteLine("<<< Ho"); // }); + app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => diff --git a/Apps/Website/Views/Account/Login.cshtml b/Apps/Website/Views/Account/Login.cshtml new file mode 100644 index 0000000..c18f609 --- /dev/null +++ b/Apps/Website/Views/Account/Login.cshtml @@ -0,0 +1,18 @@ +@model Infrastructure.Models.LoginViewModel +@{ + ViewData["Title"] = "Login"; +} + +

Login

+ +
+ + + + + + + + + +
\ No newline at end of file diff --git a/Apps/Website/Views/Account/Register.cshtml b/Apps/Website/Views/Account/Register.cshtml new file mode 100644 index 0000000..e3b9e5a --- /dev/null +++ b/Apps/Website/Views/Account/Register.cshtml @@ -0,0 +1,23 @@ +@model Infrastructure.Models.RegisterViewModel +@{ + ViewData["Title"] = "Register an account"; +} + +

Register an account

+ +
+ + + + + + + + + + + + + +
+ diff --git a/Apps/Website/Views/Shared/_Layout.cshtml b/Apps/Website/Views/Shared/_Layout.cshtml index b87ce1b..60d178f 100644 --- a/Apps/Website/Views/Shared/_Layout.cshtml +++ b/Apps/Website/Views/Shared/_Layout.cshtml @@ -24,6 +24,22 @@ + @if (!User.Identity.IsAuthenticated) + { + + + } + else + { + + + } diff --git a/Apps/Website/appsettings.Development.json b/Apps/Website/appsettings.Development.json index 8983e0f..eaa8762 100644 --- a/Apps/Website/appsettings.Development.json +++ b/Apps/Website/appsettings.Development.json @@ -3,7 +3,8 @@ "LogLevel": { "Default": "Information", "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.EntityFrameworkCore": "Information" } } } diff --git a/Apps/Website/appsettings.json b/Apps/Website/appsettings.json index d9d9a9b..3eb4436 100644 --- a/Apps/Website/appsettings.json +++ b/Apps/Website/appsettings.json @@ -6,5 +6,8 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "ConnectionStrings": { + "Default": "Data Source=./hn.db" + }, "AllowedHosts": "*" } diff --git a/Apps/Website/hn.db b/Apps/Website/hn.db new file mode 100644 index 0000000000000000000000000000000000000000..8a35307cb3fbde0846dae2b16aa0afceb1df7d48 GIT binary patch literal 32768 zcmeI&Z*S5-9Ki7wHkiv8KI$F^ZaD3eD2fkbB^6woigVbUupTEykwl(_6{3VHo<^oya^y@S~5paqZ}u zdh}JPhvg?Y?|Vo8$f)AV&!vn<#jHE>x(KbJ^Ni#8wmjf5I_I{1Q0*~0R#|0009K9o51a40&wd{hAp!^>fB*srAb|pWHJ`*Z=?k literal 0 HcmV?d00001 diff --git a/Apps/Website/hn.db-shm b/Apps/Website/hn.db-shm new file mode 100644 index 0000000000000000000000000000000000000000..65e88d0787a126147d016455c5ddbdd33db902ae GIT binary patch literal 32768 zcmeI*M{*NE7{&1?2a;_plPs_SVVjIeCMT0~5P8jp9T(sRT!Kqba0r%csA9`UiE>mSE^svi~eeoNKQpMQM}_-W8t;w*KRIo*D9kLq*!o#oC7XUG|LMx5Bk zsMB=DoK?6xa^!bdrS?$*uUDv}bFEFO?0`0uyn+qL2R)h_fE4ECK^QH}s&+W*N$uk_b#`n|76?*WR`{=o542 zbgs8eu=;`uOl!M#FX)U_oh(j=rm7`yL>H^Iq1<*8=b}^95;&?$x>c<$<+Pio&)(mW z)7(tk8-Zhb)SHD%x9XU-YG>)Xrr|#c99P_`Lj7GJZh@hyC2&G_bgx=l%4s)o{}EL! zfs^X!ezmrg({AGCFA9Nr3dEgv6aw`Wh?^KG1nMae_k>ai)KegC_@xl2r$F3oO(9TE Lfw;ljs5C8!X009sH0T2KI5C8!X009uVb_ra>djtl*gURr*7T4k8UiuzE zi}M)qJ4imTfdB}A00@8p2!H?xfB*=900@8p2sB6FjV*2Ya55^UBFS(h!be44gb(?| z1fLLnF+P|G28FQS9}?0b)ji-sd7!XRuSx^8VqG#l@gFVD&~g#a z3mE(ke*Ulj{`XG)(y6n`^8$N`-$CcztD)nN0R%t*1V8`;KmY_l00ck)1V8`;UK0YP z7UBtTdomb}_(J|rf)^wHG#?UEAwCfml6)i>O9Uc5Q4GYw&3OV`G`Rr`gbw+`0|9@) z9|=cZbH9VfjxF4O;>QP<@w~umqHSmt1V8`;KmY_l00ck)1V8`;KmY{RB0!%PXvRb# zKQC}8eh1(G=v#)q_?G%tU>8_x7?1}7AOHd&00JNY0w4eaAOHd&00OTG0r@?GCIS>* z%zFeJ?FoxV@P}{s;#22de0^m6*bs4d;GU^e=L&Uq(6+_a(qg;Q?IuO3pTgbbhizNQ zFS74KH9@YAWmKi}ouymj*rJ4&5jvA=A8qJ3Md zyX{4;tK}QE=g7ZH+wRzAca8I$tyrFx&eqP9NWUhDM~8~MKPlAavr;`@ld8GOX{lVB z^qW(*FOS{iaP{|dkK9u)oGeLN{#d0X)l9ovlVhTg6Wuu>F(kS@rd*HvKzFB`Y#!QT zX4>P)GHKEyV`AoTR;`)U=N=Q&;+U9CisP)i@?oT_9?}P| zdnD^li9;e`k`%_1LQ1?C2`Hx8B!gv?Kuz^FkU&1nT7vFQ@9kUdu4Db{YlVV9rxbF+ z&C5Qg!^QL5BR89LVyH4(EbEj)+23NN6-u_I7V`dRwesfTv{bdw4wijXT3n|@s#u#Z z6&ACFIf<3jX&Iy1NCoxkVbC%ruu;v7ViRrC%ebz}DRt^pc|%70jxEj21FAH-Ay-mv zTDJAbWBzc^H0H@tp*W`-b7kLYHRejTHsd}rfRN9PWU{2a zVKJLylgL`b>yc~8EzUR63pww2p|sE-Q!kcb+EB#W=rJ7aw$qvTgggN1TwasTEJ)=k z$+X*Jz;DVtP$s9uL2{&b+19msQ0Y0YbV!-Mwf$~Gt?KlyWnapm>W^M`P-$VSE5nr? zR86c6y%>#u1C{FZkwWcMgNDYXsfB8> zzBpbl%*{8*CoPZyRdTvm78yNNDNEUfxs%%UM|aK8Z#zhNm@>sq?E zL)Ow|PN${xBvG|g{&iC$EtPYOGlSuh+gMB0qjWO@(*XZ4hnX}}J0InU0V1u*Sw60Va-bu$%JOL-X?=PXt%qPy;eHE(z2iZ=2+U->TtPS z+`0WSbGZfiqs>U0HQnqCtd?)UIbU6wIh({t`sHo2yKZ+`^-FGS(l39tFHLX`S2W6< z8*kbH)!!nw(t<<^h#mJ(f2587)dU|21ew^G2 z5n)ZrMkr)j?5=yGRumexGwE-b+^XDS@8}}mE%bM07g+rCPd@iYPv7&$ihqHpZO#{+ zPb+2d2?8Jh0w4eaAOHd&00JNY0w4eaAn=+IIMC8M?4scce4#+x7Y&8O;Yne7TKRiM zW||nSh?zJ%;2Q|{bFJg7WXvD(1%rV}#d1XrCqkK-@Z`dzKeCO0*#&<3(cgUgtrPct zOL>prV>aiPoF9A5`izD_00ck)1V8`;KmY_l00ck)1V8`;RuS0OI?SzSA!vDB>-Z+M z&|1a;Qu!v@0J95x^U3eNJHb6SN}m@XFArb?0T2KI5C8!X009sH0T2KI5C8!XxV{O{ zM*~*u0{@u$V)%y>2Y1McunSz@BahyJ00@8p2!H?xfB*=900@8p2!MdiwwXd;&kM}{ zU3T+{-}+|}&kH~`KmY_l00ck)1V8`;KmY_l00cnbh9E$F53bk+z8?JJ=Vt!myC1;w z0yo6iqmv*20w4eaAOHd&00JNY0w4eaARs>)z@8WQ^0t@u{#5vnDxMdBVt@b$fB*=9 z00@8p2!H?xfB*=9zzsp5hxU@$1)l%lU(XiCUp@o7zzs3>=p+b$00@8p2!H?xfB*=9 z00@8p2skMMW*7M0TmSq&_uSUm1-k$g0|Y<-1V8`;KmY_l00ck)1V8`;ZU_Q$)B$D} zc;C+b$uDk8)L<95A;un^1OX5L0T2KI5C8!X009sH0T2Lznh0T2KI5C8!X009sH0T2KI5ZF!; zFuTC-Kl-+}|N5^M_TYH|C-u?Yv;?vcGKWdBORi9$U|oU5|A?-{sxBb@LB9N}XS^zifY^eOs%$?M1GutzO)9&QO*nY-A%S3 zm1~oJL#rfZyYoW(S6%)6+#~nY3nxpGmOoZ0Nj1~%*5sHdmJFvQ{s?Fm?VYqq>vIXMgoedHpyTaB~Vkn4J42cvzDN{(|h|?yX#p0`kJR8 z&?$wSaI^D5>t|g&&pmRpNhgLXv&FJbDU|&!R$8HCYic3yk5(&hE>25T3+-UpN2SGe zN~DUl`BGsqTbPqrNu8E4s*O}ouO0?1V*(r1%qTX|Hoc7Ns+>}%PL(%g#P8VB++3qd zqZ@K1_rvxst7oIX%vF6bRCl`beR6 zszF2J($qq=SYI5k7v|<0QTBGf$4yS@@YzDQDBY1 zr&upp0+09Ho$U@+Z!dSAXf@FyR)l@qjm%l{MF7_hX+T?*qVYnVAgzj)QYM8Aj^XpTjcZ=U#IWY2iDW{vT5prV9kknB$zCg+UuoIT zese7CYjwC>F7DiZnYrA8{LyBl&6;j@23E^A;GD0n%$!YPB>nQX*Swu^ogk&d-}W1c11f+cJ_6g>ku5Dbd1=avmb7Mwta?VV*>#Y0D(97!_LuqA+qdSIPv$bU#E9>#zcdNs-m$bM^ zZc)BBFgMq$HmA0um070|bS8jo<#x$vvMIQakOq)_~Gd5~@m{|t7 zO4?baR*!dyyT#!Wcy4L$>h@Lp3#FkKKuO-Uh6IKK%_1n7R0gGDDuc^X2GyEjmO)9r zbqyH|2byJ2GW9Z)b||W~OU6Ly(6zg6tYvaL)dr2KWhkw0NGAf4J*Ee! zg416abuIZ8iymtwR*b}S5wB>CmZ=~4i?H}Nw#F~-zF9HYRCM=YbfC!J2*?qd#wz>U zRMA)2+c1a^~N z>}Ga>ublbnz^4`_1lR?xi?Kx~KmY_l00ck)1V8`;KmY_l00cl_Jp!9)0cIDtW!t-l zw{?E`ecdFDa~`mf|JXnP1V8`;KmY_l00ck)1V8`;K;VWau$1R+%5UFpvvn+mhx4|M z4%?=VR5UImLurv0M8A&@#lwC+7D&bUa3Ul`6oT>()XIx?I(63*n`m>&xt%N!Xw;+Ll4u~0NZ zL^~PaLosQZkHv#NJ}d=7eqT7?KN&hn2DXb1F0%_Peen|y{maXr7@^M#aL$)(=vY32LA%z|IRNx{NC`_A5!cBKeai3 zdX04);(`DOfB*=900@8p2!H?xfB*=900=ZiptaSui4-*W7x=%A98dkNch7qjyTApT z^FmWqp%4gw00@8p2!H?xfB*=900@8p2!OyfM8MIyeG`4ZfrxDIFHlb1{rp$ozv=bV zzd%dR5b-ZSKCpoR2!H?xfB*=900@8p2!H?xfIt%jmQJ+Xl;642@D6?;OUz`h^m^d1X^yjB*r{bxzGs%2C5%JUa@Q(^7 zPNeRBV@*cql zoyW)*HV^;-5C8!X009sH0T2KI5C8!XxEcs7?P+b#FC~-yv=BX4X6ge|mAOHw%rDdirJ2F0N>v)1 zt4vF!VtID3@<3Ud=B0AIST9PozNt#7Bu&+em2!=*%rAD77Q(BR_1r zh5RBvbD$>3^|4Hg?{?e3;iqUtobwf0#N~XY=gF?ex}WdzZr-~2haIKPuh?If>OJ{3mN~B+t#1d1H_a}wgd{(OGYf?2=IW3iI zlYVo`_T{mg9IpO;?vZ=yg_9*o%O9(hq?&1WYjR8!a-usYB!)z{$CT@FAL#CMlg&e0 z%uIXSIdLNA&W@0u{Ls)rHIr6sm6;sLj_1aNOg88Cj2_j=FH7TbkB()Ag|QRvqv8qo z0oKexw@0nhtG1!9CcUZ}wOYB#NhVEtWK7H)&Z;%D`rKn;S{xIzNpYNYS3Zn%)kFH= zb&q7-DRD?7Op?NQQb>sxBLT%!n`E$z5~!)(1`^1JSxeB}>Aiic-F2*geXURs=#)ZE zxOv&ygPJq%jL1U9OfQEZ}ZdKuSMIi*gWDsRY$-?62+c|es$H{?pn zP0O|(dCVUUn#Md?Dir5*W3KEwt;Sr**2bKk>Ev`44~t_fGlAQ30NBy`0TA-JkxZ7f zH!NmzY!X>(cs+70Ib!2(pciu9@j_{#L8e|T!?dA@wb5fZ+HI#Z@dUCX|dLDe6Ou|A7xh6|yPf5q04PT+S~(`bYZGqsfuN~a$2Kb zLzSu1m4&)kURe_98ePd;rxIa`%mTGE83SoLSy?F8SI?_N-NKvgu1w$hSAN4%u-3J7 zZ-=a<%bZS2=}Dq$sr>7vMp`Q87-t5Q&1f~NP%BLxrMS(R2pJLgxJ{DOf zwnCP7Itvbm%iqf_aq@CHGclR0%*~NMt=1-oisjQ8G7idahe{@sO^Fk3&+396x={46 z;slpRslekscW1l9)!WORCt6Lkh!tVqb|Z6^d=bF4LmJRlrD(iRCrIn0v+PVWE#s3_ zsZf`u1&e&swUkLAgJbwSZsVGlF)^%pX(E}>tk&CPa0l&nSF+bi=T}#``&u0? zmy0{MUuG`1Ab+$OX|txAoq^Tz4LIkkD>G-47)igpZFbk~E~|dYjZOOHulA)0&f$ti zxpO0Ok0vL@^l)*uT9E(lf23F=v(#e4#1>H9$ia)6)x6_2cAL zh&-fVQZ_;%(_(ks8?~a)u$@VN!{k=w7JEk*`8K>q@QaUq_QX#L1<0$acQ z4~4glzTtKBJpyVMAny@8gZBt13~V3(0w4eaAOHd&00JNY0w4eaAh3Z19&GA80wTb% zrrskU1rId&9)X?qioHj0_h*M6iwoN~vF8Pxd!2h}J~j{l0T2KI5C8!X009sH0T2KI z5V%nZd@a8{8H`4JA%7^rixGdC4~eM|pNI-cJ`#*20ui4m24dl6?!%8ri+hc300W^z z{_sG+AMi)Q5rX(kepfOO3dQ_Me~=GFVo~xD6?j1mi+n_k`-D(j^aV&-6CMbUNTpK6 zZEDaTJroWPghGLE)aNG+I_S7EyTA*l|KnYr_k8`+E6)qyX#t7{8wh{^2!H?xfB*=9 z00@8p2!H?xTqOjKHDjV^A;KPL#=1btb$`6FMdPMkUqy8xwv4Fo^{1V8`; zKmY_l00ck)1V8`;t~LV4nt4z_whJ^oHqb+i6?R z3(gOH`?BH@I4`t+74Znno>8egTHGV@Howex1kMYspG7=^m9Q6=6OUlIQ*k%^@a*;CZkV`LRy+|W%mE`vWRA3u zAIiD+`_zr6-=+_ix4-e3!kh+ggyZ6+vf_t$`3+aIA7T>l;tCN)JOUCNr{PRYCviiN z33*n(;=yT%J7vTpaC;Ds0PzTnA*R$tR0H?q7U2f2+js;$HZF;H1WJ4{>RW%+s#|sP zZ?)dOlz0Tr3$`Z_k3bGmaHGW|ke?HvCIP)&;PZnszc})NAOC50o7=YCcGTwla8G~N z*{*2k$RuJ5XhpNxF>Y0X8bm5uDZ4sYk(T9s(`_Uql1mp7Njc9}O31r=R<&X( zr8FTY($GFDM|-^UyU0A%$1U~AePQ9qGBmuYX0)p9RvXA?Gsp5G2{0(fT{4tbn$R6X z8`73-tgOd-->nYUUee+wxkdTjz}#G~u|HawbsCWidb|(qbhz&5=azcq7D#j`O)C9; zo+6eprJ6ChaD9u{NO6cCE70`#|KrifZi1ot!qePy!gu7jH5 z662Rq9Fm}nZ{zEQnTYOG-;lVkmuXo?^k*gFsBt~WP9H-YI_*4LBO2X$Nf{e|jFN2A}y^8(lMkV1A4009sH z0T2KI5C8!X009sH0T5`KKp!p1o)`G^C;p?pE#5PX=LMSPhk_sg0w4eaAOHd&00JNY z0w4eaAaE@c*hhrl$Ls>%Tl~R%^ufVNJTGu94=H2^0T2KI5C8!X009sH0T2KI5CDOu z32?L|vkQFVt@qvbgCF1d-SJ~X#k%C4sZ{3*b$8IV#n#edyVLC^Mcc^_wI$Hs9pvXW z^3z6s*e2J*gPJlsdm+f7$*-`?gkh z+lyRR%QtM#k$;!AU4F!*v6~#O{(kO}drT3N_sa1WL9x70@%C#I6<(i(~Gr8u`o+Q{Hfzv!nIrxscC|WU{2aVKJLy@zm5f zeGOxBdgNMii}Ml-#+Dx%Vh753O@v%aAJv7uQpD0FTq6N_mTg_D2bIovN{6%%Vak4Y zqe0b*U&^5Bk6w3B*<73xCvq#wVi>q9HK>|c8+tJyv3AdwIvuXQKJL*yrt_+%ol>>U zjlfeCr=i=_5QM8Pnbv0!IZDTx0i^Zm!w~9D3N04o8ikbLpz0ad@L;PFa(c2-o+(!6 zqz3Z=lW??9t36PuP9G`MPBl1n$EB%-YO%gJUN6keH^?U~kOEbyJY`vA^i-uRWf$g7 zO4SAx=yIEoHupd!U6`s@s$#itvb0vehALC1D+_h8O!}_qwhrG)<~o%KQ&Uo{mM#=Y zQ_0FgxxRW{CF&O5Y%MNCzb294wX!U zD8)2pFgrk&xO^?%asnqsd7zJzSiv7V5=Hxpt&jBeT?E!^9S2j~kZJlx?NXbuUI1 z6*WLZf>TZ}Ox2H*iyaYmHHA!z-F0u&ibBJ7CjAYQTa{bv9bM#GzNcq)f%o(lKYZZ* z--@vJ2zs8O|1Rx@97llw2!H?xfB*=900@8p2!H?xfWQ?ez#YpkC6oTN5K5&YVLllQ z#QBgQhvTB%iL>H|}ixk0JSFVqI5 znZc<_RT`YDOiQI=d3Lb!Kv|mRiFK=3FG{t(sYX91lkVu^{R2GvQ=ZOhuC6NQ94yz6c-ki3vU-`eJ-A5ey1pzdt0T zLsUK@-a>hxuu!i`12ysodVR&wL;lzyUtk~_35R?>KdJcmU@{ttB~r;$nomUn0v}4H zeY_A(r}${f7Z#$?xR3}0)rw~;mD!R+`)jH-dMFef@WlerP$WcZrGK_xd0yb3KKHK= z{>8b(2z!sf`H1rwC+q?g5jGG20T2KI5C8!X009sH0T2KI5ZE{Z4>n`!pnv8+){M=e zg%mu{j17U5v(rwo=LLQ*JH43x_rROj^8(Jj&b>4r8wh{^2!H?xfB*=900@8p2!H?x z+^7V;mfxNXMkBtEKa}9bh(FDT#8ik+M1>?D3C0qEh))y)v2Zi@;YXy!y~aP^2SSJZ z;emiZ;E#kO1o4^tu4Et-iusfNARmgvqU0kg@PZf?`G^?z38A>?3y`!Xo*XzLl}Z)2 zsX>4AP&hmg3I)PZ`6&eIBVffY@C$$c`44Os!rND#7r@g3H>%pB-yi@2AOHd&00JNY z0w4eaAOHeaC4pnjm?-4u1)8xgkS=!6ZnEbEy567v&40b)T?N<$uFAoOP#^#TAOHd& z00JNY0w4eaAOHe4Jb`1)JScE6?-A^vNSR&W{yLX9b<5tjcXxSh4*Scto)?@S(nSb( znM4Ut{=Mq40xo&rofqu8$9XGnjhf5ZT;;S>t}$<`)a$U4vfX*1{i}#aVD^kk-OWFTHlmx&7G;dPyCO*xj3!)gI0aiulS@^vyV!PCf}sy5~*Ts zzEoJW@J~#|UF9{k!QdF&;WL4CZd0l2VA|^yu@AaE>~|{TIw3H+9^-zAx*L9Y_IhzQ zOx!A0r9xerPM8OXcnVGn`JtS9zfawG`fd7PdHWj-1_=VdoCeD-i)&ZbaWR?pe?a{Z zFTdex_Crh*>V6*oAlmN5vDm7!4a8kHC4s_9WsF z$UzEjw0H#aa{|;PptlQD_x=3W&Pv0DZtf}D&9*6<^TR#;U1z(ZohLi{I?i?Y+R21q-k(HLD$NCe$8G1WZDmYtRuK5jDIRjN*Xap=e=iCCLc$bvuL@JNqS>q#x2iZSQqka^i;JB@ z+q}>3(uG7)z^pVR@9r_RGNIl*uar{aA*~?N(!KM$9IpL++)|(17Z#2zQ=XR2>Q2Yq zY6JOf=2%`N0R~gzgxg~%tu&!KhK_}{Y-43T-urHKxb~73H_0u^_Xg(XdX4?j%B<6f zT+rivXs5$PUdM6uSJ_qVB{=Y+(N$PCnUT$SPklNw4(RSRRt ztCj16!M@qJjQ+06WU*}`xaZ1!pI$cIbx>1WV*HYonVDEUBtaS9#@7oo5#6bNHCon} z5&ij!8rarT3VLGJHd-exKNc|JKVNI{pO+E7*>DTGVp*p%yn4CS=H?BVibuQc^bgl3 zD=n5;=>7Dzl=$+X*JxK5ff50uHOLFA)FdXI}io6Mxpv z-XoxS*gyaTKmY_l00ck)1V8`;KmY_l00gdE0&dc?eatTK-c$EJ^O+C%2G!ouSOxUC z0_vNP{!VQOG_GMA`N0MPAOHd&00JNY0w4eaAOHd&00JOz?GxZ=7nogONBfEY`K0uT z-yT0UL>@+P&s3^&g}OUv+hS{JvEAu*lcLlvu#f!E->H3o+6we`0=Yhtw$|2e8#w$F zt%!5JLd&_Fuk<|G^;q}wU0$6xgIC>$L1X^{c;fBKzEXNsJn?p!{sortyxX<*yxZkJ zVLqja9!D~S3YX-VP%F8>e)3t-GO33Nt1@M_- zbxtDg8_2un;$d;joi)9wFj}b99;j5Oj}&UBm~$DO0OQisLbX_59IqGV<{RX%@rpU? z=;*0RS;{WVoz(o>=o--FHX&{9fl9hCRj*XVa^YlYt$qzv;9uaH^e<3wI9wa-U*O!G z?edGQ=ZRJmEn@E_vTwWL$!HHt*4`Xi_2Q`EDn?%H(GJnQ(8JCL`o`g^8dxSd2kKI} z&dxN`$*R7iX!YK*)r+gj>yfP8EArmxp#9?B*>o)JYn5N}KDS?HE{i08v>9p3X%~T7 zE#H8%q2!H?xfB*=900@8p z2!H?xfB*=9zy=ZMYi&)s0=|IX7Yf9E@u1HiofM|0S3F{c2YdtJ11+t?TA^qt91hb$ zibI3UG%;EcGqGH&z-v1wXdMJV00ck)1V8`;KmY_l00ck) z1YRWqG|s?^UEn8w@XoGi?C{%Q7kHKEqZtqY0T2KI5C8!X009sH0T2KI5O{3~xM=h2 zJ%Zu+zl{9s^MCab>UVI5?M|EX!#(|7XS<@ECp-H(&UFZmPdY~I&)E;RKifXj_M_G< zEnnk)gR5|@w%;O!b=#Zv5jUkSZiy?Fr=_!*iAmWJrRwKkI*-kA*~lIg*oYL(8`LJh}8{gSzhnnX8mgJJC|_FoEh zC!g@lH+hCmV7l(^R);#D%^b^%#BsPhcNt16r@HPK+N|c2oR#%>@4MCE+Dls8B)2I0 zBsVwLYn;HeGV3&=I6n72wA10bqn}&qm0KV)tR~f1r6koR>1RfDQ$q!lQ*SdiYI&Gh z2KivxS*2EwcZs{j;SzXmY47Uxhbptha&3|}suw^>-nE7Vh6BwaD4A3SrD7_B%Tk79 zsZg9-ErXJL>l!i`4m8W4Wa?!o?NC%}myChZp>FSWV=a^0sWxa-EkkL2Q}QuJ)smg* zlOAtx*kgKtDmeX>QP+}hvFNc@Le&?u7+Q~&iap*tw%J|dJZFdPW%=_C^(Q`s#NYq~ll;Q+acc+_dOf4*?LaLLa z)ykWT)0#Ve({!m1SYXOJUMMX{>?){v@z>8`#QnKhbdOs%c=V z=4y5AFby|fM%gK1m?*V+YE-!_uc4P4(P!)?hpWGzd*mL|_)-n3X+p@mTdhV{&TVpV zRn=@b@|HuSHefYEYMtKohD5GL9TDYs^+?mghSk?#MC8M)N91B8pyR$FI&t|ie-P*C zT8s0vj4(}x02gWf46j~pwdrg_PP@@=JDo~T$TO*Wv8_pG7Nqi&WZLa9%%rBw17)%* zIY^H5l3RH<`Ps+p0$YP``0>Xd|Mr4|z4}5C8!X z009sH0T2KI5C8!X009uVMhO_+BiQmAh0nb4SKcMi_Xs%WOE&T!8wh{^2!H?xfB*=9 z00@8p2!H?xfWS3IV1H|VQy}CEMS^L8PsfEcABv}=d?J{N@+l!Mgu;Fy5EFu=TYa=^ z?0JD*@lU-qb^63am6^I;qLj|~Js00ck)1V8`;KmY_l00ck)1VCUT2`qB$`DA|3 zAB-h^{%D$yh7(bq+|nocSR^3uu~;IKjHLXjfImt@5AwbcABeks@k62Dp)Vk z;dnD`U4DS&vedfeF`RM0h4BAJX>-TAU8@9s&8l1_B@e0w4eaAOHd&00JNY0w4ea*EfN; zw$LZ}!>M38kPOG7d@LS}@Sy;CoIjR|2Y68+@9C!!@pM3luX>U{92p3N;{I4L-pn1l z`Xv8Cd4NRisY(Mi62RvwdXL~^U+}yC^7zgjcwXT8R(SLd1V8`;KmY_l00ck)1V8`; zK;W7rAU`kAgz-XtUZBbM2;`W9%)h{|yz}$94?TV6J@7AZP3i}P1_2NN0T2KI5C8!X z009sH0T2KInE-u{pqa-PNa1#R0J96!{qOvjZ~o2OehYR186!SG00ck)1V8`;KmY_l z00ck)1VG@LBybUa2lvtrGP}U<{9Vlc=JU~DIuT0?DL$S^rudLgNbo{17~Yg#Dpl+}D&VgC^f2@DNZdaSFfl!q0y5j~{h%cwXSDQy&Nf0w4eaAOHd& Y00JNY0w4eaAOHeQ6QIuvG-H1F|JnW*lmGw# literal 0 HcmV?d00001 diff --git a/Domain/Comment.cs b/Domain/Comment.cs index 518a113..2ade782 100644 --- a/Domain/Comment.cs +++ b/Domain/Comment.cs @@ -8,10 +8,12 @@ namespace Domain public Guid LinkId { get; } public string Content { 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(); + CreatedBy = createdBy; LinkId = linkId; Content = content; CreatedAt = DateTime.UtcNow; diff --git a/Domain/Link.cs b/Domain/Link.cs index dd5cb04..d8c2a9f 100644 --- a/Domain/Link.cs +++ b/Domain/Link.cs @@ -10,12 +10,14 @@ namespace Domain public Guid Id { get; } public string Url { get; } public DateTime CreatedAt { get; } + public Guid CreatedBy { get; } - public Link(string url) + public Link(Guid createdBy, string url) { Id = Guid.NewGuid(); CreatedAt = DateTime.UtcNow; Url = url; + CreatedBy = createdBy; } /// @@ -24,9 +26,9 @@ namespace Domain /// /// /// - 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); } } } diff --git a/Infrastructure/ApplicationBuilderExtensions.cs b/Infrastructure/ApplicationBuilderExtensions.cs new file mode 100644 index 0000000..b9ec7ec --- /dev/null +++ b/Infrastructure/ApplicationBuilderExtensions.cs @@ -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(); + context.Database.Migrate(); + + return builder; + } + } +} \ No newline at end of file diff --git a/Infrastructure/EntityTypes/CommentEntityType.cs b/Infrastructure/EntityTypes/CommentEntityType.cs index d28cc24..fb18da7 100644 --- a/Infrastructure/EntityTypes/CommentEntityType.cs +++ b/Infrastructure/EntityTypes/CommentEntityType.cs @@ -1,4 +1,5 @@ using Domain; +using Infrastructure.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -16,6 +17,11 @@ namespace Infrastructure.EntityTypes .HasForeignKey(o => o.LinkId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); + builder.HasOne() + .WithMany() + .HasForeignKey(o => o.CreatedBy) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); } } } \ No newline at end of file diff --git a/Infrastructure/EntityTypes/LinkEntityType.cs b/Infrastructure/EntityTypes/LinkEntityType.cs index 0798d76..82b20d5 100644 --- a/Infrastructure/EntityTypes/LinkEntityType.cs +++ b/Infrastructure/EntityTypes/LinkEntityType.cs @@ -1,4 +1,5 @@ using Domain; +using Infrastructure.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -11,6 +12,11 @@ namespace Infrastructure.EntityTypes builder.HasKey(o => o.Id); builder.Property(o => o.Url).HasMaxLength(250).IsRequired(); builder.Property(o => o.CreatedAt).IsRequired(); + builder.HasOne() + .WithMany() + .HasForeignKey(o => o.CreatedBy) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); } } } \ No newline at end of file diff --git a/Infrastructure/HNDbContext.cs b/Infrastructure/HNDbContext.cs index 6997ea6..1e80adb 100644 --- a/Infrastructure/HNDbContext.cs +++ b/Infrastructure/HNDbContext.cs @@ -1,12 +1,14 @@ +using System; using System.Linq; using Application; using Domain; -using Infrastructure.EntityTypes; +using Infrastructure.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace Infrastructure { - public class HNDbContext : DbContext, IData + public class HNDbContext : IdentityDbContext, IData { public DbSet Links { get; set; } public DbSet Comments { get; set; } diff --git a/Infrastructure/HttpCurrentUserProvider.cs b/Infrastructure/HttpCurrentUserProvider.cs new file mode 100644 index 0000000..62e0e99 --- /dev/null +++ b/Infrastructure/HttpCurrentUserProvider.cs @@ -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 _userManager; + + public HttpCurrentUserProvider(IHttpContextAccessor httpContextAccessor, UserManager userManager) + { + _httpContextAccessor = httpContextAccessor; + _userManager = userManager; + } + + public Guid GetCurrentUserId() + { + var userPrincipal = _httpContextAccessor.HttpContext.User; + return Guid.Parse(_userManager.GetUserId(userPrincipal)); + } + } +} \ No newline at end of file diff --git a/Infrastructure/Identity/Role.cs b/Infrastructure/Identity/Role.cs new file mode 100644 index 0000000..3553019 --- /dev/null +++ b/Infrastructure/Identity/Role.cs @@ -0,0 +1,10 @@ +using System; +using Microsoft.AspNetCore.Identity; + +namespace Infrastructure.Identity +{ + public class Role : IdentityRole + { + + } +} \ No newline at end of file diff --git a/Infrastructure/Identity/User.cs b/Infrastructure/Identity/User.cs new file mode 100644 index 0000000..d696a93 --- /dev/null +++ b/Infrastructure/Identity/User.cs @@ -0,0 +1,10 @@ +using System; +using Microsoft.AspNetCore.Identity; + +namespace Infrastructure.Identity +{ + public class User : IdentityUser + { + // On peut ajouter des propriétés ici au besoin + } +} \ No newline at end of file diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj index 496090f..9e0f06e 100644 --- a/Infrastructure/Infrastructure.csproj +++ b/Infrastructure/Infrastructure.csproj @@ -9,6 +9,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.Designer.cs b/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.Designer.cs new file mode 100644 index 0000000..4e34500 --- /dev/null +++ b/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.Designer.cs @@ -0,0 +1,316 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("LinkId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LinkId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("Domain.Link", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Links"); + }); + + modelBuilder.Entity("Infrastructure.Identity.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("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", b => + { + b.HasOne("Infrastructure.Identity.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.cs b/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.cs new file mode 100644 index 0000000..f34f568 --- /dev/null +++ b/Infrastructure/Migrations/20210429074555_AddAspNetIdentity.cs @@ -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(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "INTEGER", nullable: false), + PasswordHash = table.Column(type: "TEXT", nullable: true), + SecurityStamp = table.Column(type: "TEXT", nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + LockoutEnd = table.Column(type: "TEXT", nullable: true), + LockoutEnabled = table.Column(type: "INTEGER", nullable: false), + AccessFailedCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RoleId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(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(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(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(type: "TEXT", nullable: false), + ProviderKey = table.Column(type: "TEXT", nullable: false), + ProviderDisplayName = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(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(type: "TEXT", nullable: false), + RoleId = table.Column(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(type: "TEXT", nullable: false), + LoginProvider = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Value = table.Column(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"); + } + } +} diff --git a/Infrastructure/Migrations/20210429093017_AddCreatedBy.Designer.cs b/Infrastructure/Migrations/20210429093017_AddCreatedBy.Designer.cs new file mode 100644 index 0000000..c0bd0fb --- /dev/null +++ b/Infrastructure/Migrations/20210429093017_AddCreatedBy.Designer.cs @@ -0,0 +1,341 @@ +// +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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("LinkId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.HasIndex("LinkId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("Domain.Link", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.ToTable("Links"); + }); + + modelBuilder.Entity("Infrastructure.Identity.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("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", b => + { + b.HasOne("Infrastructure.Identity.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Infrastructure/Migrations/20210429093017_AddCreatedBy.cs b/Infrastructure/Migrations/20210429093017_AddCreatedBy.cs new file mode 100644 index 0000000..a011471 --- /dev/null +++ b/Infrastructure/Migrations/20210429093017_AddCreatedBy.cs @@ -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( + name: "CreatedBy", + table: "Links", + type: "TEXT", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.AddColumn( + 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"); + } + } +} diff --git a/Infrastructure/Migrations/HNDbContextModelSnapshot.cs b/Infrastructure/Migrations/HNDbContextModelSnapshot.cs index baf7ca5..0cfe611 100644 --- a/Infrastructure/Migrations/HNDbContextModelSnapshot.cs +++ b/Infrastructure/Migrations/HNDbContextModelSnapshot.cs @@ -29,11 +29,16 @@ namespace Infrastructure.Migrations b.Property("CreatedAt") .HasColumnType("TEXT"); + b.Property("CreatedBy") + .HasColumnType("TEXT"); + b.Property("LinkId") .HasColumnType("TEXT"); b.HasKey("Id"); + b.HasIndex("CreatedBy"); + b.HasIndex("LinkId"); b.ToTable("Comments"); @@ -48,6 +53,9 @@ namespace Infrastructure.Migrations b.Property("CreatedAt") .HasColumnType("TEXT"); + b.Property("CreatedBy") + .HasColumnType("TEXT"); + b.Property("Url") .IsRequired() .HasMaxLength(250) @@ -55,17 +63,276 @@ namespace Infrastructure.Migrations b.HasKey("Id"); + b.HasIndex("CreatedBy"); + b.ToTable("Links"); }); + modelBuilder.Entity("Infrastructure.Identity.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("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", b => + { + b.HasOne("Infrastructure.Identity.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", b => + { + b.HasOne("Infrastructure.Identity.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); #pragma warning restore 612, 618 } } diff --git a/Infrastructure/Models/LoginViewModel.cs b/Infrastructure/Models/LoginViewModel.cs new file mode 100644 index 0000000..effa663 --- /dev/null +++ b/Infrastructure/Models/LoginViewModel.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Infrastructure/Models/RegisterViewModel.cs b/Infrastructure/Models/RegisterViewModel.cs new file mode 100644 index 0000000..ee506cd --- /dev/null +++ b/Infrastructure/Models/RegisterViewModel.cs @@ -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; } + } +} \ No newline at end of file diff --git a/Infrastructure/ServiceCollectionExtensions.cs b/Infrastructure/ServiceCollectionExtensions.cs index 50d548d..fdb9a0d 100644 --- a/Infrastructure/ServiceCollectionExtensions.cs +++ b/Infrastructure/ServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using System; using Application; using Domain; using Microsoft.EntityFrameworkCore; @@ -20,6 +21,8 @@ namespace Infrastructure { var configuration = provider.GetRequiredService(); + // configuration["ConnectionStrings:Default"] + options.UseSqlite(configuration.GetConnectionString("Default")); }); @@ -38,9 +41,10 @@ namespace Infrastructure /// public static IServiceCollection AddHNServicesInMemory(this IServiceCollection services) { - var link1 = new Domain.Link("http://default.website"); - var link2 = new Domain.Link("http://another.website"); - var link3 = new Domain.Link("http://a.final.website"); + var uid = Guid.NewGuid(); + var link1 = new Domain.Link(uid, "http://default.website"); + var link2 = new Domain.Link(uid, "http://another.website"); + var link3 = new Domain.Link(uid, "http://a.final.website"); services.AddSingleton(new Infrastructure.Repositories.Memory.LinkRepository( link1, @@ -48,8 +52,8 @@ namespace Infrastructure link3 )); services.AddSingleton(new Infrastructure.Repositories.Memory.CommentRepository( - link1.AddComment("my first comment"), - link3.AddComment("another comment") + link1.AddComment(uid, "my first comment"), + link3.AddComment(uid, "another comment") )); services.AddSingleton(serviceProvider => { @@ -69,6 +73,7 @@ namespace Infrastructure /// private static IServiceCollection AddCommon(this IServiceCollection services) { + services.AddScoped(); services.AddTransient(); services.AddTransient();