218 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using DysonNetwork.Shared.Models;
 | |
| using DysonNetwork.Shared.Proto;
 | |
| using Grpc.Core;
 | |
| using Microsoft.EntityFrameworkCore;
 | |
| using NodaTime.Serialization.Protobuf;
 | |
| using ApiKey = DysonNetwork.Shared.Proto.ApiKey;
 | |
| using AuthService = DysonNetwork.Pass.Auth.AuthService;
 | |
| 
 | |
| namespace DysonNetwork.Pass.Account;
 | |
| 
 | |
| public class BotAccountReceiverGrpc(
 | |
|     AppDatabase db,
 | |
|     AccountService accounts,
 | |
|     FileService.FileServiceClient files,
 | |
|     FileReferenceService.FileReferenceServiceClient fileRefs,
 | |
|     AuthService authService
 | |
| )
 | |
|     : BotAccountReceiverService.BotAccountReceiverServiceBase
 | |
| {
 | |
|     public override async Task<CreateBotAccountResponse> CreateBotAccount(
 | |
|         CreateBotAccountRequest request,
 | |
|         ServerCallContext context
 | |
|     )
 | |
|     {
 | |
|         var account = SnAccount.FromProtoValue(request.Account);
 | |
|         account = await accounts.CreateBotAccount(
 | |
|             account,
 | |
|             Guid.Parse(request.AutomatedId),
 | |
|             request.PictureId,
 | |
|             request.BackgroundId
 | |
|         );
 | |
| 
 | |
|         return new CreateBotAccountResponse
 | |
|         {
 | |
|             Bot = new BotAccount
 | |
|             {
 | |
|                 Account = account.ToProtoValue(),
 | |
|                 AutomatedId = account.Id.ToString(),
 | |
|                 CreatedAt = account.CreatedAt.ToTimestamp(),
 | |
|                 UpdatedAt = account.UpdatedAt.ToTimestamp(),
 | |
|                 IsActive = true
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     public override async Task<UpdateBotAccountResponse> UpdateBotAccount(
 | |
|         UpdateBotAccountRequest request,
 | |
|         ServerCallContext context
 | |
|     )
 | |
|     {
 | |
|         var account = SnAccount.FromProtoValue(request.Account);
 | |
| 
 | |
|         if (request.PictureId is not null)
 | |
|         {
 | |
|             var file = await files.GetFileAsync(new GetFileRequest { Id = request.PictureId });
 | |
|             if (account.Profile.Picture is not null)
 | |
|                 await fileRefs.DeleteResourceReferencesAsync(
 | |
|                     new DeleteResourceReferencesRequest { ResourceId = account.Profile.ResourceIdentifier }
 | |
|                 );
 | |
|             await fileRefs.CreateReferenceAsync(
 | |
|                 new CreateReferenceRequest
 | |
|                 {
 | |
|                     ResourceId = account.Profile.ResourceIdentifier,
 | |
|                     FileId = request.PictureId,
 | |
|                     Usage = "profile.picture"
 | |
|                 }
 | |
|             );
 | |
|             account.Profile.Picture = SnCloudFileReferenceObject.FromProtoValue(file);
 | |
|         }
 | |
| 
 | |
|         if (request.BackgroundId is not null)
 | |
|         {
 | |
|             var file = await files.GetFileAsync(new GetFileRequest { Id = request.BackgroundId });
 | |
|             if (account.Profile.Background is not null)
 | |
|                 await fileRefs.DeleteResourceReferencesAsync(
 | |
|                     new DeleteResourceReferencesRequest { ResourceId = account.Profile.ResourceIdentifier }
 | |
|                 );
 | |
|             await fileRefs.CreateReferenceAsync(
 | |
|                 new CreateReferenceRequest
 | |
|                 {
 | |
|                     ResourceId = account.Profile.ResourceIdentifier,
 | |
|                     FileId = request.BackgroundId,
 | |
|                     Usage = "profile.background"
 | |
|                 }
 | |
|             );
 | |
|             account.Profile.Background = SnCloudFileReferenceObject.FromProtoValue(file);
 | |
|         }
 | |
| 
 | |
|         db.Accounts.Update(account);
 | |
|         await db.SaveChangesAsync();
 | |
| 
 | |
|         return new UpdateBotAccountResponse
 | |
|         {
 | |
|             Bot = new BotAccount
 | |
|             {
 | |
|                 Account = account.ToProtoValue(),
 | |
|                 AutomatedId = account.Id.ToString(),
 | |
|                 CreatedAt = account.CreatedAt.ToTimestamp(),
 | |
|                 UpdatedAt = account.UpdatedAt.ToTimestamp(),
 | |
|                 IsActive = true
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     public override async Task<DeleteBotAccountResponse> DeleteBotAccount(
 | |
|         DeleteBotAccountRequest request,
 | |
|         ServerCallContext context
 | |
|     )
 | |
|     {
 | |
|         var automatedId = Guid.Parse(request.AutomatedId);
 | |
|         var account = await accounts.GetBotAccount(automatedId);
 | |
|         if (account is null)
 | |
|             throw new RpcException(new Grpc.Core.Status(Grpc.Core.StatusCode.NotFound, "Account not found"));
 | |
| 
 | |
|         await accounts.DeleteAccount(account);
 | |
| 
 | |
|         return new DeleteBotAccountResponse();
 | |
|     }
 | |
| 
 | |
|     public override async Task<ApiKey> GetApiKey(GetApiKeyRequest request, ServerCallContext context)
 | |
|     {
 | |
|         var keyId = Guid.Parse(request.Id);
 | |
|         var key = await db.ApiKeys
 | |
|             .Include(k => k.Account)
 | |
|             .FirstOrDefaultAsync(k => k.Id == keyId);
 | |
| 
 | |
|         if (key == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found"));
 | |
| 
 | |
|         return key.ToProtoValue();
 | |
|     }
 | |
| 
 | |
|     public override async Task<GetApiKeyBatchResponse> ListApiKey(ListApiKeyRequest request, ServerCallContext context)
 | |
|     {
 | |
|         var automatedId = Guid.Parse(request.AutomatedId);
 | |
|         var account = await accounts.GetBotAccount(automatedId);
 | |
|         if (account == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "Account not found"));
 | |
| 
 | |
|         var keys = await db.ApiKeys
 | |
|             .Where(k => k.AccountId == account.Id)
 | |
|             .Select(k => k.ToProtoValue())
 | |
|             .ToListAsync();
 | |
| 
 | |
|         var response = new GetApiKeyBatchResponse();
 | |
|         response.Data.AddRange(keys);
 | |
|         return response;
 | |
|     }
 | |
| 
 | |
|     public override async Task<ApiKey> CreateApiKey(ApiKey request, ServerCallContext context)
 | |
|     {
 | |
|         var accountId = Guid.Parse(request.AccountId);
 | |
|         var account = await accounts.GetBotAccount(accountId);
 | |
|         if (account == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "Account not found"));
 | |
| 
 | |
|         if (string.IsNullOrWhiteSpace(request.Label))
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Label is required"));
 | |
| 
 | |
|         var key = await authService.CreateApiKey(account.Id, request.Label, null);
 | |
|         key.Key = await authService.IssueApiKeyToken(key);
 | |
|         
 | |
|         return key.ToProtoValue();
 | |
|     }
 | |
| 
 | |
|     public override async Task<ApiKey> UpdateApiKey(ApiKey request, ServerCallContext context)
 | |
|     {
 | |
|         var keyId = Guid.Parse(request.Id);
 | |
|         var accountId = Guid.Parse(request.AccountId);
 | |
|         
 | |
|         var key = await db.ApiKeys
 | |
|             .Include(k => k.Session)
 | |
|             .Where(k => k.Id == keyId && k.AccountId == accountId)
 | |
|             .FirstOrDefaultAsync();
 | |
|             
 | |
|         if (key == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found"));
 | |
| 
 | |
|         // Only update the label if provided
 | |
|         if (string.IsNullOrWhiteSpace(request.Label)) return key.ToProtoValue();
 | |
|         key.Label = request.Label;
 | |
|         db.ApiKeys.Update(key);
 | |
|         await db.SaveChangesAsync();
 | |
| 
 | |
|         return key.ToProtoValue();
 | |
|     }
 | |
| 
 | |
|     public override async Task<ApiKey> RotateApiKey(GetApiKeyRequest request, ServerCallContext context)
 | |
|     {
 | |
|         var keyId = Guid.Parse(request.Id);
 | |
|         var key = await db.ApiKeys
 | |
|             .Include(k => k.Session)
 | |
|             .FirstOrDefaultAsync(k => k.Id == keyId);
 | |
|             
 | |
|         if (key == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found"));
 | |
| 
 | |
|         key = await authService.RotateApiKeyToken(key);
 | |
|         key.Key = await authService.IssueApiKeyToken(key);
 | |
|         
 | |
|         return key.ToProtoValue();
 | |
|     }
 | |
| 
 | |
|     public override async Task<DeleteApiKeyResponse> DeleteApiKey(GetApiKeyRequest request, ServerCallContext context)
 | |
|     {
 | |
|         var keyId = Guid.Parse(request.Id);
 | |
|         var key = await db.ApiKeys
 | |
|             .Include(k => k.Session)
 | |
|             .FirstOrDefaultAsync(k => k.Id == keyId);
 | |
|             
 | |
|         if (key == null)
 | |
|             throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found"));
 | |
| 
 | |
|         await authService.RevokeApiKeyToken(key);
 | |
|         
 | |
|         return new DeleteApiKeyResponse { Success = true };
 | |
|     }
 | |
| } |