Add MasterBotUserId and MasterAgentName for copy trading support

- Introduced MasterBotUserId and MasterAgentName properties to facilitate copy trading functionality.
- Updated relevant models, controllers, and database entities to accommodate these new properties.
- Enhanced validation logic in StartCopyTradingCommandHandler to ensure proper ownership checks for master strategies.
This commit is contained in:
2025-11-20 00:33:31 +07:00
parent 97103fbfe8
commit ff2df2d9ac
13 changed files with 1852 additions and 20 deletions

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Managing.Infrastructure.Databases.Migrations
{
/// <inheritdoc />
public partial class AddMasterBotUserIdToBots : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MasterBotUserId",
table: "Bots",
type: "integer",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MasterBotUserId",
table: "Bots");
}
}
}

View File

@@ -318,6 +318,9 @@ namespace Managing.Infrastructure.Databases.Migrations
b.Property<int>("LongPositionCount")
.HasColumnType("integer");
b.Property<int?>("MasterBotUserId")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(255)

View File

@@ -36,4 +36,15 @@ public class BotEntity
public decimal Fees { get; set; }
public int LongPositionCount { get; set; }
public int ShortPositionCount { get; set; }
/// <summary>
/// The user ID of the master bot's owner when this bot is for copy trading
/// </summary>
[ForeignKey("MasterBotUser")]
public int? MasterBotUserId { get; set; }
/// <summary>
/// Navigation property for the master bot's owner when this bot is for copy trading
/// </summary>
public virtual UserEntity? MasterBotUser { get; set; }
}

View File

@@ -548,6 +548,12 @@ public class ManagingDbContext : DbContext
.WithMany()
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.SetNull);
// Configure relationship with MasterBotUser
entity.HasOne(e => e.MasterBotUser)
.WithMany()
.HasForeignKey(e => e.MasterBotUserId)
.OnDelete(DeleteBehavior.SetNull);
});
// Configure MoneyManagement entity

View File

@@ -79,6 +79,7 @@ public class PostgreSqlBotRepository : IBotRepository
existingEntity.LastStartTime = bot.LastStartTime;
existingEntity.LastStopTime = bot.LastStopTime;
existingEntity.AccumulatedRunTimeSeconds = bot.AccumulatedRunTimeSeconds;
existingEntity.MasterBotUserId = bot.MasterBotUserId;
await _context.SaveChangesAsync().ConfigureAwait(false);
}
@@ -114,10 +115,26 @@ public class PostgreSqlBotRepository : IBotRepository
var entities = await _context.Bots
.AsNoTracking()
.Include(m => m.User)
.Include(m => m.MasterBotUser)
.Where(b => b.UserId == id)
.ToListAsync()
.ConfigureAwait(false);
return PostgreSqlMappers.Map(entities);
// Map entities to domain objects
var bots = PostgreSqlMappers.Map(entities).ToList();
// Attach master bot users to domain objects
foreach (var entity in entities.Where(e => e.MasterBotUser != null))
{
var bot = bots.FirstOrDefault(b => b.MasterBotUserId == entity.MasterBotUserId);
if (bot != null)
{
// Convert UserEntity to User domain object
bot.MasterBotUser = PostgreSqlMappers.Map(entity.MasterBotUser);
}
}
return bots;
}
public async Task<IEnumerable<Bot>> GetBotsByStatusAsync(BotStatus status)

View File

@@ -753,7 +753,8 @@ public static class PostgreSqlMappers
Volume = entity.Volume,
Fees = entity.Fees,
LongPositionCount = entity.LongPositionCount,
ShortPositionCount = entity.ShortPositionCount
ShortPositionCount = entity.ShortPositionCount,
MasterBotUserId = entity.MasterBotUserId
};
return bot;
@@ -784,6 +785,7 @@ public static class PostgreSqlMappers
Fees = bot.Fees,
LongPositionCount = bot.LongPositionCount,
ShortPositionCount = bot.ShortPositionCount,
MasterBotUserId = bot.MasterBotUserId,
UpdatedAt = DateTime.UtcNow
};
}