173 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using DysonNetwork.Shared.Models;
 | 
						|
using DysonNetwork.Shared.Proto;
 | 
						|
using DysonNetwork.Shared.Registry;
 | 
						|
using Grpc.Core;
 | 
						|
using Microsoft.EntityFrameworkCore;
 | 
						|
using NodaTime.Serialization.Protobuf;
 | 
						|
 | 
						|
namespace DysonNetwork.Develop.Identity;
 | 
						|
 | 
						|
public class BotAccountService(
 | 
						|
    AppDatabase db,
 | 
						|
    BotAccountReceiverService.BotAccountReceiverServiceClient accountReceiver,
 | 
						|
    RemoteAccountService remoteAccounts
 | 
						|
)
 | 
						|
{
 | 
						|
    public async Task<SnBotAccount?> GetBotByIdAsync(Guid id)
 | 
						|
    {
 | 
						|
        return await db.BotAccounts
 | 
						|
            .Include(b => b.Project)
 | 
						|
            .FirstOrDefaultAsync(b => b.Id == id);
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task<List<SnBotAccount>> GetBotsByProjectAsync(Guid projectId)
 | 
						|
    {
 | 
						|
        return await db.BotAccounts
 | 
						|
            .Where(b => b.ProjectId == projectId)
 | 
						|
            .ToListAsync();
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task<SnBotAccount> CreateBotAsync(
 | 
						|
        SnDevProject project,
 | 
						|
        string slug,
 | 
						|
        Account account,
 | 
						|
        string? pictureId,
 | 
						|
        string? backgroundId
 | 
						|
    )
 | 
						|
    {
 | 
						|
        // First, check if a bot with this slug already exists in this project
 | 
						|
        var existingBot = await db.BotAccounts
 | 
						|
            .FirstOrDefaultAsync(b => b.ProjectId == project.Id && b.Slug == slug);
 | 
						|
 | 
						|
        if (existingBot != null)
 | 
						|
            throw new InvalidOperationException("A bot with this slug already exists in this project.");
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            var automatedId = Guid.NewGuid();
 | 
						|
            var createRequest = new CreateBotAccountRequest
 | 
						|
            {
 | 
						|
                AutomatedId = automatedId.ToString(),
 | 
						|
                Account = account,
 | 
						|
                PictureId = pictureId,
 | 
						|
                BackgroundId = backgroundId
 | 
						|
            };
 | 
						|
 | 
						|
            var createResponse = await accountReceiver.CreateBotAccountAsync(createRequest);
 | 
						|
            var botAccount = createResponse.Bot;
 | 
						|
 | 
						|
            // Then create the local bot account
 | 
						|
            var bot = new SnBotAccount
 | 
						|
            {
 | 
						|
                Id = automatedId,
 | 
						|
                Slug = slug,
 | 
						|
                ProjectId = project.Id,
 | 
						|
                Project = project,
 | 
						|
                IsActive = botAccount.IsActive,
 | 
						|
                CreatedAt = botAccount.CreatedAt.ToInstant(),
 | 
						|
                UpdatedAt = botAccount.UpdatedAt.ToInstant()
 | 
						|
            };
 | 
						|
 | 
						|
            db.BotAccounts.Add(bot);
 | 
						|
            await db.SaveChangesAsync();
 | 
						|
 | 
						|
            return bot;
 | 
						|
        }
 | 
						|
        catch (RpcException ex) when (ex.StatusCode == StatusCode.AlreadyExists)
 | 
						|
        {
 | 
						|
            throw new InvalidOperationException(
 | 
						|
                "A bot account with this ID already exists in the authentication service.", ex);
 | 
						|
        }
 | 
						|
        catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument)
 | 
						|
        {
 | 
						|
            throw new ArgumentException($"Invalid bot account data: {ex.Status.Detail}", ex);
 | 
						|
        }
 | 
						|
        catch (RpcException ex)
 | 
						|
        {
 | 
						|
            throw new Exception($"Failed to create bot account: {ex.Status.Detail}", ex);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task<SnBotAccount> UpdateBotAsync(
 | 
						|
        SnBotAccount bot,
 | 
						|
        Account account,
 | 
						|
        string? pictureId,
 | 
						|
        string? backgroundId
 | 
						|
    )
 | 
						|
    {
 | 
						|
        db.Update(bot);
 | 
						|
        await db.SaveChangesAsync();
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // Update the bot account in the Pass service
 | 
						|
            var updateRequest = new UpdateBotAccountRequest
 | 
						|
            {
 | 
						|
                AutomatedId = bot.Id.ToString(),
 | 
						|
                Account = account,
 | 
						|
                PictureId = pictureId,
 | 
						|
                BackgroundId = backgroundId
 | 
						|
            };
 | 
						|
 | 
						|
            var updateResponse = await accountReceiver.UpdateBotAccountAsync(updateRequest);
 | 
						|
            var updatedBot = updateResponse.Bot;
 | 
						|
 | 
						|
            // Update local bot account
 | 
						|
            bot.UpdatedAt = updatedBot.UpdatedAt.ToInstant();
 | 
						|
            bot.IsActive = updatedBot.IsActive;
 | 
						|
            await db.SaveChangesAsync();
 | 
						|
        }
 | 
						|
        catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound)
 | 
						|
        {
 | 
						|
            throw new Exception("Bot account not found in the authentication service", ex);
 | 
						|
        }
 | 
						|
        catch (RpcException ex)
 | 
						|
        {
 | 
						|
            throw new Exception($"Failed to update bot account: {ex.Status.Detail}", ex);
 | 
						|
        }
 | 
						|
 | 
						|
        return bot;
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task DeleteBotAsync(SnBotAccount bot)
 | 
						|
    {
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // Delete the bot account from the Pass service
 | 
						|
            var deleteRequest = new DeleteBotAccountRequest
 | 
						|
            {
 | 
						|
                AutomatedId = bot.Id.ToString(),
 | 
						|
                Force = false
 | 
						|
            };
 | 
						|
 | 
						|
            await accountReceiver.DeleteBotAccountAsync(deleteRequest);
 | 
						|
        }
 | 
						|
        catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound)
 | 
						|
        {
 | 
						|
            // Account not found in Pass service, continue with local deletion
 | 
						|
        }
 | 
						|
 | 
						|
        // Delete the local bot account
 | 
						|
        db.BotAccounts.Remove(bot);
 | 
						|
        await db.SaveChangesAsync();
 | 
						|
    }
 | 
						|
 | 
						|
    public async Task<SnBotAccount?> LoadBotAccountAsync(SnBotAccount bot) =>
 | 
						|
        (await LoadBotsAccountAsync([bot])).FirstOrDefault();
 | 
						|
 | 
						|
    public async Task<List<SnBotAccount>> LoadBotsAccountAsync(List<SnBotAccount> bots)
 | 
						|
    {
 | 
						|
        var automatedIds = bots.Select(b => b.Id).ToList();
 | 
						|
        var data = await remoteAccounts.GetBotAccountBatch(automatedIds);
 | 
						|
 | 
						|
        foreach (var bot in bots)
 | 
						|
        {
 | 
						|
            bot.Account = data
 | 
						|
                .Select(SnAccount.FromProtoValue)
 | 
						|
                .FirstOrDefault(e => e.AutomatedId == bot.Id);
 | 
						|
        }
 | 
						|
 | 
						|
        return bots;
 | 
						|
    }
 | 
						|
}
 |