✨ Relationships controllers
This commit is contained in:
parent
cec8c3af81
commit
f9701764f3
@ -79,7 +79,7 @@ public class AccountController(AppDatabase db, FileService fs) : ControllerBase
|
|||||||
{
|
{
|
||||||
var userIdClaim = User.FindFirst("user_id")?.Value;
|
var userIdClaim = User.FindFirst("user_id")?.Value;
|
||||||
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
||||||
if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim.");
|
if (userId is null) return BadRequest("Invalid or missing user_id claim.");
|
||||||
|
|
||||||
var account = await db.Accounts
|
var account = await db.Accounts
|
||||||
.Include(e => e.Profile)
|
.Include(e => e.Profile)
|
||||||
@ -103,7 +103,7 @@ public class AccountController(AppDatabase db, FileService fs) : ControllerBase
|
|||||||
{
|
{
|
||||||
var userIdClaim = User.FindFirst("user_id")?.Value;
|
var userIdClaim = User.FindFirst("user_id")?.Value;
|
||||||
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
||||||
if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim.");
|
if (userId is null) return BadRequest("Invalid or missing user_id claim.");
|
||||||
|
|
||||||
var account = await db.Accounts.FindAsync(userId);
|
var account = await db.Accounts.FindAsync(userId);
|
||||||
if (account is null) return BadRequest("Unable to get your account.");
|
if (account is null) return BadRequest("Unable to get your account.");
|
||||||
@ -132,7 +132,7 @@ public class AccountController(AppDatabase db, FileService fs) : ControllerBase
|
|||||||
{
|
{
|
||||||
var userIdClaim = User.FindFirst("user_id")?.Value;
|
var userIdClaim = User.FindFirst("user_id")?.Value;
|
||||||
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
||||||
if (userId is null) return new BadRequestObjectResult("Invalid or missing user_id claim.");
|
if (userId is null) return BadRequest("Invalid or missing user_id claim.");
|
||||||
|
|
||||||
var profile = await db.AccountProfiles
|
var profile = await db.AccountProfiles
|
||||||
.Where(p => p.Account.Id == userId)
|
.Where(p => p.Account.Id == userId)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
using Casbin;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Account;
|
namespace DysonNetwork.Sphere.Account;
|
||||||
|
|
||||||
public class AccountService(AppDatabase db)
|
public class AccountService(AppDatabase db, IEnforcer enforcer)
|
||||||
{
|
{
|
||||||
public async Task<Account?> LookupAccount(string probe)
|
public async Task<Account?> LookupAccount(string probe)
|
||||||
{
|
{
|
||||||
@ -17,4 +19,144 @@ public class AccountService(AppDatabase db)
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> HasExistingRelationship(Account userA, Account userB)
|
||||||
|
{
|
||||||
|
var count = await db.AccountRelationships
|
||||||
|
.Where(r => (r.AccountId == userA.Id && r.AccountId == userB.Id) ||
|
||||||
|
(r.AccountId == userB.Id && r.AccountId == userA.Id))
|
||||||
|
.CountAsync();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Relationship?> GetRelationship(
|
||||||
|
Account account,
|
||||||
|
Account related,
|
||||||
|
RelationshipStatus? status,
|
||||||
|
bool ignoreExpired = false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var now = Instant.FromDateTimeUtc(DateTime.UtcNow);
|
||||||
|
var queries = db.AccountRelationships
|
||||||
|
.Where(r => r.AccountId == account.Id && r.AccountId == related.Id);
|
||||||
|
if (ignoreExpired) queries = queries.Where(r => r.ExpiredAt > now);
|
||||||
|
if (status is not null) queries = queries.Where(r => r.Status == status);
|
||||||
|
var relationship = await queries.FirstOrDefaultAsync();
|
||||||
|
return relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Relationship> CreateRelationship(Account sender, Account target, RelationshipStatus status)
|
||||||
|
{
|
||||||
|
if (status == RelationshipStatus.Pending)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Cannot create relationship with pending status, use SendFriendRequest instead.");
|
||||||
|
if (await HasExistingRelationship(sender, target))
|
||||||
|
throw new InvalidOperationException("Found existing relationship between you and target user.");
|
||||||
|
|
||||||
|
var relationship = new Relationship
|
||||||
|
{
|
||||||
|
Account = sender,
|
||||||
|
AccountId = sender.Id,
|
||||||
|
Related = target,
|
||||||
|
RelatedId = target.Id,
|
||||||
|
Status = status
|
||||||
|
};
|
||||||
|
|
||||||
|
db.AccountRelationships.Add(relationship);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
await ApplyRelationshipPermissions(relationship);
|
||||||
|
|
||||||
|
return relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Relationship> SendFriendRequest(Account sender, Account target)
|
||||||
|
{
|
||||||
|
if (await HasExistingRelationship(sender, target))
|
||||||
|
throw new InvalidOperationException("Found existing relationship between you and target user.");
|
||||||
|
|
||||||
|
var relationship = new Relationship
|
||||||
|
{
|
||||||
|
Account = sender,
|
||||||
|
AccountId = sender.Id,
|
||||||
|
Related = target,
|
||||||
|
RelatedId = target.Id,
|
||||||
|
Status = RelationshipStatus.Pending,
|
||||||
|
ExpiredAt = Instant.FromDateTimeUtc(DateTime.UtcNow.AddDays(7))
|
||||||
|
};
|
||||||
|
|
||||||
|
db.AccountRelationships.Add(relationship);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Relationship> AcceptFriendRelationship(
|
||||||
|
Relationship relationship,
|
||||||
|
RelationshipStatus status = RelationshipStatus.Friends
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (relationship.Status == RelationshipStatus.Pending)
|
||||||
|
throw new ArgumentException("Cannot accept friend request by setting the new status to pending.");
|
||||||
|
|
||||||
|
// Whatever the receiver decides to apply which status to the relationship,
|
||||||
|
// the sender should always see the user as a friend since the sender ask for it
|
||||||
|
relationship.Status = RelationshipStatus.Friends;
|
||||||
|
relationship.ExpiredAt = null;
|
||||||
|
db.Update(relationship);
|
||||||
|
|
||||||
|
var relationshipBackward = new Relationship
|
||||||
|
{
|
||||||
|
Account = relationship.Related,
|
||||||
|
AccountId = relationship.RelatedId,
|
||||||
|
Related = relationship.Account,
|
||||||
|
RelatedId = relationship.AccountId,
|
||||||
|
Status = status
|
||||||
|
};
|
||||||
|
db.AccountRelationships.Add(relationshipBackward);
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
await Task.WhenAll(
|
||||||
|
ApplyRelationshipPermissions(relationship),
|
||||||
|
ApplyRelationshipPermissions(relationshipBackward)
|
||||||
|
);
|
||||||
|
|
||||||
|
return relationshipBackward;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Relationship> UpdateRelationship(Account account, Account related, RelationshipStatus status)
|
||||||
|
{
|
||||||
|
var relationship = await GetRelationship(account, related, status);
|
||||||
|
if (relationship is null) throw new ArgumentException("There is no relationship between you and the user.");
|
||||||
|
if (relationship.Status == status) return relationship;
|
||||||
|
relationship.Status = status;
|
||||||
|
db.Update(relationship);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
await ApplyRelationshipPermissions(relationship);
|
||||||
|
return relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ApplyRelationshipPermissions(Relationship relationship)
|
||||||
|
{
|
||||||
|
// Apply the relationship permissions to casbin enforcer
|
||||||
|
// domain: the user
|
||||||
|
// status is friends: all permissions are allowed by default, expect specially specified
|
||||||
|
// status is blocked: all permissions are disallowed by default, expect specially specified
|
||||||
|
// others: use the default permissions by design
|
||||||
|
|
||||||
|
var domain = $"user:{relationship.AccountId.ToString()}";
|
||||||
|
var target = relationship.RelatedId.ToString();
|
||||||
|
|
||||||
|
await enforcer.DeleteRolesForUserAsync(target, domain);
|
||||||
|
|
||||||
|
string role = relationship.Status switch
|
||||||
|
{
|
||||||
|
RelationshipStatus.Friends => "friends",
|
||||||
|
RelationshipStatus.Blocked => "blocked",
|
||||||
|
_ => "default" // fallback role
|
||||||
|
};
|
||||||
|
if (role == "default") return;
|
||||||
|
|
||||||
|
await enforcer.AddRoleForUserAsync(target, role, domain);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,18 +1,22 @@
|
|||||||
|
using NodaTime;
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Account;
|
namespace DysonNetwork.Sphere.Account;
|
||||||
|
|
||||||
public enum RelationshipType
|
public enum RelationshipStatus
|
||||||
{
|
{
|
||||||
Friend,
|
Pending,
|
||||||
|
Friends,
|
||||||
Blocked
|
Blocked
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Relationship : ModelBase
|
public class Relationship : ModelBase
|
||||||
{
|
{
|
||||||
public long FromAccountId { get; set; }
|
public long AccountId { get; set; }
|
||||||
public Account FromAccount { get; set; } = null!;
|
public Account Account { get; set; } = null!;
|
||||||
|
public long RelatedId { get; set; }
|
||||||
|
public Account Related { get; set; } = null!;
|
||||||
|
|
||||||
public long ToAccountId { get; set; }
|
public Instant? ExpiredAt { get; set; }
|
||||||
public Account ToAccount { get; set; } = null!;
|
|
||||||
|
|
||||||
public RelationshipType Type { get; set; }
|
public RelationshipStatus Status { get; set; } = RelationshipStatus.Pending;
|
||||||
}
|
}
|
66
DysonNetwork.Sphere/Account/RelationshipController.cs
Normal file
66
DysonNetwork.Sphere/Account/RelationshipController.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Account;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("/relationships")]
|
||||||
|
public class RelationshipController(AppDatabase db, AccountService accounts) : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<List<Relationship>>> ListRelationships([FromQuery] int offset = 0,
|
||||||
|
[FromQuery] int take = 20)
|
||||||
|
{
|
||||||
|
var userIdClaim = User.FindFirst("user_id")?.Value;
|
||||||
|
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
||||||
|
if (userId is null) return BadRequest("Invalid or missing user_id claim.");
|
||||||
|
|
||||||
|
var totalCount = await db.AccountRelationships
|
||||||
|
.CountAsync(r => r.Account.Id == userId);
|
||||||
|
var relationships = await db.AccountRelationships
|
||||||
|
.Where(r => r.Account.Id == userId)
|
||||||
|
.Include(r => r.Related)
|
||||||
|
.Skip(offset)
|
||||||
|
.Take(take)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
Response.Headers["X-Total"] = totalCount.ToString();
|
||||||
|
|
||||||
|
return relationships;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RelationshipCreateRequest
|
||||||
|
{
|
||||||
|
[Required] public long UserId { get; set; }
|
||||||
|
[Required] public RelationshipStatus Status { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<Relationship>> CreateRelationship([FromBody] RelationshipCreateRequest request)
|
||||||
|
{
|
||||||
|
var userIdClaim = User.FindFirst("user_id")?.Value;
|
||||||
|
long? userId = long.TryParse(userIdClaim, out var id) ? id : null;
|
||||||
|
if (userId is null) return BadRequest("Invalid or missing user_id claim.");
|
||||||
|
|
||||||
|
var currentUser = await db.Accounts.FindAsync(userId.Value);
|
||||||
|
if (currentUser is null) return BadRequest("Failed to get your current user");
|
||||||
|
var relatedUser = await db.Accounts.FindAsync(request.UserId);
|
||||||
|
if (relatedUser is null) return BadRequest("Invalid related user");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var relationship = await accounts.CreateRelationship(
|
||||||
|
currentUser, relatedUser, request.Status
|
||||||
|
);
|
||||||
|
return relationship;
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException err)
|
||||||
|
{
|
||||||
|
return BadRequest(err.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -53,15 +53,15 @@ public class AppDatabase(
|
|||||||
.HasForeignKey<Account.Profile>(p => p.Id);
|
.HasForeignKey<Account.Profile>(p => p.Id);
|
||||||
|
|
||||||
modelBuilder.Entity<Account.Relationship>()
|
modelBuilder.Entity<Account.Relationship>()
|
||||||
.HasKey(r => new { r.FromAccountId, r.ToAccountId });
|
.HasKey(r => new { FromAccountId = r.AccountId, ToAccountId = r.RelatedId });
|
||||||
modelBuilder.Entity<Account.Relationship>()
|
modelBuilder.Entity<Account.Relationship>()
|
||||||
.HasOne(r => r.FromAccount)
|
.HasOne(r => r.Account)
|
||||||
.WithMany(a => a.OutgoingRelationships)
|
.WithMany(a => a.OutgoingRelationships)
|
||||||
.HasForeignKey(r => r.FromAccountId);
|
.HasForeignKey(r => r.AccountId);
|
||||||
modelBuilder.Entity<Account.Relationship>()
|
modelBuilder.Entity<Account.Relationship>()
|
||||||
.HasOne(r => r.ToAccount)
|
.HasOne(r => r.Related)
|
||||||
.WithMany(a => a.IncomingRelationships)
|
.WithMany(a => a.IncomingRelationships)
|
||||||
.HasForeignKey(r => r.ToAccountId);
|
.HasForeignKey(r => r.RelatedId);
|
||||||
|
|
||||||
// Automatically apply soft-delete filter to all entities inheriting BaseModel
|
// Automatically apply soft-delete filter to all entities inheriting BaseModel
|
||||||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||||
|
@ -14,7 +14,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace DysonNetwork.Sphere.Migrations
|
namespace DysonNetwork.Sphere.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(AppDatabase))]
|
[DbContext(typeof(AppDatabase))]
|
||||||
[Migration("20250415171044_AddRelationship")]
|
[Migration("20250417145426_AddRelationship")]
|
||||||
partial class AddRelationship
|
partial class AddRelationship
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -226,13 +226,13 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("FromAccountId")
|
b.Property<long>("AccountId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("from_account_id");
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
b.Property<long>("ToAccountId")
|
b.Property<long>("RelatedId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("to_account_id");
|
.HasColumnName("related_id");
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
b.Property<Instant>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
@ -242,19 +242,23 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("deleted_at");
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
b.Property<int>("Type")
|
b.Property<Instant?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expired_at");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("type");
|
.HasColumnName("status");
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
b.Property<Instant>("UpdatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.HasKey("FromAccountId", "ToAccountId")
|
b.HasKey("AccountId", "RelatedId")
|
||||||
.HasName("pk_account_relationships");
|
.HasName("pk_account_relationships");
|
||||||
|
|
||||||
b.HasIndex("ToAccountId")
|
b.HasIndex("RelatedId")
|
||||||
.HasDatabaseName("ix_account_relationships_to_account_id");
|
.HasDatabaseName("ix_account_relationships_related_id");
|
||||||
|
|
||||||
b.ToTable("account_relationships", (string)null);
|
b.ToTable("account_relationships", (string)null);
|
||||||
});
|
});
|
||||||
@ -514,23 +518,23 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "FromAccount")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||||
.WithMany("OutgoingRelationships")
|
.WithMany("OutgoingRelationships")
|
||||||
.HasForeignKey("FromAccountId")
|
.HasForeignKey("AccountId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_account_relationships_accounts_from_account_id");
|
.HasConstraintName("fk_account_relationships_accounts_account_id");
|
||||||
|
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "ToAccount")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Related")
|
||||||
.WithMany("IncomingRelationships")
|
.WithMany("IncomingRelationships")
|
||||||
.HasForeignKey("ToAccountId")
|
.HasForeignKey("RelatedId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_account_relationships_accounts_to_account_id");
|
.HasConstraintName("fk_account_relationships_accounts_related_id");
|
||||||
|
|
||||||
b.Navigation("FromAccount");
|
b.Navigation("Account");
|
||||||
|
|
||||||
b.Navigation("ToAccount");
|
b.Navigation("Related");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b =>
|
@ -15,34 +15,35 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
name: "account_relationships",
|
name: "account_relationships",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
from_account_id = table.Column<long>(type: "bigint", nullable: false),
|
account_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
to_account_id = table.Column<long>(type: "bigint", nullable: false),
|
related_id = table.Column<long>(type: "bigint", nullable: false),
|
||||||
type = table.Column<int>(type: "integer", nullable: false),
|
expired_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true),
|
||||||
|
status = table.Column<int>(type: "integer", nullable: false),
|
||||||
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("pk_account_relationships", x => new { x.from_account_id, x.to_account_id });
|
table.PrimaryKey("pk_account_relationships", x => new { x.account_id, x.related_id });
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "fk_account_relationships_accounts_from_account_id",
|
name: "fk_account_relationships_accounts_account_id",
|
||||||
column: x => x.from_account_id,
|
column: x => x.account_id,
|
||||||
principalTable: "accounts",
|
principalTable: "accounts",
|
||||||
principalColumn: "id",
|
principalColumn: "id",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "fk_account_relationships_accounts_to_account_id",
|
name: "fk_account_relationships_accounts_related_id",
|
||||||
column: x => x.to_account_id,
|
column: x => x.related_id,
|
||||||
principalTable: "accounts",
|
principalTable: "accounts",
|
||||||
principalColumn: "id",
|
principalColumn: "id",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "ix_account_relationships_to_account_id",
|
name: "ix_account_relationships_related_id",
|
||||||
table: "account_relationships",
|
table: "account_relationships",
|
||||||
column: "to_account_id");
|
column: "related_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
@ -223,13 +223,13 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("FromAccountId")
|
b.Property<long>("AccountId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("from_account_id");
|
.HasColumnName("account_id");
|
||||||
|
|
||||||
b.Property<long>("ToAccountId")
|
b.Property<long>("RelatedId")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("to_account_id");
|
.HasColumnName("related_id");
|
||||||
|
|
||||||
b.Property<Instant>("CreatedAt")
|
b.Property<Instant>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
@ -239,19 +239,23 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("deleted_at");
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
b.Property<int>("Type")
|
b.Property<Instant?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expired_at");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("type");
|
.HasColumnName("status");
|
||||||
|
|
||||||
b.Property<Instant>("UpdatedAt")
|
b.Property<Instant>("UpdatedAt")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("updated_at");
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
b.HasKey("FromAccountId", "ToAccountId")
|
b.HasKey("AccountId", "RelatedId")
|
||||||
.HasName("pk_account_relationships");
|
.HasName("pk_account_relationships");
|
||||||
|
|
||||||
b.HasIndex("ToAccountId")
|
b.HasIndex("RelatedId")
|
||||||
.HasDatabaseName("ix_account_relationships_to_account_id");
|
.HasDatabaseName("ix_account_relationships_related_id");
|
||||||
|
|
||||||
b.ToTable("account_relationships", (string)null);
|
b.ToTable("account_relationships", (string)null);
|
||||||
});
|
});
|
||||||
@ -511,23 +515,23 @@ namespace DysonNetwork.Sphere.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Account.Relationship", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "FromAccount")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Account")
|
||||||
.WithMany("OutgoingRelationships")
|
.WithMany("OutgoingRelationships")
|
||||||
.HasForeignKey("FromAccountId")
|
.HasForeignKey("AccountId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_account_relationships_accounts_from_account_id");
|
.HasConstraintName("fk_account_relationships_accounts_account_id");
|
||||||
|
|
||||||
b.HasOne("DysonNetwork.Sphere.Account.Account", "ToAccount")
|
b.HasOne("DysonNetwork.Sphere.Account.Account", "Related")
|
||||||
.WithMany("IncomingRelationships")
|
.WithMany("IncomingRelationships")
|
||||||
.HasForeignKey("ToAccountId")
|
.HasForeignKey("RelatedId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_account_relationships_accounts_to_account_id");
|
.HasConstraintName("fk_account_relationships_accounts_related_id");
|
||||||
|
|
||||||
b.Navigation("FromAccount");
|
b.Navigation("Account");
|
||||||
|
|
||||||
b.Navigation("ToAccount");
|
b.Navigation("Related");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b =>
|
modelBuilder.Entity("DysonNetwork.Sphere.Auth.Challenge", b =>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user