114 lines
4.1 KiB
C#
114 lines
4.1 KiB
C#
using DysonNetwork.Shared.Proto;
|
|
using Grpc.Core;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NodaTime;
|
|
|
|
namespace DysonNetwork.Pass.Account;
|
|
|
|
public class ActionLogServiceGrpc : Shared.Proto.ActionLogService.ActionLogServiceBase
|
|
{
|
|
private readonly ActionLogService _actionLogService;
|
|
private readonly AppDatabase _db;
|
|
private readonly ILogger<ActionLogServiceGrpc> _logger;
|
|
|
|
public ActionLogServiceGrpc(
|
|
ActionLogService actionLogService,
|
|
AppDatabase db,
|
|
ILogger<ActionLogServiceGrpc> logger)
|
|
{
|
|
_actionLogService = actionLogService ?? throw new ArgumentNullException(nameof(actionLogService));
|
|
_db = db ?? throw new ArgumentNullException(nameof(db));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
public override async Task<CreateActionLogResponse> CreateActionLog(CreateActionLogRequest request,
|
|
ServerCallContext context)
|
|
{
|
|
if (string.IsNullOrEmpty(request.AccountId) || !Guid.TryParse(request.AccountId, out var accountId))
|
|
{
|
|
throw new RpcException(new Grpc.Core.Status(Grpc.Core.StatusCode.InvalidArgument, "Invalid account ID"));
|
|
}
|
|
|
|
try
|
|
{
|
|
var meta = request.Meta
|
|
?.Select(x => new KeyValuePair<string, object?>(x.Key, GrpcTypeHelper.ConvertField(x.Value)))
|
|
.ToDictionary() ?? new Dictionary<string, object?>();
|
|
|
|
_actionLogService.CreateActionLog(
|
|
accountId,
|
|
request.Action,
|
|
meta
|
|
);
|
|
|
|
return new CreateActionLogResponse();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating action log");
|
|
throw new RpcException(new Grpc.Core.Status(Grpc.Core.StatusCode.Internal, "Failed to create action log"));
|
|
}
|
|
}
|
|
|
|
public override async Task<ListActionLogsResponse> ListActionLogs(ListActionLogsRequest request,
|
|
ServerCallContext context)
|
|
{
|
|
if (string.IsNullOrEmpty(request.AccountId) || !Guid.TryParse(request.AccountId, out var accountId))
|
|
{
|
|
throw new RpcException(new Grpc.Core.Status(Grpc.Core.StatusCode.InvalidArgument, "Invalid account ID"));
|
|
}
|
|
|
|
try
|
|
{
|
|
var query = _db.ActionLogs
|
|
.AsNoTracking()
|
|
.Where(log => log.AccountId == accountId);
|
|
|
|
if (!string.IsNullOrEmpty(request.Action))
|
|
{
|
|
query = query.Where(log => log.Action == request.Action);
|
|
}
|
|
|
|
// Apply ordering (default to newest first)
|
|
query = (request.OrderBy?.ToLower() ?? "createdat desc") switch
|
|
{
|
|
"createdat" => query.OrderBy(log => log.CreatedAt),
|
|
"createdat desc" => query.OrderByDescending(log => log.CreatedAt),
|
|
_ => query.OrderByDescending(log => log.CreatedAt)
|
|
};
|
|
|
|
// Apply pagination
|
|
var pageSize = request.PageSize == 0 ? 50 : Math.Min(request.PageSize, 1000);
|
|
var logs = await query
|
|
.Take(pageSize + 1) // Fetch one extra to determine if there are more pages
|
|
.ToListAsync();
|
|
|
|
var hasMore = logs.Count > pageSize;
|
|
if (hasMore)
|
|
{
|
|
logs.RemoveAt(logs.Count - 1);
|
|
}
|
|
|
|
var response = new ListActionLogsResponse
|
|
{
|
|
TotalSize = await query.CountAsync()
|
|
};
|
|
|
|
if (hasMore)
|
|
{
|
|
// In a real implementation, you'd generate a proper page token
|
|
response.NextPageToken = (logs.LastOrDefault()?.CreatedAt ?? SystemClock.Instance.GetCurrentInstant())
|
|
.ToString();
|
|
}
|
|
|
|
response.ActionLogs.AddRange(logs.Select(log => log.ToProtoValue()));
|
|
|
|
return response;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error listing action logs");
|
|
throw new RpcException(new Grpc.Core.Status(Grpc.Core.StatusCode.Internal, "Failed to list action logs"));
|
|
}
|
|
}
|
|
} |