♻️ Refind bot account

This commit is contained in:
2025-08-23 13:00:30 +08:00
parent fb7e52d6f3
commit 5d7429a416
15 changed files with 691 additions and 71 deletions

View File

@@ -51,7 +51,8 @@ public class Account : ModelBase
Profile = Profile.ToProtoValue(),
PerkSubscription = PerkSubscription?.ToProtoValue(),
CreatedAt = CreatedAt.ToTimestamp(),
UpdatedAt = UpdatedAt.ToTimestamp()
UpdatedAt = UpdatedAt.ToTimestamp(),
AutomatedId = AutomatedId?.ToString()
};
// Add contacts
@@ -81,6 +82,7 @@ public class Account : ModelBase
: null,
CreatedAt = proto.CreatedAt.ToInstant(),
UpdatedAt = proto.UpdatedAt.ToInstant(),
AutomatedId = proto.AutomatedId is not null ? Guid.Parse(proto.AutomatedId) : null
};
account.Profile = AccountProfile.FromProtoValue(proto.Profile);
@@ -119,7 +121,7 @@ public abstract class Leveling
public class AccountProfile : ModelBase, IIdentifiedResource
{
public Guid Id { get; set; }
public Guid Id { get; set; } = Guid.NewGuid();
[MaxLength(256)] public string? FirstName { get; set; }
[MaxLength(256)] public string? MiddleName { get; set; }
[MaxLength(256)] public string? LastName { get; set; }

View File

@@ -30,6 +30,7 @@ public class AccountCurrentController(
{
[HttpGet]
[ProducesResponseType<Account>(StatusCodes.Status200OK)]
[ProducesResponseType<ApiError>(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult<Account>> GetCurrentIdentity()
{
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();

View File

@@ -6,6 +6,7 @@ using DysonNetwork.Pass.Email;
using DysonNetwork.Pass.Localization;
using DysonNetwork.Pass.Permission;
using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Data;
using DysonNetwork.Shared.Proto;
using DysonNetwork.Shared.Stream;
using EFCore.BulkExtensions;
@@ -21,6 +22,8 @@ namespace DysonNetwork.Pass.Account;
public class AccountService(
AppDatabase db,
MagicSpellService spells,
FileService.FileServiceClient files,
FileReferenceService.FileReferenceServiceClient fileRefs,
AccountUsernameService uname,
EmailService mailer,
PusherService.PusherServiceClient pusher,
@@ -182,7 +185,7 @@ public class AccountService(
);
}
public async Task<Account> CreateBotAccount(Account account, Guid automatedId)
public async Task<Account> CreateBotAccount(Account account, Guid automatedId, string? pictureId, string? backgroundId)
{
var dupeAutomateCount = await db.Accounts.Where(a => a.AutomatedId == automatedId).CountAsync();
if (dupeAutomateCount > 0)
@@ -195,8 +198,38 @@ public class AccountService(
account.AutomatedId = automatedId;
account.ActivatedAt = SystemClock.Instance.GetCurrentInstant();
account.IsSuperuser = false;
if (!string.IsNullOrEmpty(pictureId))
{
var file = await files.GetFileAsync(new GetFileRequest { Id = pictureId });
await fileRefs.CreateReferenceAsync(
new CreateReferenceRequest
{
ResourceId = account.Profile.ResourceIdentifier,
FileId = pictureId,
Usage = "profile.picture"
}
);
account.Profile.Picture = CloudFileReferenceObject.FromProtoValue(file);
}
if (!string.IsNullOrEmpty(backgroundId))
{
var file = await files.GetFileAsync(new GetFileRequest { Id = backgroundId });
await fileRefs.CreateReferenceAsync(
new CreateReferenceRequest
{
ResourceId = account.Profile.ResourceIdentifier,
FileId = backgroundId,
Usage = "profile.background"
}
);
account.Profile.Background = CloudFileReferenceObject.FromProtoValue(file);
}
db.Accounts.Add(account);
await db.SaveChangesAsync();
return account;
}

View File

@@ -42,6 +42,26 @@ public class AccountServiceGrpc(
return account.ToProtoValue();
}
public override async Task<Shared.Proto.Account> GetBotAccount(GetBotAccountRequest request,
ServerCallContext context)
{
if (!Guid.TryParse(request.AutomatedId, out var automatedId))
throw new RpcException(new Grpc.Core.Status(StatusCode.InvalidArgument, "Invalid automated ID format"));
var account = await _db.Accounts
.AsNoTracking()
.Include(a => a.Profile)
.FirstOrDefaultAsync(a => a.AutomatedId == automatedId);
if (account == null)
throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, $"Account with automated ID {request.AutomatedId} not found"));
var perk = await subscriptions.GetPerkSubscriptionAsync(account.Id);
account.PerkSubscription = perk?.ToReference();
return account.ToProtoValue();
}
public override async Task<GetAccountBatchResponse> GetAccountBatch(GetAccountBatchRequest request,
ServerCallContext context)
{
@@ -56,7 +76,35 @@ public class AccountServiceGrpc(
.Where(a => accountIds.Contains(a.Id))
.Include(a => a.Profile)
.ToListAsync();
var perks = await subscriptions.GetPerkSubscriptionsAsync(
accounts.Select(x => x.Id).ToList()
);
foreach (var account in accounts)
if (perks.TryGetValue(account.Id, out var perk))
account.PerkSubscription = perk?.ToReference();
var response = new GetAccountBatchResponse();
response.Accounts.AddRange(accounts.Select(a => a.ToProtoValue()));
return response;
}
public override async Task<GetAccountBatchResponse> GetBotAccountBatch(GetBotAccountBatchRequest request,
ServerCallContext context)
{
var automatedIds = request.AutomatedId
.Select(id => Guid.TryParse(id, out var automatedId) ? automatedId : (Guid?)null)
.Where(id => id.HasValue)
.Select(id => id!.Value)
.ToList();
var accounts = await _db.Accounts
.AsNoTracking()
.Where(a => a.AutomatedId != null && automatedIds.Contains(a.AutomatedId.Value))
.Include(a => a.Profile)
.ToListAsync();
var perks = await subscriptions.GetPerkSubscriptionsAsync(
accounts.Select(x => x.Id).ToList()
);
@@ -76,7 +124,8 @@ public class AccountServiceGrpc(
return status.ToProtoValue();
}
public override async Task<GetAccountStatusBatchResponse> GetAccountStatusBatch(GetAccountBatchRequest request, ServerCallContext context)
public override async Task<GetAccountStatusBatchResponse> GetAccountStatusBatch(GetAccountBatchRequest request,
ServerCallContext context)
{
var accountIds = request.Id
.Select(id => Guid.TryParse(id, out var accountId) ? accountId : (Guid?)null)
@@ -98,14 +147,14 @@ public class AccountServiceGrpc(
.Where(a => accountNames.Contains(a.Name))
.Include(a => a.Profile)
.ToListAsync();
var perks = await subscriptions.GetPerkSubscriptionsAsync(
accounts.Select(x => x.Id).ToList()
);
foreach (var account in accounts)
if (perks.TryGetValue(account.Id, out var perk))
account.PerkSubscription = perk?.ToReference();
var response = new GetAccountBatchResponse();
response.Accounts.AddRange(accounts.Select(a => a.ToProtoValue()));
return response;

View File

@@ -1,3 +1,4 @@
using DysonNetwork.Shared.Data;
using DysonNetwork.Shared.Proto;
using Grpc.Core;
using NodaTime;
@@ -5,7 +6,12 @@ using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Pass.Account;
public class BotAccountReceiverGrpc(AppDatabase db, AccountService accounts)
public class BotAccountReceiverGrpc(
AppDatabase db,
AccountService accounts,
FileService.FileServiceClient files,
FileReferenceService.FileReferenceServiceClient fileRefs
)
: BotAccountReceiverService.BotAccountReceiverServiceBase
{
public override async Task<CreateBotAccountResponse> CreateBotAccount(
@@ -14,7 +20,12 @@ public class BotAccountReceiverGrpc(AppDatabase db, AccountService accounts)
)
{
var account = Account.FromProtoValue(request.Account);
account = await accounts.CreateBotAccount(account, Guid.Parse(request.AutomatedId));
account = await accounts.CreateBotAccount(
account,
Guid.Parse(request.AutomatedId),
request.PictureId,
request.BackgroundId
);
return new CreateBotAccountResponse
{
@@ -34,16 +45,44 @@ public class BotAccountReceiverGrpc(AppDatabase db, AccountService accounts)
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(StatusCode.NotFound, "Account not found"));
var account = Account.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 = CloudFileReferenceObject.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 = CloudFileReferenceObject.FromProtoValue(file);
}
account.Name = request.Account.Name;
account.Nick = request.Account.Nick;
account.Profile = AccountProfile.FromProtoValue(request.Account.Profile);
account.Language = request.Account.Language;
db.Accounts.Update(account);
await db.SaveChangesAsync();
@@ -56,7 +95,7 @@ public class BotAccountReceiverGrpc(AppDatabase db, AccountService accounts)
CreatedAt = account.CreatedAt.ToTimestamp(),
UpdatedAt = account.UpdatedAt.ToTimestamp(),
IsActive = true
}
}
};
}
@@ -69,9 +108,9 @@ public class BotAccountReceiverGrpc(AppDatabase db, AccountService accounts)
var account = await accounts.GetBotAccount(automatedId);
if (account is null)
throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "Account not found"));
await accounts.DeleteAccount(account);
return new DeleteBotAccountResponse();
}
}