ajout auteur des liens / commentaires
This commit is contained in:
parent
9399b6d92c
commit
5b1f99bae1
@ -1,6 +1,9 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using HackerNet.Api.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace HackerNet.Api.Controllers;
|
||||
|
||||
@ -10,17 +13,21 @@ public class AccountsController : ControllerBase
|
||||
{
|
||||
private readonly UserManager<IdentityUser> _userManager;
|
||||
private readonly SignInManager<IdentityUser> _signInManager;
|
||||
private readonly IUserClaimsPrincipalFactory<IdentityUser> _claimsFactory;
|
||||
private readonly TokenValidation _tokenValidation;
|
||||
|
||||
public AccountsController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
|
||||
public AccountsController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, IUserClaimsPrincipalFactory<IdentityUser> claimsFactory, TokenValidation tokenValidation)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_claimsFactory = claimsFactory;
|
||||
_tokenValidation = tokenValidation;
|
||||
}
|
||||
|
||||
[HttpGet("me")]
|
||||
public ActionResult Me()
|
||||
public ActionResult<string> Me()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return User.Identity.Name;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -36,4 +43,36 @@ public class AccountsController : ControllerBase
|
||||
|
||||
return CreatedAtAction(nameof(Me), null);
|
||||
}
|
||||
|
||||
[HttpPost("token")]
|
||||
public async Task<ActionResult<string>> Signin(SignupLoginViewModel cmd)
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(cmd.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var result = await _signInManager.CheckPasswordSignInAsync(user, cmd.Password, false);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
var principal = await _claimsFactory.CreateAsync(user);
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = (ClaimsIdentity)principal.Identity,
|
||||
Expires = DateTime.UtcNow.AddDays(7),
|
||||
Issuer = _tokenValidation.Issuer,
|
||||
Audience = _tokenValidation.Audience,
|
||||
SigningCredentials = new SigningCredentials(
|
||||
new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_tokenValidation.Key))
|
||||
, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
|
||||
return new JwtSecurityTokenHandler().CreateEncodedJwt(tokenDescriptor);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using HackerNet.Application;
|
||||
using HackerNet.Infrastructure.AspNet.Filters;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HackerNet.Api.Controllers;
|
||||
@ -52,6 +53,7 @@ public class LinksController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("{id:guid}/comments")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
public ActionResult PublishComment(Guid id, PublishCommentBody cmd)
|
||||
@ -76,6 +78,7 @@ public class LinksController : ControllerBase
|
||||
/// <param name="cmd"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public ActionResult PublishLink(PublishLinkCommand cmd)
|
||||
|
||||
@ -12,6 +12,7 @@ var tokenValidation = builder.Configuration
|
||||
.GetSection("TokenValidation")
|
||||
.Get<TokenValidation>();
|
||||
|
||||
builder.Services.AddSingleton(tokenValidation);
|
||||
builder.Services.AddHackerNetServicesEntityFramework(builder.Configuration);
|
||||
builder.Services.AddControllers();
|
||||
builder.Services
|
||||
|
||||
@ -6,6 +6,7 @@ GET {{url}}/api/links
|
||||
|
||||
POST {{url}}/api/links
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiJiMGFiMDU0Zi1lMjI0LTRlNGMtYmY0MC0xY2UxNzU0ZWNiMTciLCJuYW1lIjoidGVzdCIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiRlNHVk01U0ZFRUpSTzVORFIzR0ZPN1ZRWkRJQ1c2QVEiLCJuYmYiOjE2Mzk1Nzg3NjEsImV4cCI6MTY0MDE4MzU2MSwiaWF0IjoxNjM5NTc4NzYxLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo3MjUyLyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjcyNTIvIn0.wjL5ALncw5JtNe5YpZD-uQAz2-BvbznOqqN1xgZpjAU
|
||||
|
||||
{
|
||||
"url": "https://localhost:7252/api/links",
|
||||
@ -34,3 +35,13 @@ Content-Type: application/json
|
||||
"username": "test",
|
||||
"password": "G6:c`bzr2h#Pq;4"
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
POST {{url}}/api/accounts/token
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "test",
|
||||
"password": "G6:c`bzr2h#Pq;4"
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Default": "Debug",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
|
||||
@ -9,5 +9,6 @@
|
||||
<a class="text-indigo-500 hover:underline" asp-controller="Links" asp-action="Detail" asp-route-id="@Model.Id">Détail du lien</a>
|
||||
<a class="text-indigo-500 hover:underline" asp-controller="Comments" asp-action="New" asp-route-id="@Model.Id">Ajouter un commentaire</a>
|
||||
<p>@Model.CommentsCount commentaire@(Model.CommentsCount > 1 ? "s" : "")</p>
|
||||
<p>@Model.Author</p>
|
||||
</div>
|
||||
</article>
|
||||
@ -7,20 +7,25 @@ public class LinkService
|
||||
private readonly ILinkRepository _repository;
|
||||
private readonly ICommentRepository _commentRepository;
|
||||
private readonly IReadStore _readStore;
|
||||
private readonly ICurrentUser _currentUser;
|
||||
|
||||
public LinkService(
|
||||
ILinkRepository repository,
|
||||
ICommentRepository commentRepository,
|
||||
IReadStore readStore)
|
||||
IReadStore readStore,
|
||||
ICurrentUser currentUser)
|
||||
{
|
||||
_repository = repository;
|
||||
_commentRepository = commentRepository;
|
||||
_readStore = readStore;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public Guid PublishLink(PublishLinkCommand cmd)
|
||||
{
|
||||
var link = new Link(cmd.Url, cmd.Description);
|
||||
var link = new Link(_currentUser.GetCurrentUserId(),
|
||||
cmd.Url,
|
||||
cmd.Description);
|
||||
|
||||
_repository.Add(link);
|
||||
|
||||
@ -29,7 +34,7 @@ public class LinkService
|
||||
|
||||
public Guid PublishComment(PublishCommentCommand cmd)
|
||||
{
|
||||
var comment = new Comment(cmd.LinkId, cmd.Content);
|
||||
var comment = new Comment(_currentUser.GetCurrentUserId(), cmd.LinkId, cmd.Content);
|
||||
|
||||
_commentRepository.Add(comment);
|
||||
|
||||
@ -53,17 +58,24 @@ public interface IReadStore
|
||||
LinkComment[] GetLinkComments(Guid linkId);
|
||||
}
|
||||
|
||||
public interface ICurrentUser
|
||||
{
|
||||
string GetCurrentUserId();
|
||||
}
|
||||
|
||||
public class LinkHomePage
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int CommentsCount { get; set; }
|
||||
public string Author { get; set; }
|
||||
}
|
||||
|
||||
public class LinkComment
|
||||
{
|
||||
public string Content { get; set; }
|
||||
public string User { get; set; }
|
||||
}
|
||||
|
||||
public class PublishLinkCommand
|
||||
|
||||
@ -6,12 +6,14 @@ public class Comment
|
||||
public Guid LinkId { get; }
|
||||
public string Content { get; }
|
||||
public DateTime CreatedAt { get; }
|
||||
public string CreatedBy { get; }
|
||||
|
||||
public Comment(Guid linkId, string content)
|
||||
public Comment(string createdBy, Guid linkId, string content)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
LinkId = linkId;
|
||||
Content = content;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
CreatedBy = createdBy;
|
||||
}
|
||||
}
|
||||
@ -6,12 +6,14 @@ public class Link
|
||||
public string Url { get; }
|
||||
public string Description { get; }
|
||||
public DateTime CreatedAt { get; }
|
||||
public string CreatedBy { get; }
|
||||
|
||||
public Link(string url, string description)
|
||||
public Link(string createdBy, string url, string description)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
Url = url;
|
||||
Description = description;
|
||||
CreatedAt = DateTime.UtcNow;
|
||||
CreatedBy = createdBy;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@ public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddHackerNetServicesMemory(this IServiceCollection services)
|
||||
{
|
||||
var link = new Link("https://localhost:7050/", "Youhouuu");
|
||||
var comment = new Comment(link.Id, "Wow!");
|
||||
var link = new Link("", "https://localhost:7050/", "Youhouuu");
|
||||
var comment = new Comment("", link.Id, "Wow!");
|
||||
var linksRepository = new MemoryLinkRepository(link);
|
||||
var commentsRepository = new MemoryCommentRepository(comment);
|
||||
|
||||
@ -33,6 +33,7 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
services.AddDbContext<HackerContext>(options
|
||||
=> options.UseSqlite(configuration.GetConnectionString("Default")));
|
||||
services.AddScoped<ICurrentUser, HttpCurrentUser>();
|
||||
services.AddScoped<ILinkRepository, EFLinkRepository>();
|
||||
services.AddScoped<ICommentRepository, EFCommentRepository>();
|
||||
services.AddScoped<IReadStore, EFReadStore>();
|
||||
|
||||
23
HackerNet.Infrastructure/AspNet/HttpCurrentUser.cs
Normal file
23
HackerNet.Infrastructure/AspNet/HttpCurrentUser.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using HackerNet.Application;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace HackerNet.Infrastructure.AspNet;
|
||||
|
||||
public class HttpCurrentUser : ICurrentUser
|
||||
{
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private readonly UserManager<IdentityUser> _userManager;
|
||||
|
||||
public HttpCurrentUser(IHttpContextAccessor contextAccessor, UserManager<IdentityUser> userManager)
|
||||
{
|
||||
_contextAccessor = contextAccessor;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
public string GetCurrentUserId()
|
||||
{
|
||||
var userPrincipal = _contextAccessor.HttpContext.User;
|
||||
return _userManager.GetUserId(userPrincipal);
|
||||
}
|
||||
}
|
||||
349
HackerNet.Infrastructure/Migrations/20211215145254_AddCreatedBy.Designer.cs
generated
Normal file
349
HackerNet.Infrastructure/Migrations/20211215145254_AddCreatedBy.Designer.cs
generated
Normal file
@ -0,0 +1,349 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using HackerNet.Infrastructure.Repositories.EntityFramework;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace HackerNet.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(HackerContext))]
|
||||
[Migration("20211215145254_AddCreatedBy")]
|
||||
partial class AddCreatedBy
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
|
||||
|
||||
modelBuilder.Entity("HackerNet.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<string>("CreatedBy")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HackerNet.Domain.Link", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatedBy")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.ToTable("Links");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.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", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.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", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("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", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HackerNet.Domain.Comment", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HackerNet.Domain.Link", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("LinkId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HackerNet.Domain.Link", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace HackerNet.Infrastructure.Migrations
|
||||
{
|
||||
public partial class AddCreatedBy : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("DELETE FROM Links; DELETE FROM Comments;");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "CreatedBy",
|
||||
table: "Links",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "CreatedBy",
|
||||
table: "Comments",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,11 +30,17 @@ namespace HackerNet.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatedBy")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("LinkId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
@ -49,6 +55,10 @@ namespace HackerNet.Infrastructure.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CreatedBy")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
@ -60,6 +70,8 @@ namespace HackerNet.Infrastructure.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedBy");
|
||||
|
||||
b.ToTable("Links");
|
||||
});
|
||||
|
||||
@ -257,6 +269,12 @@ namespace HackerNet.Infrastructure.Migrations
|
||||
|
||||
modelBuilder.Entity("HackerNet.Domain.Comment", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("HackerNet.Domain.Link", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("LinkId")
|
||||
@ -264,6 +282,15 @@ namespace HackerNet.Infrastructure.Migrations
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("HackerNet.Domain.Link", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||
|
||||
@ -27,16 +27,30 @@ public class EFReadStore : IReadStore
|
||||
|
||||
private IQueryable<LinkHomePage> GetLinks(Guid? id = null)
|
||||
{
|
||||
return _context.Links
|
||||
.Where(l => !id.HasValue || l.Id == id)
|
||||
.OrderByDescending(l => l.CreatedAt)
|
||||
.Select(l => new LinkHomePage
|
||||
return (from link in _context.Links
|
||||
join user in _context.Users on link.CreatedBy equals user.Id
|
||||
orderby link.CreatedAt descending
|
||||
select new LinkHomePage
|
||||
{
|
||||
Id = l.Id,
|
||||
Url = l.Url,
|
||||
Description = l.Description,
|
||||
CommentsCount = _context.Comments
|
||||
.Count(c => c.LinkId == l.Id),
|
||||
Id = link.Id,
|
||||
Url = link.Url,
|
||||
Description = link.Description,
|
||||
CommentsCount = _context.Comments.Count(c => c.LinkId == link.Id),
|
||||
Author = user.UserName,
|
||||
});
|
||||
|
||||
|
||||
// return _context.Links
|
||||
// .Where(l => !id.HasValue || l.Id == id)
|
||||
// .OrderByDescending(l => l.CreatedAt)
|
||||
// .Join()
|
||||
// .Select(l => new LinkHomePage
|
||||
// {
|
||||
// Id = l.Id,
|
||||
// Url = l.Url,
|
||||
// Description = l.Description,
|
||||
// CommentsCount = _context.Comments
|
||||
// .Count(c => c.LinkId == l.Id),
|
||||
// });
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using HackerNet.Domain;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
@ -16,5 +17,10 @@ public class CommentEntityTypeConfiguration : IEntityTypeConfiguration<Comment>
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
builder.Property(o => o.Content).IsRequired();
|
||||
builder.Property(o => o.CreatedAt).IsRequired();
|
||||
builder.HasOne<IdentityUser>()
|
||||
.WithMany()
|
||||
.HasForeignKey(o => o.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using HackerNet.Domain;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
@ -12,5 +13,11 @@ public class LinkEntityTypeConfiguration : IEntityTypeConfiguration<Link>
|
||||
builder.Property(o => o.Url).IsRequired().HasMaxLength(250);
|
||||
builder.Property(o => o.Description).IsRequired();
|
||||
builder.Property(o => o.CreatedAt).IsRequired();
|
||||
|
||||
builder.HasOne<IdentityUser>()
|
||||
.WithMany()
|
||||
.HasForeignKey(o => o.CreatedBy)
|
||||
.IsRequired()
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user