add-aspnet-identity #26

Merged
jleicher merged 5 commits from add-aspnet-identity into master 2020-12-11 17:59:36 +01:00
16 changed files with 774 additions and 59 deletions
Showing only changes of commit fb886c5c33 - Show all commits

View File

@ -10,15 +10,17 @@ namespace HN.Application
public class AddLinkCommandHandler : IRequestHandler<AddLinkCommand, Guid> public class AddLinkCommandHandler : IRequestHandler<AddLinkCommand, Guid>
{ {
private readonly ILinkRepository _repository; private readonly ILinkRepository _repository;
private readonly IExecutingUserProvider _executingUserProvider;
public AddLinkCommandHandler(ILinkRepository repository) public AddLinkCommandHandler(ILinkRepository repository, IExecutingUserProvider executingUserProvider)
{ {
this._repository = repository; _repository = repository;
_executingUserProvider = executingUserProvider;
} }
public async Task<Guid> Handle(AddLinkCommand request, CancellationToken cancellationToken) public async Task<Guid> Handle(AddLinkCommand request, CancellationToken cancellationToken)
{ {
var link = Link.FromUrl(request.Url); var link = Link.FromUrl(_executingUserProvider.GetCurrentUserId(), request.Url);
await this._repository.AddAsync(link); await this._repository.AddAsync(link);

View File

@ -10,17 +10,19 @@ namespace HN.Application
{ {
private readonly ILinkRepository _linkRepository; private readonly ILinkRepository _linkRepository;
private readonly ICommentRepository _commentRepository; private readonly ICommentRepository _commentRepository;
private readonly IExecutingUserProvider _executingUserProvider;
public CommentLinkCommandHandler(ILinkRepository linkRepository, ICommentRepository commentRepository) public CommentLinkCommandHandler(ILinkRepository linkRepository, ICommentRepository commentRepository, IExecutingUserProvider executingUserProvider)
{ {
_linkRepository = linkRepository; _linkRepository = linkRepository;
_commentRepository = commentRepository; _commentRepository = commentRepository;
_executingUserProvider = executingUserProvider;
} }
public async Task<Guid> Handle(CommentLinkCommand request, CancellationToken cancellationToken) public async Task<Guid> Handle(CommentLinkCommand request, CancellationToken cancellationToken)
{ {
var link = await _linkRepository.GetByIdAsync(request.LinkId); var link = await _linkRepository.GetByIdAsync(request.LinkId);
var comment = link.AddComment(request.Content); var comment = link.AddComment(_executingUserProvider.GetCurrentUserId(), request.Content);
await _commentRepository.AddAsync(comment); await _commentRepository.AddAsync(comment);

View File

@ -0,0 +1,12 @@
using System;
namespace HN.Application
{
/// <summary>
/// Permet de récupérer l'utilisateur courant effectuant une commande.
/// </summary>
public interface IExecutingUserProvider
{
Guid GetCurrentUserId();
}
}

View File

@ -8,23 +8,26 @@ namespace HN.Application
public sealed class VoteForCommentCommandHandler : IRequestHandler<VoteForCommentCommand> public sealed class VoteForCommentCommandHandler : IRequestHandler<VoteForCommentCommand>
{ {
private readonly ICommentRepository _commentRepository; private readonly ICommentRepository _commentRepository;
private readonly IExecutingUserProvider _executingUserProvider;
public VoteForCommentCommandHandler(ICommentRepository commentRepository) public VoteForCommentCommandHandler(ICommentRepository commentRepository, IExecutingUserProvider executingUserProvider)
{ {
_commentRepository = commentRepository; _commentRepository = commentRepository;
_executingUserProvider = executingUserProvider;
} }
public async Task<Unit> Handle(VoteForCommentCommand request, CancellationToken cancellationToken) public async Task<Unit> Handle(VoteForCommentCommand request, CancellationToken cancellationToken)
{ {
var comment = await _commentRepository.GetByIdAsync(request.CommentId); var comment = await _commentRepository.GetByIdAsync(request.CommentId);
var userId = _executingUserProvider.GetCurrentUserId();
switch (request.Type) switch (request.Type)
{ {
case VoteType.Up: case VoteType.Up:
comment.Upvote(); comment.Upvote(userId);
break; break;
case VoteType.Down: case VoteType.Down:
comment.Downvote(); comment.Downvote(userId);
break; break;
} }

View File

@ -8,23 +8,26 @@ namespace HN.Application
public sealed class VoteForLinkCommandHandler : IRequestHandler<VoteForLinkCommand> public sealed class VoteForLinkCommandHandler : IRequestHandler<VoteForLinkCommand>
{ {
private readonly ILinkRepository _linkRepository; private readonly ILinkRepository _linkRepository;
private readonly IExecutingUserProvider _executingUserProvider;
public VoteForLinkCommandHandler(ILinkRepository linkRepository) public VoteForLinkCommandHandler(ILinkRepository linkRepository, IExecutingUserProvider executingUserProvider)
{ {
_linkRepository = linkRepository; _linkRepository = linkRepository;
_executingUserProvider = executingUserProvider;
} }
public async Task<Unit> Handle(VoteForLinkCommand request, CancellationToken cancellationToken) public async Task<Unit> Handle(VoteForLinkCommand request, CancellationToken cancellationToken)
{ {
var link = await _linkRepository.GetByIdAsync(request.LinkId); var link = await _linkRepository.GetByIdAsync(request.LinkId);
var userId = _executingUserProvider.GetCurrentUserId();
switch (request.Type) switch (request.Type)
{ {
case VoteType.Up: case VoteType.Up:
link.Upvote(); link.Upvote(userId);
break; break;
case VoteType.Down: case VoteType.Down:
link.Downvote(); link.Downvote(userId);
break; break;
} }

View File

@ -0,0 +1,25 @@
using System;
using HN.Application;
using HN.Infrastructure;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
namespace Website
{
public sealed class HttpExecutingUserProvider : IExecutingUserProvider
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager<User> _userManager;
public HttpExecutingUserProvider(IHttpContextAccessor httpContextAccessor, UserManager<User> userManager)
{
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
}
public Guid GetCurrentUserId()
{
return Guid.Parse(_userManager.GetUserId(_httpContextAccessor.HttpContext.User));
}
}
}

View File

@ -30,6 +30,7 @@ namespace Website
services.AddScoped<IHNContext, HNDbContext>(); services.AddScoped<IHNContext, HNDbContext>();
services.AddScoped<ILinkRepository, LinkRepository>(); services.AddScoped<ILinkRepository, LinkRepository>();
services.AddScoped<ICommentRepository, CommentRepository>(); services.AddScoped<ICommentRepository, CommentRepository>();
services.AddScoped<IExecutingUserProvider, HttpExecutingUserProvider>();
services.AddMediatR(typeof(HN.Application.IHNContext)); services.AddMediatR(typeof(HN.Application.IHNContext));
// Permet d'avoir des routes en lowercase // Permet d'avoir des routes en lowercase

View File

@ -1,34 +1,22 @@
using System; using System;
using System.Collections.Generic;
namespace HN.Domain namespace HN.Domain
{ {
public sealed class Comment public sealed class Comment : Votable
{ {
public Guid Id { get; private set; } public Guid Id { get; }
public Guid LinkId { get; private set; } public Guid LinkId { get; }
public string Content { get; private set; } public string Content { get; }
public DateTime CreatedAt { get; private set; } public Guid CreatedBy { get; }
private List<Vote> _votes; public DateTime CreatedAt { get; }
public IReadOnlyList<Vote> Votes => _votes;
internal Comment(Guid linkId, string content) internal Comment(Guid linkId, Guid createdBy, string content) : base()
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
LinkId = linkId; LinkId = linkId;
CreatedBy = createdBy;
Content = content; Content = content;
CreatedAt = DateTime.UtcNow; CreatedAt = DateTime.UtcNow;
_votes = new List<Vote>();
}
public void Upvote()
{
_votes.Add(new Vote(VoteType.Up));
}
public void Downvote()
{
_votes.Add(new Vote(VoteType.Down));
} }
} }
} }

View File

@ -1,42 +1,30 @@
using System; using System;
using System.Collections.Generic;
namespace HN.Domain namespace HN.Domain
{ {
public sealed class Link public sealed class Link : Votable
{ {
public Guid Id { get; } public Guid Id { get; }
public string Url { get; } public string Url { get; }
public DateTime CreatedAt { get; } public DateTime CreatedAt { get; }
private List<Vote> _votes; public Guid CreatedBy { get; }
public IReadOnlyList<Vote> Votes => _votes;
private Link(string url) private Link(Guid createdBy, string url) : base()
{ {
this.Id = Guid.NewGuid(); Id = Guid.NewGuid();
this.CreatedAt = DateTime.UtcNow; CreatedBy = createdBy;
this.Url = url; CreatedAt = DateTime.UtcNow;
this._votes = new List<Vote>(); Url = url;
} }
public static Link FromUrl(string url) public static Link FromUrl(Guid posterId, string url)
{ {
return new Link(url); return new Link(posterId, url);
} }
public void Upvote() public Comment AddComment(Guid userId, string content)
{ {
_votes.Add(new Vote(VoteType.Up)); return new Comment(Id, userId, content);
}
public void Downvote()
{
_votes.Add(new Vote(VoteType.Down));
}
public Comment AddComment(string content)
{
return new Comment(Id, content);
} }
} }
} }

43
Domain/Votable.cs Normal file
View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace HN.Domain
{
/// <summary>
/// Représente une entité sur laquelle on peut voter.
/// </summary>
public abstract class Votable
{
private List<Vote> _votes;
public IReadOnlyList<Vote> Votes => _votes;
protected Votable()
{
_votes = new List<Vote>();
}
public void Upvote(Guid userId)
{
UpsertUserVote(userId, VoteType.Up);
}
public void Downvote(Guid userId)
{
UpsertUserVote(userId, VoteType.Down);
}
private void UpsertUserVote(Guid userId, VoteType type)
{
var vote = _votes.SingleOrDefault(v => v.CreatedBy == userId);
if (vote == null)
{
_votes.Add(new Vote(userId, type));
return;
}
vote.HasType(type);
}
}
}

View File

@ -5,9 +5,21 @@ namespace HN.Domain
public sealed class Vote public sealed class Vote
{ {
public VoteType Type { get; private set; } public VoteType Type { get; private set; }
public Guid CreatedBy { get; }
public DateTime CreatedAt { get; private set; } public DateTime CreatedAt { get; private set; }
internal Vote(VoteType type) internal Vote(Guid createdBy, VoteType type)
{
CreatedBy = createdBy;
Type = type;
CreatedAt = DateTime.UtcNow;
}
/// <summary>
/// Change le type d'un vote
/// </summary>
/// <param name="type"></param>
public void HasType(VoteType type)
{ {
Type = type; Type = type;
CreatedAt = DateTime.UtcNow; CreatedAt = DateTime.UtcNow;

View File

@ -17,11 +17,14 @@ namespace HN.Infrastructure
builder.Property(o => o.Content).IsRequired(); builder.Property(o => o.Content).IsRequired();
builder.Property(o => o.CreatedAt).IsRequired(); builder.Property(o => o.CreatedAt).IsRequired();
builder.HasOne<User>().WithMany().HasForeignKey(nameof(Comment.CreatedBy)).IsRequired();
builder.OwnsMany(o => o.Votes, vote => builder.OwnsMany(o => o.Votes, vote =>
{ {
vote.ToTable("comment_votes"); vote.ToTable("comment_votes");
vote.WithOwner().HasForeignKey("CommentId"); vote.WithOwner().HasForeignKey("CommentId");
vote.HasKey("CommentId"); vote.HasKey("CommentId", nameof(Comment.CreatedBy));
vote.HasOne<User>().WithMany().HasForeignKey(nameof(Vote.CreatedBy)).IsRequired();
vote.Property(o => o.Type).IsRequired(); vote.Property(o => o.Type).IsRequired();
vote.Property(o => o.CreatedAt).IsRequired(); vote.Property(o => o.CreatedAt).IsRequired();
}); });

View File

@ -14,11 +14,14 @@ namespace HN.Infrastructure.EntityTypes
builder.Property(o => o.CreatedAt).IsRequired(); builder.Property(o => o.CreatedAt).IsRequired();
builder.HasIndex(o => o.Url).IsUnique(); builder.HasIndex(o => o.Url).IsUnique();
builder.HasOne<User>().WithMany().HasForeignKey(nameof(Link.CreatedBy)).IsRequired();
builder.OwnsMany(o => o.Votes, vote => builder.OwnsMany(o => o.Votes, vote =>
{ {
vote.ToTable("link_votes"); vote.ToTable("link_votes");
vote.WithOwner().HasForeignKey("LinkId"); vote.WithOwner().HasForeignKey("LinkId");
vote.HasKey("LinkId"); vote.HasKey("LinkId", nameof(Link.CreatedBy));
vote.HasOne<User>().WithMany().HasForeignKey(nameof(Vote.CreatedBy)).IsRequired();
vote.Property(o => o.Type).IsRequired(); vote.Property(o => o.Type).IsRequired();
vote.Property(o => o.CreatedAt).IsRequired(); vote.Property(o => o.CreatedAt).IsRequired();
}); });

View File

@ -0,0 +1,408 @@
// <auto-generated />
using System;
using HN.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Infrastructure.Migrations
{
[DbContext(typeof(HNDbContext))]
[Migration("20201211144029_AddCreatedBy")]
partial class AddCreatedBy
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.0");
modelBuilder.Entity("HN.Domain.Comment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b.Property<Guid>("LinkId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CreatedBy");
b.HasIndex("LinkId");
b.ToTable("comments");
});
modelBuilder.Entity("HN.Domain.Link", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b.Property<string>("Url")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CreatedBy");
b.HasIndex("Url")
.IsUnique();
b.ToTable("links");
});
modelBuilder.Entity("HN.Infrastructure.Role", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("HN.Infrastructure.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<Guid>("RoleId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<Guid>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("HN.Domain.Comment", b =>
{
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("HN.Domain.Link", null)
.WithMany()
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
{
b1.Property<Guid>("CommentId")
.HasColumnType("TEXT");
b1.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b1.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b1.Property<int>("Type")
.HasColumnType("INTEGER");
b1.HasKey("CommentId", "CreatedBy");
b1.HasIndex("CreatedBy");
b1.ToTable("comment_votes");
b1.WithOwner()
.HasForeignKey("CommentId");
b1.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
b.Navigation("Votes");
});
modelBuilder.Entity("HN.Domain.Link", b =>
{
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
{
b1.Property<Guid>("LinkId")
.HasColumnType("TEXT");
b1.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b1.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b1.Property<int>("Type")
.HasColumnType("INTEGER");
b1.HasKey("LinkId", "CreatedBy");
b1.HasIndex("CreatedBy");
b1.ToTable("link_votes");
b1.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b1.WithOwner()
.HasForeignKey("LinkId");
});
b.Navigation("Votes");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("HN.Infrastructure.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("HN.Infrastructure.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,178 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Infrastructure.Migrations
{
public partial class AddCreatedBy : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_link_votes",
table: "link_votes");
migrationBuilder.DropPrimaryKey(
name: "PK_comment_votes",
table: "comment_votes");
migrationBuilder.AddColumn<Guid>(
name: "CreatedBy",
table: "links",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "CreatedBy",
table: "link_votes",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "CreatedBy",
table: "comments",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "CreatedBy",
table: "comment_votes",
type: "TEXT",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddPrimaryKey(
name: "PK_link_votes",
table: "link_votes",
columns: new[] { "LinkId", "CreatedBy" });
migrationBuilder.AddPrimaryKey(
name: "PK_comment_votes",
table: "comment_votes",
columns: new[] { "CommentId", "CreatedBy" });
migrationBuilder.CreateIndex(
name: "IX_links_CreatedBy",
table: "links",
column: "CreatedBy");
migrationBuilder.CreateIndex(
name: "IX_link_votes_CreatedBy",
table: "link_votes",
column: "CreatedBy");
migrationBuilder.CreateIndex(
name: "IX_comments_CreatedBy",
table: "comments",
column: "CreatedBy");
migrationBuilder.CreateIndex(
name: "IX_comment_votes_CreatedBy",
table: "comment_votes",
column: "CreatedBy");
migrationBuilder.AddForeignKey(
name: "FK_comment_votes_AspNetUsers_CreatedBy",
table: "comment_votes",
column: "CreatedBy",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_comments_AspNetUsers_CreatedBy",
table: "comments",
column: "CreatedBy",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_link_votes_AspNetUsers_CreatedBy",
table: "link_votes",
column: "CreatedBy",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_links_AspNetUsers_CreatedBy",
table: "links",
column: "CreatedBy",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_comment_votes_AspNetUsers_CreatedBy",
table: "comment_votes");
migrationBuilder.DropForeignKey(
name: "FK_comments_AspNetUsers_CreatedBy",
table: "comments");
migrationBuilder.DropForeignKey(
name: "FK_link_votes_AspNetUsers_CreatedBy",
table: "link_votes");
migrationBuilder.DropForeignKey(
name: "FK_links_AspNetUsers_CreatedBy",
table: "links");
migrationBuilder.DropIndex(
name: "IX_links_CreatedBy",
table: "links");
migrationBuilder.DropPrimaryKey(
name: "PK_link_votes",
table: "link_votes");
migrationBuilder.DropIndex(
name: "IX_link_votes_CreatedBy",
table: "link_votes");
migrationBuilder.DropIndex(
name: "IX_comments_CreatedBy",
table: "comments");
migrationBuilder.DropPrimaryKey(
name: "PK_comment_votes",
table: "comment_votes");
migrationBuilder.DropIndex(
name: "IX_comment_votes_CreatedBy",
table: "comment_votes");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "links");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "link_votes");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "comments");
migrationBuilder.DropColumn(
name: "CreatedBy",
table: "comment_votes");
migrationBuilder.AddPrimaryKey(
name: "PK_link_votes",
table: "link_votes",
column: "LinkId");
migrationBuilder.AddPrimaryKey(
name: "PK_comment_votes",
table: "comment_votes",
column: "CommentId");
}
}
}

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(500) .HasMaxLength(500)
@ -55,6 +63,8 @@ namespace Infrastructure.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CreatedBy");
b.HasIndex("Url") b.HasIndex("Url")
.IsUnique(); .IsUnique();
@ -254,6 +264,12 @@ namespace Infrastructure.Migrations
modelBuilder.Entity("HN.Domain.Comment", b => modelBuilder.Entity("HN.Domain.Comment", b =>
{ {
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("HN.Domain.Link", null) b.HasOne("HN.Domain.Link", null)
.WithMany() .WithMany()
.HasForeignKey("LinkId") .HasForeignKey("LinkId")
@ -265,18 +281,29 @@ namespace Infrastructure.Migrations
b1.Property<Guid>("CommentId") b1.Property<Guid>("CommentId")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b1.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b1.Property<DateTime>("CreatedAt") b1.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b1.Property<int>("Type") b1.Property<int>("Type")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b1.HasKey("CommentId"); b1.HasKey("CommentId", "CreatedBy");
b1.HasIndex("CreatedBy");
b1.ToTable("comment_votes"); b1.ToTable("comment_votes");
b1.WithOwner() b1.WithOwner()
.HasForeignKey("CommentId"); .HasForeignKey("CommentId");
b1.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
}); });
b.Navigation("Votes"); b.Navigation("Votes");
@ -284,21 +311,38 @@ namespace Infrastructure.Migrations
modelBuilder.Entity("HN.Domain.Link", b => modelBuilder.Entity("HN.Domain.Link", b =>
{ {
b.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsMany("HN.Domain.Vote", "Votes", b1 => b.OwnsMany("HN.Domain.Vote", "Votes", b1 =>
{ {
b1.Property<Guid>("LinkId") b1.Property<Guid>("LinkId")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b1.Property<Guid>("CreatedBy")
.HasColumnType("TEXT");
b1.Property<DateTime>("CreatedAt") b1.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b1.Property<int>("Type") b1.Property<int>("Type")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b1.HasKey("LinkId"); b1.HasKey("LinkId", "CreatedBy");
b1.HasIndex("CreatedBy");
b1.ToTable("link_votes"); b1.ToTable("link_votes");
b1.HasOne("HN.Infrastructure.User", null)
.WithMany()
.HasForeignKey("CreatedBy")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b1.WithOwner() b1.WithOwner()
.HasForeignKey("LinkId"); .HasForeignKey("LinkId");
}); });